diff --git a/src/nm-device.c b/src/nm-device.c index e54d798df7..5c8ac58a05 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -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); diff --git a/src/nm-device.h b/src/nm-device.h index e665bbaabb..a654d2b736 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -23,7 +23,7 @@ #define NM_DEVICE_H #include -#include +#include #include #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); diff --git a/src/nm-manager.c b/src/nm-manager.c index f02522e3f8..ce6e43fe1b 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1640,6 +1640,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) { @@ -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.