core: add generic device authorization request signal
authorDan Williams <dcbw@redhat.com>
Fri, 1 Jun 2012 20:27:39 +0000 (15:27 -0500)
committerDan Williams <dcbw@redhat.com>
Fri, 1 Jun 2012 22:05:00 +0000 (17:05 -0500)
Allows devices to generically request authorization from the manager
for whatever operation they want, and allows us to keep the devices
from including the auth code directly.

src/nm-device.c
src/nm-device.h
src/nm-manager.c

index e54d798..5c8ac58 100644 (file)
@@ -91,6 +91,7 @@ enum {
        STATE_CHANGED,
        DISCONNECT_REQUEST,
        AUTOCONNECT_ALLOWED,
+       AUTH_REQUEST,
        LAST_SIGNAL,
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -4157,6 +4158,15 @@ nm_device_class_init (NMDeviceClass *klass)
                              _nm_marshal_BOOLEAN__VOID,
                              G_TYPE_BOOLEAN, 0);
 
+       signals[AUTH_REQUEST] =
+               g_signal_new (NM_DEVICE_AUTH_REQUEST,
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0, NULL, NULL,
+                             /* dbus-glib context, permission, allow_interaction, callback, user_data */
+                             _nm_marshal_VOID__POINTER_STRING_BOOLEAN_POINTER_POINTER,
+                             G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER);
+
        dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
                                         &dbus_glib_nm_device_interface_object_info);
 
index e665bba..a654d2b 100644 (file)
@@ -23,7 +23,7 @@
 #define NM_DEVICE_H
 
 #include <glib-object.h>
-#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
 #include <netinet/in.h>
 
 #include "NetworkManager.h"
@@ -60,6 +60,7 @@
 
 /* Internal signal */
 #define NM_DEVICE_DISCONNECT_REQUEST "disconnect-request"
+#define NM_DEVICE_AUTH_REQUEST "auth-request"
 
 
 G_BEGIN_DECLS
@@ -171,6 +172,11 @@ typedef struct {
 } NMDeviceClass;
 
 
+typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
+                                         DBusGMethodInvocation *context,
+                                         GError *error,
+                                         gpointer user_data);
+
 GType nm_device_get_type (void);
 
 const char *    nm_device_get_path (NMDevice *dev);
index f02522e..ce6e43f 100644 (file)
@@ -1641,6 +1641,99 @@ manager_device_disconnect_request (NMDevice *device,
 }
 
 static void
+device_auth_done_cb (NMAuthChain *chain,
+                     GError *auth_error,
+                     DBusGMethodInvocation *context,
+                     gpointer user_data)
+{
+       NMManager *self = NM_MANAGER (user_data);
+       NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+       GError *error = NULL;
+       NMAuthCallResult result;
+       NMDevice *device;
+       const char *permission;
+       NMDeviceAuthRequestFunc callback;
+
+       priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+       permission = nm_auth_chain_get_data (chain, "requested-permission");
+       g_assert (permission);
+       callback = nm_auth_chain_get_data (chain, "callback");
+       g_assert (callback);
+       device = nm_auth_chain_get_data (chain, "device");
+       g_assert (device);
+
+       result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
+       if (auth_error) {
+               /* translate the auth error into a manager permission denied error */
+               nm_log_dbg (LOGD_CORE, "%s request failed: %s", permission, auth_error->message);
+               error = g_error_new (NM_MANAGER_ERROR,
+                                    NM_MANAGER_ERROR_PERMISSION_DENIED,
+                                    "%s request failed: %s",
+                                    permission, auth_error->message);
+       } else if (result != NM_AUTH_CALL_RESULT_YES) {
+               nm_log_dbg (LOGD_CORE, "%s request failed: not authorized", permission);
+               error = g_error_new (NM_MANAGER_ERROR,
+                                    NM_MANAGER_ERROR_PERMISSION_DENIED,
+                                    "%s request failed: not authorized",
+                                    permission);
+       }
+
+       g_assert (error || (result == NM_AUTH_CALL_RESULT_YES));
+
+       callback (device,
+                 context,
+                 error,
+                 nm_auth_chain_get_data (chain, "user-data"));
+
+       g_clear_error (&error);
+       nm_auth_chain_unref (chain);
+}
+
+static void
+device_auth_request_cb (NMDevice *device,
+                        DBusGMethodInvocation *context,
+                        const char *permission,
+                        gboolean allow_interaction,
+                        NMDeviceAuthRequestFunc callback,
+                        gpointer user_data,
+                        NMManager *self)
+{
+       NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+       GError *error = NULL;
+       gulong sender_uid = G_MAXULONG;
+       char *error_desc = NULL;
+       NMAuthChain *chain;
+
+       /* Get the caller's UID for the root check */
+       if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &sender_uid, &error_desc)) {
+               error = g_error_new_literal (NM_MANAGER_ERROR,
+                                            NM_MANAGER_ERROR_PERMISSION_DENIED,
+                                            error_desc);
+               callback (device, context, error, user_data);
+               g_error_free (error);
+               g_free (error_desc);
+               return;
+       }
+
+       /* Yay for root */
+       if (0 == sender_uid)
+               callback (device, context, NULL, user_data);
+       else {
+               /* Otherwise validate the non-root request */
+               chain = nm_auth_chain_new (context, NULL, device_auth_done_cb, self);
+               g_assert (chain);
+               priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+
+               nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
+               nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
+               nm_auth_chain_set_data (chain, "callback", callback, NULL);
+               nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
+               nm_auth_chain_add_call (chain, permission, allow_interaction);
+       }
+}
+
+static void
 add_device (NMManager *self, NMDevice *device)
 {
        NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -1683,6 +1776,10 @@ add_device (NMManager *self, NMDevice *device)
                                          G_CALLBACK (manager_device_disconnect_request),
                                          self);
 
+       g_signal_connect (device, NM_DEVICE_AUTH_REQUEST,
+                         G_CALLBACK (device_auth_request_cb),
+                         self);
+
        if (devtype == NM_DEVICE_TYPE_WIFI) {
                /* Attach to the access-point-added signal so that the manager can fill
                 * non-SSID-broadcasting APs with an SSID.