From a878cd814564e9d349eb8fd4f7d7d5d81d4aecaf Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Sep 2012 13:17:46 -0500 Subject: [PATCH 01/32] core: move connection completion code closer to callers Move the connection completion code out of the PendingActivation object and into the D-Bus method handler for AddAndActivate. This is part of simplifying PendingActivation so we can fold its functionality into NMActiveConnection and use the AC objects to track all activation requests from start to finish. This also requires a bit of reorganization since the PA used to handle some of the request validation but that now needs to be handled by each DBus method itself. Previously the PA tracked the connection path, but that's really quite unecessary, we might as well just track the actual connection object itself. This allows us to only validate the path once, instead of three times like the code did before. This does require a boolean "add_and_activate" variable though, because the PA handles the DBus method return and it needs to know whether the request came from ActivateConnection or AddAndActivateConnection, which was previously handled by checking pending->connection, which only AddAndActivate set. --- src/nm-manager.c | 321 +++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 161 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index d6e6f57cef..cdbd540646 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -192,8 +192,8 @@ struct PendingActivation { PendingActivationFunc callback; NMAuthChain *chain; const char *wifi_shared_permission; + gboolean add_and_activate; - char *connection_path; NMConnection *connection; char *specific_object_path; char *device_path; @@ -846,66 +846,22 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -static gboolean -might_be_vpn (NMConnection *connection) -{ - NMSettingConnection *s_con; - const char *ctype = NULL; - - if (nm_connection_get_setting_vpn (connection)) - return TRUE; - - /* Make sure it's not a VPN, which we can't autocomplete yet */ - s_con = nm_connection_get_setting_connection (connection); - if (s_con) - ctype = nm_setting_connection_get_connection_type (s_con); - - return (g_strcmp0 (ctype, NM_SETTING_VPN_SETTING_NAME) == 0); -} - -static gboolean -try_complete_vpn (NMConnection *connection, GSList *existing, GError **error) -{ - g_assert (might_be_vpn (connection) == TRUE); - - if (!nm_connection_get_setting_vpn (connection)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, - "VPN connections require a 'vpn' setting"); - return FALSE; - } - - nm_utils_complete_generic (connection, - NM_SETTING_VPN_SETTING_NAME, - existing, - _("VPN connection %d"), - NULL, - FALSE); /* No IPv6 by default for now */ - - return TRUE; -} - static PendingActivation * pending_activation_new (NMManager *manager, DBusGMethodInvocation *context, const char *device_path, - const char *connection_path, - GHashTable *settings, + NMConnection *connection, const char *specific_object_path, + gboolean add_and_activate, PendingActivationFunc callback, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); PendingActivation *pending; - NMDevice *device = NULL; - NMConnection *connection = NULL; - GSList *all_connections = NULL; - gboolean success; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (device_path != NULL, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); /* A object path of "/" means NULL */ if (g_strcmp0 (specific_object_path, "/") == 0) @@ -913,55 +869,17 @@ pending_activation_new (NMManager *manager, if (g_strcmp0 (device_path, "/") == 0) device_path = NULL; - /* Create the partial connection from the given settings */ - if (settings) { - if (device_path) - device = nm_manager_get_device_by_path (manager, device_path); - if (!device) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Device not found"); - return NULL; - } - - connection = nm_connection_new (); - nm_connection_replace_settings (connection, settings, NULL); - - all_connections = nm_settings_get_connections (priv->settings); - - if (might_be_vpn (connection)) { - /* Try to fill the VPN's connection setting and name at least */ - success = try_complete_vpn (connection, all_connections, error); - } else { - /* Let each device subclass complete the connection */ - success = nm_device_complete_connection (device, - connection, - specific_object_path, - all_connections, - error); - } - g_slist_free (all_connections); - - if (success == FALSE) { - g_object_unref (connection); - return NULL; - } - } - pending = g_slice_new0 (PendingActivation); pending->manager = manager; pending->context = context; pending->callback = callback; + pending->add_and_activate = add_and_activate; - pending->connection_path = g_strdup (connection_path); - pending->connection = connection; + pending->connection = g_object_ref (connection); /* "/" is special-cased to NULL to get through D-Bus */ - if (specific_object_path && strcmp (specific_object_path, "/")) - pending->specific_object_path = g_strdup (specific_object_path); - if (device_path && strcmp (device_path, "/")) - pending->device_path = g_strdup (device_path); + pending->specific_object_path = g_strdup (specific_object_path); + pending->device_path = g_strdup (device_path); return pending; } @@ -1004,30 +922,10 @@ pending_activation_check_authorized (PendingActivation *pending) { GError *error; const char *wifi_permission = NULL; - NMConnection *connection; - NMSettings *settings; const char *error_desc = NULL; g_return_if_fail (pending != NULL); - /* By this point we have an auto-completed connection (for AddAndActivate) - * or an existing connection (for Activate). - */ - connection = pending->connection; - if (!connection) { - settings = NM_MANAGER_GET_PRIVATE (pending->manager)->settings; - connection = (NMConnection *) nm_settings_get_connection_by_path (settings, pending->connection_path); - } - - if (!connection) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection could not be found."); - pending->callback (pending, error); - g_error_free (error); - return; - } - /* First check if the user is allowed to use networking at all, giving * the user a chance to authenticate to gain the permission. */ @@ -1039,7 +937,7 @@ pending_activation_check_authorized (PendingActivation *pending) nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); /* Shared wifi connections require special permissions too */ - wifi_permission = nm_utils_get_shared_wifi_permission (connection); + wifi_permission = nm_utils_get_shared_wifi_permission (pending->connection); if (wifi_permission) { pending->wifi_shared_permission = wifi_permission; nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE); @@ -1063,9 +961,9 @@ pending_activation_destroy (PendingActivation *pending, if (error) dbus_g_method_return_error (pending->context, error); else if (ac) { - if (pending->connection) { + if (pending->add_and_activate) { dbus_g_method_return (pending->context, - pending->connection_path, + nm_connection_get_path (pending->connection), nm_active_connection_get_path (ac)); } else { dbus_g_method_return (pending->context, @@ -1073,11 +971,9 @@ pending_activation_destroy (PendingActivation *pending, } } - g_free (pending->connection_path); g_free (pending->specific_object_path); g_free (pending->device_path); - if (pending->connection) - g_object_unref (pending->connection); + g_clear_object (&pending->connection); if (pending->chain) nm_auth_chain_unref (pending->chain); @@ -3230,22 +3126,20 @@ activated: * it. */ static void -pending_activate (NMManager *self, PendingActivation *pending) +pending_activate (PendingActivation *pending, NMSettingsConnection *new_connection) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *connection; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager); NMActiveConnection *ac = NULL; - GError *error = NULL; char *sender = NULL; + GError *error = NULL; - /* Ok, we're authorized */ - - connection = nm_settings_get_connection_by_path (priv->settings, pending->connection_path); - if (!connection) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection could not be found."); - goto out; + /* If we're given a new NMSettingsConnection (ie, from AddAndActivate now + * that the connection is saved) swap out the old one for the new one. + */ + if (new_connection) { + g_assert (pending->add_and_activate); + g_object_unref (pending->connection); + pending->connection = g_object_ref (new_connection); } if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, @@ -3254,38 +3148,78 @@ pending_activate (NMManager *self, PendingActivation *pending) NULL)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - "D-Bus sendder could not be determined."); - goto out; + "D-Bus sender could not be determined."); + } else { + g_assert (sender); + ac = nm_manager_activate_connection (pending->manager, + NM_CONNECTION (pending->connection), + pending->specific_object_path, + pending->device_path, + sender, + &error); + g_free (sender); } - g_assert (sender); - ac = nm_manager_activate_connection (self, - NM_CONNECTION (connection), - pending->specific_object_path, - pending->device_path, - sender, - &error); - g_free (sender); - if (!ac) { nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", - pending->connection_path, + nm_connection_get_path (pending->connection), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); } -out: pending_activation_destroy (pending, error, ac); g_clear_error (&error); } +static gboolean +validate_activation_request (NMManager *self, + NMConnection *connection, + const char *device_path, + NMDevice **out_device, + gboolean *out_vpn, + GError **error) +{ + NMDevice *device = NULL; + gboolean vpn = FALSE; + + g_assert (connection); + + /* Check whether it's a VPN or not */ + if ( nm_connection_get_setting_vpn (connection) + || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) + vpn = TRUE; + + /* Validate the device path, if given; "/" means NULL */ + if (device_path && (g_strcmp0 (device_path, "/") != 0)) + device = nm_manager_get_device_by_path (self, device_path); + + /* VPN doesn't require a device, but if one is given validate it. + * Device-based connections obviously require a device, unless they are + * for a software device that hasn't been created yet. + */ + if ((device_path && !device) || + (!vpn && !device && !connection_needs_virtual_device (connection))) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Device not found"); + return FALSE; + } + + if (out_device) + *out_device = device; + if (out_vpn) + *out_vpn = vpn; + return TRUE; +} + static void activation_auth_done (PendingActivation *pending, GError *error) { if (error) pending_activation_destroy (pending, error, NULL); else - pending_activate (pending->manager, pending); + pending_activate (pending, NULL); } static void @@ -3295,27 +3229,43 @@ impl_manager_activate_connection (NMManager *self, const char *specific_object_path, DBusGMethodInvocation *context) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); PendingActivation *pending; + NMConnection *connection; GError *error = NULL; + connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); + if (!connection) { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_CONNECTION, + "Connection could not be found."); + goto error; + } + + if (!validate_activation_request (self, connection, device_path, NULL, NULL, &error)) + goto error; + /* Need to check the caller's permissions and stuff before we can * activate the connection. */ pending = pending_activation_new (self, context, device_path, - connection_path, - NULL, + connection, specific_object_path, + FALSE, activation_auth_done, &error); - if (pending) + if (pending) { + /* Success */ pending_activation_check_authorized (pending); - else { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + return; } + +error: + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); } static void @@ -3330,11 +3280,7 @@ activation_add_done (NMSettings *self, if (error) pending_activation_destroy (pending, error, NULL); else { - /* Save the new connection's D-Bus path */ - pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection))); - - /* And activate it */ - pending_activate (pending->manager, pending); + pending_activate (pending, connection); } } @@ -3363,8 +3309,54 @@ impl_manager_add_and_activate_connection (NMManager *self, const char *specific_object_path, DBusGMethodInvocation *context) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMConnection *connection = NULL; + GSList *all_connections = NULL; PendingActivation *pending; GError *error = NULL; + NMDevice *device = NULL; + gboolean vpn = FALSE; + + if (!settings || !g_hash_table_size (settings)) { + error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, + "Settings required to create a connection."); + goto error; + } + + /* Try to create a new connection with the given settings */ + connection = nm_connection_new (); + nm_connection_replace_settings (connection, settings, NULL); + + if (!validate_activation_request (self, connection, device_path, &device, &vpn, &error)) + goto error; + + all_connections = nm_settings_get_connections (priv->settings); + if (vpn) { + /* Try to fill the VPN's connection setting and name at least */ + if (!nm_connection_get_setting_vpn (connection)) { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, + "VPN connections require a 'vpn' setting"); + goto error; + } + + nm_utils_complete_generic (connection, + NM_SETTING_VPN_SETTING_NAME, + all_connections, + _("VPN connection %d"), + NULL, + FALSE); /* No IPv6 by default for now */ + } else { + /* Let each device subclass complete the connection */ + if (!nm_device_complete_connection (device, + connection, + specific_object_path, + all_connections, + &error)) + goto error; + } + g_slist_free (all_connections); + all_connections = NULL; /* Need to check the caller's permissions and stuff before we can * activate the connection. @@ -3372,18 +3364,25 @@ impl_manager_add_and_activate_connection (NMManager *self, pending = pending_activation_new (self, context, device_path, - NULL, - settings, + connection, specific_object_path, + TRUE, add_and_activate_auth_done, &error); - if (pending) + if (pending) { + /* Success! */ + g_object_unref (connection); pending_activation_check_authorized (pending); - else { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + return; } + +error: + g_clear_object (&connection); + g_slist_free (all_connections); + + g_assert (error); + dbus_g_method_return_error (context, error); + g_error_free (error); } gboolean From f94ac164a6e33ed03fe707fd5eeb2e2ce6c0fbcb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Sep 2012 15:57:36 -0500 Subject: [PATCH 02/32] core: make nm_manager_activate_connection() take a Device, not a path Simpler; everywhere that called it has an NMDevice already anyway. --- src/nm-manager.c | 48 ++++++++++++++++++++---------------------------- src/nm-manager.h | 2 +- src/nm-policy.c | 4 ++-- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index cdbd540646..c6123bbf2f 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -195,8 +195,8 @@ struct PendingActivation { gboolean add_and_activate; NMConnection *connection; + NMDevice *device; char *specific_object_path; - char *device_path; }; typedef struct { @@ -849,7 +849,7 @@ nm_manager_get_state (NMManager *manager) static PendingActivation * pending_activation_new (NMManager *manager, DBusGMethodInvocation *context, - const char *device_path, + NMDevice *device, NMConnection *connection, const char *specific_object_path, gboolean add_and_activate, @@ -860,26 +860,21 @@ pending_activation_new (NMManager *manager, g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (context != NULL, NULL); - g_return_val_if_fail (device_path != NULL, NULL); + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); /* A object path of "/" means NULL */ if (g_strcmp0 (specific_object_path, "/") == 0) specific_object_path = NULL; - if (g_strcmp0 (device_path, "/") == 0) - device_path = NULL; pending = g_slice_new0 (PendingActivation); pending->manager = manager; pending->context = context; pending->callback = callback; pending->add_and_activate = add_and_activate; - pending->connection = g_object_ref (connection); - - /* "/" is special-cased to NULL to get through D-Bus */ + pending->device = g_object_ref (device); pending->specific_object_path = g_strdup (specific_object_path); - pending->device_path = g_strdup (device_path); return pending; } @@ -972,7 +967,7 @@ pending_activation_destroy (PendingActivation *pending, } g_free (pending->specific_object_path); - g_free (pending->device_path); + g_clear_object (&pending->device); g_clear_object (&pending->connection); if (pending->chain) @@ -2768,7 +2763,7 @@ ensure_master_active_connection (NMManager *self, master_ac = nm_manager_activate_connection (self, candidate, NULL, - nm_device_get_path (master_device), + master_device, dbus_sender, error); if (!master_ac) @@ -2816,7 +2811,7 @@ ensure_master_active_connection (NMManager *self, master_ac = nm_manager_activate_connection (self, master_connection, NULL, - nm_device_get_path (candidate), + candidate, dbus_sender, error); if (!master_ac) @@ -2907,12 +2902,11 @@ NMActiveConnection * nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, - const char *device_path, + NMDevice *device, const char *dbus_sender, GError **error) { NMManagerPrivate *priv; - NMDevice *device = NULL; gulong sender_uid = G_MAXULONG; char *iface; NMDevice *master_device = NULL; @@ -2947,14 +2941,7 @@ nm_manager_activate_connection (NMManager *manager, } /* Device-based connection */ - if (device_path) { - device = nm_manager_get_device_by_path (manager, device_path); - if (!device) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Device not found"); - return NULL; - } - + if (device) { /* If it's a virtual interface make sure the device given by the * path matches the connection's interface details. */ @@ -3154,7 +3141,7 @@ pending_activate (PendingActivation *pending, NMSettingsConnection *new_connecti ac = nm_manager_activate_connection (pending->manager, NM_CONNECTION (pending->connection), pending->specific_object_path, - pending->device_path, + pending->device, sender, &error); g_free (sender); @@ -3189,8 +3176,12 @@ validate_activation_request (NMManager *self, || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) vpn = TRUE; - /* Validate the device path, if given; "/" means NULL */ - if (device_path && (g_strcmp0 (device_path, "/") != 0)) + /* Normalize device path */ + if (device_path && g_strcmp0 (device_path, "/") == 0) + device_path = NULL; + + /* And validate it */ + if (device_path) device = nm_manager_get_device_by_path (self, device_path); /* VPN doesn't require a device, but if one is given validate it. @@ -3232,6 +3223,7 @@ impl_manager_activate_connection (NMManager *self, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); PendingActivation *pending; NMConnection *connection; + NMDevice *device = NULL; GError *error = NULL; connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); @@ -3242,7 +3234,7 @@ impl_manager_activate_connection (NMManager *self, goto error; } - if (!validate_activation_request (self, connection, device_path, NULL, NULL, &error)) + if (!validate_activation_request (self, connection, device_path, &device, NULL, &error)) goto error; /* Need to check the caller's permissions and stuff before we can @@ -3250,7 +3242,7 @@ impl_manager_activate_connection (NMManager *self, */ pending = pending_activation_new (self, context, - device_path, + device, connection, specific_object_path, FALSE, @@ -3363,7 +3355,7 @@ impl_manager_add_and_activate_connection (NMManager *self, */ pending = pending_activation_new (self, context, - device_path, + device, connection, specific_object_path, TRUE, diff --git a/src/nm-manager.h b/src/nm-manager.h index fd6fa0aeee..6baf6f4d90 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -116,7 +116,7 @@ NMDevice *nm_manager_get_device_by_ifindex (NMManager *manager, NMActiveConnection *nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, - const char *device_path, + NMDevice *device, const char *dbus_sender, /* NULL if automatic */ GError **error); diff --git a/src/nm-policy.c b/src/nm-policy.c index 49c005c47e..9f1db55cfb 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1040,7 +1040,7 @@ auto_activate_device (gpointer user_data) if (!nm_manager_activate_connection (priv->manager, best_connection, specific_object, - nm_device_get_path (data->device), + data->device, NULL, &error)) { nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s", @@ -1357,7 +1357,7 @@ activate_secondary_connections (NMPolicy *policy, ac = nm_manager_activate_connection (priv->manager, NM_CONNECTION (settings_con), nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)), - nm_device_get_path (device), + device, nm_act_request_get_dbus_sender (req), &error); if (ac) { From 4e4e14e65ca8b783e6845bd6b688a5829f21cd98 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Sep 2012 16:51:58 -0500 Subject: [PATCH 03/32] core: more flattening of PendingActivation objects Do less authentication in the PA and make the DBusGMethodInvocation opaque to the PA. This pushes the responsibility for replying to the D-Bus method call closer to the D-Bus method handler instead of stuffing it all into the PA. This does mean we need to get the D-Bus sender name and the sender UID and pass that into the pending_activation_new(), but we'll clean that up in a bit. --- src/nm-manager.c | 221 +++++++++++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 93 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index c6123bbf2f..2ff093fad8 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -183,16 +183,19 @@ platform_link_added_cb (NMPlatform *platform, typedef struct PendingActivation PendingActivation; typedef void (*PendingActivationFunc) (PendingActivation *pending, + gpointer user_data, GError *error); struct PendingActivation { NMManager *manager; - DBusGMethodInvocation *context; PendingActivationFunc callback; + gpointer user_data; + + char *dbus_sender; + gulong sender_uid; NMAuthChain *chain; const char *wifi_shared_permission; - gboolean add_and_activate; NMConnection *connection; NMDevice *device; @@ -848,20 +851,22 @@ nm_manager_get_state (NMManager *manager) static PendingActivation * pending_activation_new (NMManager *manager, - DBusGMethodInvocation *context, + char *dbus_sender, + gulong sender_uid, NMDevice *device, NMConnection *connection, const char *specific_object_path, - gboolean add_and_activate, PendingActivationFunc callback, + gpointer user_data, GError **error) { PendingActivation *pending; g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (context != NULL, NULL); + g_return_val_if_fail (dbus_sender != NULL, NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (callback != NULL, NULL); /* A object path of "/" means NULL */ if (g_strcmp0 (specific_object_path, "/") == 0) @@ -869,13 +874,15 @@ pending_activation_new (NMManager *manager, pending = g_slice_new0 (PendingActivation); pending->manager = manager; - pending->context = context; - pending->callback = callback; - pending->add_and_activate = add_and_activate; pending->connection = g_object_ref (connection); pending->device = g_object_ref (device); pending->specific_object_path = g_strdup (specific_object_path); + pending->callback = callback; + pending->user_data = user_data; + pending->dbus_sender = dbus_sender; + pending->sender_uid = sender_uid; + return pending; } @@ -908,7 +915,7 @@ pending_auth_done (NMAuthChain *chain, } } - pending->callback (pending, tmp_error); + pending->callback (pending, pending->user_data, tmp_error); g_clear_error (&tmp_error); } @@ -917,17 +924,16 @@ pending_activation_check_authorized (PendingActivation *pending) { GError *error; const char *wifi_permission = NULL; - const char *error_desc = NULL; g_return_if_fail (pending != NULL); /* First check if the user is allowed to use networking at all, giving * the user a chance to authenticate to gain the permission. */ - pending->chain = nm_auth_chain_new (pending->context, - pending_auth_done, - pending, - &error_desc); + pending->chain = nm_auth_chain_new_dbus_sender (pending->dbus_sender, + pending->sender_uid, + pending_auth_done, + pending); if (pending->chain) { nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); @@ -940,33 +946,19 @@ pending_activation_check_authorized (PendingActivation *pending) } else { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); - pending->callback (pending, error); + "Failed to authorize"); + pending->callback (pending, pending->user_data, error); g_error_free (error); } } static void -pending_activation_destroy (PendingActivation *pending, - GError *error, - NMActiveConnection *ac) +pending_activation_destroy (PendingActivation *pending) { g_return_if_fail (pending != NULL); - if (error) - dbus_g_method_return_error (pending->context, error); - else if (ac) { - if (pending->add_and_activate) { - dbus_g_method_return (pending->context, - nm_connection_get_path (pending->connection), - nm_active_connection_get_path (ac)); - } else { - dbus_g_method_return (pending->context, - nm_active_connection_get_path (ac)); - } - } - g_free (pending->specific_object_path); + g_free (pending->dbus_sender); g_clear_object (&pending->device); g_clear_object (&pending->connection); @@ -3106,71 +3098,58 @@ activated: return ac; } -/* - * TODO this function was created and named in the era of user settings, where - * we could get activation requests for a connection before we got the settings - * data of that connection. Now that user settings are gone, flatten or rename - * it. +/* Finally activate a pending activation request; on success returns the new + * NMActiveConnection object, otherwise NULL and sets an error. */ -static void -pending_activate (PendingActivation *pending, NMSettingsConnection *new_connection) +static NMActiveConnection * +pending_activate (PendingActivation *pending, + NMSettingsConnection *new_connection, + GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager); NMActiveConnection *ac = NULL; - char *sender = NULL; - GError *error = NULL; - - /* If we're given a new NMSettingsConnection (ie, from AddAndActivate now - * that the connection is saved) swap out the old one for the new one. - */ - if (new_connection) { - g_assert (pending->add_and_activate); - g_object_unref (pending->connection); - pending->connection = g_object_ref (new_connection); - } - - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, - pending->context, - &sender, - NULL)) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "D-Bus sender could not be determined."); - } else { - g_assert (sender); - ac = nm_manager_activate_connection (pending->manager, - NM_CONNECTION (pending->connection), - pending->specific_object_path, - pending->device, - sender, - &error); - g_free (sender); - } + GError *local = NULL; + ac = nm_manager_activate_connection (pending->manager, + new_connection ? + NM_CONNECTION (new_connection) : pending->connection, + pending->specific_object_path, + pending->device, + pending->dbus_sender, + &local); if (!ac) { nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", nm_connection_get_path (pending->connection), - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + local->code, local->message ? local->message : "(unknown)"); + g_propagate_error (error, local); } - pending_activation_destroy (pending, error, ac); - g_clear_error (&error); + return ac; } static gboolean validate_activation_request (NMManager *self, + DBusGMethodInvocation *context, NMConnection *connection, const char *device_path, NMDevice **out_device, gboolean *out_vpn, + gulong *out_sender_uid, GError **error) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device = NULL; gboolean vpn = FALSE; g_assert (connection); + /* Get caller's UID */ + if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, out_sender_uid)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, + "Failed to get request UID."); + return FALSE; + } + /* Check whether it's a VPN or not */ if ( nm_connection_get_setting_vpn (connection) || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) @@ -3204,13 +3183,29 @@ validate_activation_request (NMManager *self, return TRUE; } +/***********************************************************************/ + static void -activation_auth_done (PendingActivation *pending, GError *error) +activation_auth_done (PendingActivation *pending, gpointer user_data, GError *error) { - if (error) - pending_activation_destroy (pending, error, NULL); + DBusGMethodInvocation *context = user_data; + NMActiveConnection *ac = NULL; + GError *local = NULL; + + if (!error) { + /* Try to activate the connection */ + ac = pending_activate (pending, NULL, &local); + if (!ac) + error = local; + } + + if (ac) + dbus_g_method_return (context, nm_active_connection_get_path (ac)); else - pending_activate (pending, NULL); + dbus_g_method_return_error (context, error); + + g_clear_error (&local); + pending_activation_destroy (pending); } static void @@ -3225,6 +3220,7 @@ impl_manager_activate_connection (NMManager *self, NMConnection *connection; NMDevice *device = NULL; GError *error = NULL; + gulong sender_uid = G_MAXULONG; connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); if (!connection) { @@ -3234,19 +3230,27 @@ impl_manager_activate_connection (NMManager *self, goto error; } - if (!validate_activation_request (self, connection, device_path, &device, NULL, &error)) + if (!validate_activation_request (self, + context, + connection, + device_path, + &device, + NULL, + &sender_uid, + &error)) goto error; /* Need to check the caller's permissions and stuff before we can * activate the connection. */ pending = pending_activation_new (self, - context, + dbus_g_method_get_sender (context), + sender_uid, device, connection, specific_object_path, - FALSE, activation_auth_done, + context, &error); if (pending) { /* Success */ @@ -3260,35 +3264,55 @@ error: g_error_free (error); } +/***********************************************************************/ + static void activation_add_done (NMSettings *self, - NMSettingsConnection *connection, + NMSettingsConnection *new_connection, GError *error, DBusGMethodInvocation *context, gpointer user_data) { PendingActivation *pending = user_data; + NMActiveConnection *ac = NULL; + GError *local = NULL; - if (error) - pending_activation_destroy (pending, error, NULL); - else { - pending_activate (pending, connection); + if (!error) { + /* Try to activate the connection */ + ac = pending_activate (pending, new_connection, &local); + if (!ac) + error = local; } + + if (ac) { + dbus_g_method_return (context, + nm_connection_get_path (NM_CONNECTION (new_connection)), + nm_active_connection_get_path (ac)); + } else + dbus_g_method_return_error (context, error); + + g_clear_error (&local); + pending_activation_destroy (pending); } static void -add_and_activate_auth_done (PendingActivation *pending, GError *error) +add_and_activate_auth_done (PendingActivation *pending, + gpointer user_data, + GError *error) { - if (error) - pending_activation_destroy (pending, error, NULL); - else { + DBusGMethodInvocation *context = user_data; + + if (error) { + dbus_g_method_return_error (context, error); + pending_activation_destroy (pending); + } else { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager); /* Basic sender auth checks performed; try to add the connection */ nm_settings_add_connection_dbus (priv->settings, pending->connection, TRUE, - pending->context, + context, activation_add_done, pending); } @@ -3308,6 +3332,7 @@ impl_manager_add_and_activate_connection (NMManager *self, GError *error = NULL; NMDevice *device = NULL; gboolean vpn = FALSE; + gulong sender_uid = G_MAXULONG; if (!settings || !g_hash_table_size (settings)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, @@ -3319,7 +3344,14 @@ impl_manager_add_and_activate_connection (NMManager *self, connection = nm_connection_new (); nm_connection_replace_settings (connection, settings, NULL); - if (!validate_activation_request (self, connection, device_path, &device, &vpn, &error)) + if (!validate_activation_request (self, + context, + connection, + device_path, + &device, + &vpn, + &sender_uid, + &error)) goto error; all_connections = nm_settings_get_connections (priv->settings); @@ -3354,12 +3386,13 @@ impl_manager_add_and_activate_connection (NMManager *self, * activate the connection. */ pending = pending_activation_new (self, - context, + dbus_g_method_get_sender (context), + sender_uid, device, connection, specific_object_path, - TRUE, add_and_activate_auth_done, + context, &error); if (pending) { /* Success! */ @@ -3377,6 +3410,8 @@ error: g_error_free (error); } +/***********************************************************************/ + gboolean nm_manager_deactivate_connection (NMManager *manager, const char *connection_path, From 6413241ff2a08ae5821492acea27b222507aa3c8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 17 Sep 2012 10:28:11 -0500 Subject: [PATCH 04/32] core: handle NULL object paths in NMActiveConnection NM uses "/" to mean a NULL object path, since you can't pass NULL object paths through D-Bus. The AC code didn't handle that and we'll soon be passing object paths from D-Bus into it. --- src/nm-active-connection.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 5adf248708..a5264b2e04 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -145,6 +145,11 @@ nm_active_connection_set_specific_object (NMActiveConnection *self, { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + /* Nothing that calls this function should be using paths from D-Bus, + * where NM uses "/" to mean NULL. + */ + g_assert (g_strcmp0 (specific_object, "/") != 0); + if (g_strcmp0 (priv->specific_object, specific_object) == 0) return; @@ -253,6 +258,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); + const char *tmp; switch (prop_id) { case PROP_INT_CONNECTION: @@ -278,7 +284,10 @@ set_property (GObject *object, guint prop_id, g_warn_if_fail (priv->master != priv->device); break; case PROP_SPECIFIC_OBJECT: - priv->specific_object = g_value_dup_boxed (value); + tmp = g_value_get_boxed (value); + /* NM uses "/" to mean NULL */ + if (g_strcmp0 (tmp, "/") != 0) + priv->specific_object = g_value_dup_boxed (value); break; case PROP_DEFAULT: priv->is_default = g_value_get_boolean (value); From 428ebf42b0724954611a0e0b976691b30d4f2065 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 17 Sep 2012 10:59:03 -0500 Subject: [PATCH 05/32] core: simplify NMActRequest The 'connection' and 'device' private variables aren't needed since they will always be available through the NMActiveConnection superclass. --- src/nm-activation-request.c | 52 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 508b10db5d..7c14813f7a 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -51,8 +51,6 @@ typedef struct { } ShareRule; typedef struct { - NMConnection *connection; - NMDevice *device; guint device_state_id; char *dbus_sender; GSList *secrets_calls; @@ -157,6 +155,7 @@ void nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id) { NMActRequestPrivate *priv; + NMConnection *connection; GSList *iter; g_return_if_fail (self); @@ -165,6 +164,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id) priv = NM_ACT_REQUEST_GET_PRIVATE (self); + connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (self)); for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { GetSecretsInfo *info = iter->data; @@ -173,7 +173,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id) priv->secrets_calls = g_slist_remove_link (priv->secrets_calls, iter); g_slist_free (iter); - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), call_id); + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), call_id); g_free (info); break; } @@ -300,6 +300,8 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + g_return_if_fail (device == nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self))); + /* Set NMActiveConnection state based on the device's state */ switch (nm_device_get_state (device)) { case NM_DEVICE_STATE_PREPARE: @@ -323,11 +325,10 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; /* No longer need to pay attention to device state */ - if (priv->device && priv->device_state_id) { - g_signal_handler_disconnect (priv->device, priv->device_state_id); + if (device && priv->device_state_id) { + g_signal_handler_disconnect (device, priv->device_state_id); priv->device_state_id = 0; } - g_clear_object (&priv->device); break; default: break; @@ -376,7 +377,7 @@ nm_act_request_new (NMConnection *connection, GObject *object; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_DEVICE (device), NULL); + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); object = g_object_new (NM_TYPE_ACT_REQUEST, NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, @@ -386,10 +387,8 @@ nm_act_request_new (NMConnection *connection, NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid, NM_ACTIVE_CONNECTION_INT_MASTER, master, NULL); - if (object) { - nm_active_connection_export (NM_ACTIVE_CONNECTION (object)); + if (object) NM_ACT_REQUEST_GET_PRIVATE (object)->dbus_sender = g_strdup (dbus_sender); - } return (NMActRequest *) object; } @@ -403,32 +402,30 @@ static void constructed (GObject *object) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - NMConnection *connection; NMDevice *device; G_OBJECT_CLASS (nm_act_request_parent_class)->constructed (object); - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object)); - priv->connection = g_object_ref (connection); - device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - if (device) { - priv->device = g_object_ref (device); - priv->device_state_id = g_signal_connect (priv->device, - "notify::" NM_DEVICE_STATE, - G_CALLBACK (device_state_changed), - NM_ACT_REQUEST (object)); - } + g_assert (device); + priv->device_state_id = g_signal_connect (device, + "notify::" NM_DEVICE_STATE, + G_CALLBACK (device_state_changed), + NM_ACT_REQUEST (object)); + nm_active_connection_export (NM_ACTIVE_CONNECTION (object)); } static void dispose (GObject *object) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); + NMConnection *connection; + NMDevice *device; GSList *iter; - if (priv->device && priv->device_state_id) { - g_signal_handler_disconnect (priv->device, priv->device_state_id); + device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); + if (device && priv->device_state_id) { + g_signal_handler_disconnect (device, priv->device_state_id); priv->device_state_id = 0; } @@ -439,11 +436,11 @@ dispose (GObject *object) } /* Kill any in-progress secrets requests */ - for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { + connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object)); + for (iter = priv->secrets_calls; connection && iter; iter = g_slist_next (iter)) { GetSecretsInfo *info = iter->data; - g_assert (priv->connection); - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), info->call_id); + nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), info->call_id); g_free (info); } g_slist_free (priv->secrets_calls); @@ -452,9 +449,6 @@ dispose (GObject *object) g_free (priv->dbus_sender); priv->dbus_sender = NULL; - g_clear_object (&priv->device); - g_clear_object (&priv->connection); - G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); } From f6f626de34e8acd24a5bf872455a24660de8d793 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 26 Apr 2013 11:06:58 -0500 Subject: [PATCH 06/32] core: ensure active connection has a device before exporting it --- src/nm-active-connection.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index a5264b2e04..dadb52c5f4 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -210,6 +210,8 @@ nm_active_connection_export (NMActiveConnection *self) NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); static guint32 counter = 0; + g_assert (priv->device || priv->vpn); + priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++); nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); } From 3660a80c29e5a4e3b52b9b726405736b745d6553 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 22 Apr 2013 13:29:36 -0500 Subject: [PATCH 07/32] core: export new active connection from the manager When we eventually do authorization in the ActiveConnection itself, we want to make sure the AC doesn't get exported until everything is authorized. Thus let the manager handle exporting the objects since it knows when the AC will be authorized or not. --- src/nm-activation-request.c | 1 - src/nm-manager.c | 4 +++- src/vpn-manager/nm-vpn-connection.c | 8 +------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 7c14813f7a..6c331777f3 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -412,7 +412,6 @@ constructed (GObject *object) "notify::" NM_DEVICE_STATE, G_CALLBACK (device_state_changed), NM_ACT_REQUEST (object)); - nm_active_connection_export (NM_ACTIVE_CONNECTION (object)); } static void diff --git a/src/nm-manager.c b/src/nm-manager.c index 2ff093fad8..88965d47c7 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3092,8 +3092,10 @@ nm_manager_activate_connection (NMManager *manager, error); activated: - if (ac) + if (ac) { active_connection_add (manager, ac); + nm_active_connection_export (ac); + } return ac; } diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 9f52a2a1fa..a3a30e9ae8 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -403,12 +403,10 @@ nm_vpn_connection_new (NMConnection *connection, gboolean user_requested, gulong user_uid) { - NMVPNConnection *self; - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); - self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, + return (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, @@ -416,10 +414,6 @@ nm_vpn_connection_new (NMConnection *connection, NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid, NM_ACTIVE_CONNECTION_VPN, TRUE, NULL); - if (self) - nm_active_connection_export (NM_ACTIVE_CONNECTION (self)); - - return self; } static const char * From a007292937c0d7032c27735bdd4300124ad389d8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 25 Jul 2013 10:59:28 -0500 Subject: [PATCH 08/32] core: move VPN active connection creation to the manager Eventually the manager will create both NMActRequest and NMVPNConnection subclasses directly, instead of leaving NMVPNConnection creation to the VPN manager. This also ensures that VPN connections get their user_requested attribute set correctly, which wasn't happening before in the case of secondary VPN connections. --- src/nm-manager.c | 28 +++++++++---- src/vpn-manager/nm-vpn-manager.c | 71 +++++++++++++------------------- src/vpn-manager/nm-vpn-manager.h | 10 ++--- src/vpn-manager/nm-vpn-service.c | 28 +++++-------- src/vpn-manager/nm-vpn-service.h | 10 ++--- 5 files changed, 65 insertions(+), 82 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 88965d47c7..f6cc50b9ad 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2841,6 +2841,7 @@ static NMActiveConnection * activate_vpn_connection (NMManager *self, NMConnection *connection, const char *specific_object, + gboolean user_requested, gulong sender_uid, GError **error) { @@ -2848,6 +2849,8 @@ activate_vpn_connection (NMManager *self, NMActiveConnection *parent = NULL; NMDevice *device = NULL; GSList *iter; + NMVPNConnection *vpn; + gboolean success = FALSE; if (specific_object) { /* Find the specifc connection the client requested we use */ @@ -2881,13 +2884,17 @@ activate_vpn_connection (NMManager *self, return NULL; } - return nm_vpn_manager_activate_connection (priv->vpn_manager, - connection, - device, - nm_active_connection_get_path (parent), - TRUE, - sender_uid, - error); + vpn = nm_vpn_connection_new (connection, + device, + nm_active_connection_get_path (parent), + user_requested, + sender_uid); + g_assert (vpn); + success = nm_vpn_manager_activate_connection (priv->vpn_manager, vpn, error); + if (!success) + g_object_unref (vpn); + + return success ? NM_ACTIVE_CONNECTION (vpn) : NULL; } NMActiveConnection * @@ -2928,7 +2935,12 @@ nm_manager_activate_connection (NMManager *manager, /* VPN ? */ if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { - ac = activate_vpn_connection (manager, connection, specific_object, sender_uid, error); + ac = activate_vpn_connection (manager, + connection, + specific_object, + !!dbus_sender, + sender_uid, + error); goto activated; } diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 9cd140e54e..6c63edc1e7 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -78,7 +78,7 @@ get_service_by_namefile (NMVPNManager *self, const char *namefile) } static NMVPNConnection * -find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *connection) +find_active_vpn_connection (NMVPNManager *self, NMConnection *connection) { NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); GHashTableIter iter; @@ -104,66 +104,53 @@ find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *conn return found; } -NMActiveConnection * +gboolean nm_vpn_manager_activate_connection (NMVPNManager *manager, - NMConnection *connection, - NMDevice *device, - const char *specific_object, - gboolean user_requested, - gulong user_uid, + NMVPNConnection *vpn, GError **error) { - NMSettingVPN *vpn_setting; + NMVPNConnection *existing = NULL; + NMConnection *connection; + NMSettingVPN *s_vpn; NMVPNService *service; - NMVPNConnection *vpn = NULL; const char *service_name; + NMDevice *device; - g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - g_return_val_if_fail (error != NULL, NULL); - g_return_val_if_fail (*error == NULL, NULL); + g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE); + g_return_val_if_fail (error != NULL, FALSE); + g_return_val_if_fail (*error == NULL, FALSE); + device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); + g_assert (device); if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED && nm_device_get_state (device) != NM_DEVICE_STATE_SECONDARIES) { - g_set_error (error, - NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE, - "%s", "The base device for the VPN connection was not active."); - return NULL; + g_set_error_literal (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE, + "The base device for the VPN connection was not active."); + return FALSE; } - vpn_setting = nm_connection_get_setting_vpn (connection); - if (!vpn_setting) { - g_set_error (error, - NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_CONNECTION_INVALID, - "%s", "The connection was not a VPN connection."); - return NULL; - } + connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn)); + g_assert (connection); + s_vpn = nm_connection_get_setting_vpn (connection); + g_assert (s_vpn); - vpn = find_active_vpn_connection_by_connection (manager, connection); - if (vpn) { - nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED); - vpn = NULL; - } - - service_name = nm_setting_vpn_get_service_type (vpn_setting); + service_name = nm_setting_vpn_get_service_type (s_vpn); g_assert (service_name); service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name); if (!service) { - g_set_error (error, - NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID, + g_set_error (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID, "The VPN service '%s' was not installed.", service_name); - return NULL; + return FALSE; } - return (NMActiveConnection *) nm_vpn_service_activate (service, - connection, - device, - specific_object, - user_requested, - user_uid, - error); + existing = find_active_vpn_connection (manager, + nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn))); + if (existing) + nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED); + + return nm_vpn_service_activate (service, vpn, error); } gboolean diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index 1d398ea2cb..57f947b0e4 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -59,13 +59,9 @@ GType nm_vpn_manager_get_type (void); NMVPNManager *nm_vpn_manager_get (void); -NMActiveConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager, - NMConnection *connection, - NMDevice *device, - const char *specific_object, - gboolean user_requested, - gulong user_uid, - GError **error); +gboolean nm_vpn_manager_activate_connection (NMVPNManager *manager, + NMVPNConnection *vpn, + GError **error); gboolean nm_vpn_manager_deactivate_connection (NMVPNManager *manager, NMVPNConnection *connection, diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index a34c782e73..8ecd9a1176 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -323,45 +323,37 @@ connection_vpn_state_changed (NMVPNConnection *connection, } } -NMVPNConnection * +gboolean nm_vpn_service_activate (NMVPNService *service, - NMConnection *connection, - NMDevice *device, - const char *specific_object, - gboolean user_requested, - gulong user_uid, + NMVPNConnection *vpn, GError **error) { - NMVPNConnection *vpn; NMVPNServicePrivate *priv; - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - g_return_val_if_fail (error != NULL, NULL); - g_return_val_if_fail (*error == NULL, NULL); + g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE); + g_return_val_if_fail (error != NULL, FALSE); + g_return_val_if_fail (*error == NULL, FALSE); priv = NM_VPN_SERVICE_GET_PRIVATE (service); clear_quit_timeout (service); - vpn = nm_vpn_connection_new (connection, device, specific_object, user_requested, user_uid); g_signal_connect (vpn, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, G_CALLBACK (connection_vpn_state_changed), service); priv->connections = g_slist_prepend (priv->connections, g_object_ref (vpn)); - if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service)) { - // FIXME: fill in error when errors happen + if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service)) nm_vpn_connection_activate (vpn); - } else if (priv->start_timeout == 0) { + else if (priv->start_timeout == 0) { nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name); if (!nm_vpn_service_daemon_exec (service, error)) - vpn = NULL; + return FALSE; } - return vpn; + return TRUE; } const GSList * diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h index e883d55f8b..2ad79a0d6b 100644 --- a/src/vpn-manager/nm-vpn-service.h +++ b/src/vpn-manager/nm-vpn-service.h @@ -54,13 +54,9 @@ const char *nm_vpn_service_get_dbus_service (NMVPNService *service); /* Returns the path of the VPN service's .name file */ const char *nm_vpn_service_get_name_file (NMVPNService *service); -NMVPNConnection * nm_vpn_service_activate (NMVPNService *service, - NMConnection *connection, - NMDevice *device, - const char *specific_object, - gboolean user_requested, - gulong user_uid, - GError **error); +gboolean nm_vpn_service_activate (NMVPNService *service, + NMVPNConnection *vpn, + GError **error); const GSList *nm_vpn_service_get_active_connections (NMVPNService *service); From 7a9d5a262a9767c8639831151efd9b7858d25272 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 25 Jul 2013 12:01:49 -0500 Subject: [PATCH 09/32] core: grab remote process id when authenticating D-Bus clients --- src/nm-dbus-manager.c | 46 ++++++++++++++++++++++++--- src/nm-dbus-manager.h | 6 ++-- src/nm-manager-auth.c | 3 +- src/nm-manager.c | 5 +-- src/settings/nm-agent-manager.c | 4 ++- src/settings/nm-settings-connection.c | 2 +- src/settings/nm-settings.c | 4 +-- 7 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 891a765f46..e9d5fce5c1 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -267,6 +267,27 @@ private_server_get_connection_owner (PrivateServer *s, DBusGConnection *connecti /**************************************************************/ +static gboolean +_bus_get_unix_pid (NMDBusManager *self, + const char *sender, + gulong *out_pid, + GError **error) +{ + guint32 unix_pid = G_MAXUINT32; + + if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, + "GetConnectionUnixProcessID", 2000, error, + G_TYPE_STRING, sender, + G_TYPE_INVALID, + G_TYPE_UINT, &unix_pid, + G_TYPE_INVALID)) { + return FALSE; + } + + *out_pid = (gulong) unix_pid; + return TRUE; +} + /** * _get_caller_info_from_context(): * @@ -279,7 +300,8 @@ _get_caller_info (NMDBusManager *self, DBusConnection *connection, DBusMessage *message, char **out_sender, - gulong *out_uid) + gulong *out_uid, + gulong *out_pid) { NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); DBusGConnection *gconn; @@ -312,6 +334,10 @@ _get_caller_info (NMDBusManager *self, *out_uid = 0; if (out_sender) *out_sender = g_strdup (priv_sender); + if (out_pid) { + if (!dbus_connection_get_unix_process_id (connection, out_pid)) + *out_pid = G_MAXULONG; + } return TRUE; } } @@ -331,6 +357,14 @@ _get_caller_info (NMDBusManager *self, } } + if (out_pid) { + if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { + *out_pid = G_MAXULONG; + g_free (sender); + return FALSE; + } + } + if (out_sender) *out_sender = g_strdup (sender); @@ -342,9 +376,10 @@ gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self, DBusGMethodInvocation *context, char **out_sender, - gulong *out_uid) + gulong *out_uid, + gulong *out_pid) { - return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid); + return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); } gboolean @@ -352,9 +387,10 @@ nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, DBusConnection *connection, DBusMessage *message, char **out_sender, - gulong *out_uid) + gulong *out_uid, + gulong *out_pid) { - return _get_caller_info (self, NULL, connection, message, out_sender, out_uid); + return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); } gboolean diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h index 319252e87f..7895a20375 100644 --- a/src/nm-dbus-manager.h +++ b/src/nm-dbus-manager.h @@ -87,7 +87,8 @@ DBusGConnection * nm_dbus_manager_get_connection (NMDBusManager *self); gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self, DBusGMethodInvocation *context, char **out_sender, - gulong *out_uid); + gulong *out_uid, + gulong *out_pid); gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self, const char *sender, @@ -97,7 +98,8 @@ gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, DBusConnection *connection, DBusMessage *message, char **out_sender, - gulong *out_uid); + gulong *out_uid, + gulong *out_pid); void nm_dbus_manager_register_exported_type (NMDBusManager *self, GType object_type, diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c index eea74f2152..78b78cfa4f 100644 --- a/src/nm-manager-auth.c +++ b/src/nm-manager-auth.c @@ -157,7 +157,8 @@ nm_auth_chain_new (DBusGMethodInvocation *context, if (nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, &sender, - &sender_uid)) { + &sender_uid, + NULL)) { chain = _auth_chain_new (context, NULL, sender, sender_uid, done_func, user_data); } diff --git a/src/nm-manager.c b/src/nm-manager.c index f6cc50b9ad..eede07c50b 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3157,7 +3157,7 @@ validate_activation_request (NMManager *self, g_assert (connection); /* Get caller's UID */ - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, out_sender_uid)) { + if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, out_sender_uid, NULL)) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Failed to get request UID."); @@ -4410,7 +4410,8 @@ prop_filter (DBusConnection *connection, connection, message, NULL, - &caller_uid)) { + &caller_uid, + NULL)) { reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, "Could not determine request UID."); goto out; diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 5d1c519efa..980b1f1461 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -280,7 +280,8 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, &sender, - &sender_uid)) { + &sender_uid, + NULL)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, "Unable to determine request sender and UID."); @@ -363,6 +364,7 @@ impl_agent_manager_unregister (NMAgentManager *self, if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, &sender, + NULL, NULL)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 0d7fe3a8e1..bc6eb17155 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -1009,7 +1009,7 @@ check_user_in_acl (NMConnection *connection, g_return_val_if_fail (session_monitor != NULL, FALSE); /* Get the caller's UID */ - if (!nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, NULL, &sender_uid)) { + if (!nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, NULL, &sender_uid, NULL)) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 2898888add..e6187175e9 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1135,7 +1135,7 @@ nm_settings_add_connection_dbus (NMSettings *self, } /* Get the caller's UID */ - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) { + if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Unable to determine request UID."); @@ -1251,7 +1251,7 @@ impl_settings_reload_connections (NMSettings *self, gulong caller_uid; GError *error = NULL; - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) { + if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Unable to determine request UID."); From 49d098f29d7a0bf98e7fbecc4febf48d912e095b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 25 Jul 2013 22:53:43 -0500 Subject: [PATCH 10/32] core: add NMAuthSubject object to encapsulate authentication info This object encapsulates all authentication information we need about some entity that requests that NetworkManager perform an action on its behalf. --- src/Makefile.am | 2 + src/devices/wimax/Makefile.am | 1 + src/nm-auth-subject.c | 210 ++++++++++++++++++++++++++++++++++ src/nm-auth-subject.h | 68 +++++++++++ 4 files changed, 281 insertions(+) create mode 100644 src/nm-auth-subject.c create mode 100644 src/nm-auth-subject.h diff --git a/src/Makefile.am b/src/Makefile.am index 3a64a8f7d9..bcac9ac300 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -248,6 +248,8 @@ nm_sources = \ nm-ip6-config.h \ nm-manager-auth.c \ nm-manager-auth.h \ + nm-auth-subject.c \ + nm-auth-subject.h \ nm-manager.c \ nm-manager.h \ nm-netlink-monitor.c \ diff --git a/src/devices/wimax/Makefile.am b/src/devices/wimax/Makefile.am index 80a93b5be7..f6bd1e9e71 100644 --- a/src/devices/wimax/Makefile.am +++ b/src/devices/wimax/Makefile.am @@ -9,6 +9,7 @@ AM_CPPFLAGS = \ -I${top_builddir}/libnm-util \ -I${top_srcdir}/libnm-util \ $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) \ $(IWMX_SDK_CFLAGS) \ $(LIBNL_CFLAGS) \ $(GUDEV_CFLAGS) diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c new file mode 100644 index 0000000000..66c0d4e63e --- /dev/null +++ b/src/nm-auth-subject.c @@ -0,0 +1,210 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +/** + * SECTION:nm-auth-subject + * @short_description: Encapsulates authentication information about a requestor + * + * #NMAuthSubject encpasulates identifying information about an entity that + * makes requests, like process identifier and user UID. + */ + +#include +#include +#include +#include +#include + +#if WITH_POLKIT +#include +#endif + +#include "nm-auth-subject.h" +#include "nm-dbus-manager.h" + +G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT) + +#define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate)) + +typedef struct { + gulong pid; + gulong uid; + char *dbus_sender; + +#if WITH_POLKIT + PolkitSubject *pk_subject; +#endif +} NMAuthSubjectPrivate; + +static NMAuthSubject * +_new_common (DBusGMethodInvocation *context, + DBusConnection *connection, + DBusMessage *message, + gboolean internal) +{ + NMAuthSubject *subject; + NMAuthSubjectPrivate *priv; + NMDBusManager *dbus_mgr; + gboolean success = FALSE; + + g_return_val_if_fail (context || (connection && message) || internal, NULL); + if (internal) + g_return_val_if_fail (context == NULL && connection == NULL && message == NULL, NULL); + + subject = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, NULL)); + priv = NM_AUTH_SUBJECT_GET_PRIVATE (subject); + + dbus_mgr = nm_dbus_manager_get (); + + if (internal) { + priv->uid = 0; + priv->pid = 0; + return subject; + } + + if (context) { + success = nm_dbus_manager_get_caller_info (dbus_mgr, + context, + &priv->dbus_sender, + &priv->uid, + &priv->pid); + } else if (message) { + success = nm_dbus_manager_get_caller_info_from_message (dbus_mgr, + connection, + message, + &priv->dbus_sender, + &priv->uid, + &priv->pid); + } else + g_assert_not_reached (); + + if (!success) { + g_object_unref (subject); + return NULL; + } + + g_assert (priv->dbus_sender); + g_assert_cmpuint (priv->pid, !=, 0); + +#if WITH_POLKIT + /* FIXME: should we use polkit_unix_session_new() to store the session ID + * of a short-lived process, so that the process can exit but we can still + * ask that user for authorization? + */ + priv->pk_subject = polkit_unix_process_new_for_owner (priv->pid, 0, priv->uid); + if (!priv->pk_subject) + return NULL; +#endif + + return subject; +} + + +NMAuthSubject * +nm_auth_subject_new_from_context (DBusGMethodInvocation *context) +{ + return _new_common (context, NULL, NULL, FALSE); +} + +NMAuthSubject * +nm_auth_subject_new_from_message (DBusConnection *connection, + DBusMessage *message) +{ + return _new_common (NULL, connection, message, FALSE); +} + +/** + * nm_auth_subject_new_internal(): + * + * Creates a new auth subject representing the NetworkManager process itself. + * + * Returns: the new #NMAuthSubject + */ +NMAuthSubject * +nm_auth_subject_new_internal (void) +{ + return _new_common (NULL, NULL, NULL, TRUE); +} + +/**************************************************************/ + +gulong +nm_auth_subject_get_uid (NMAuthSubject *subject) +{ + return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->uid; +} + +const char * +nm_auth_subject_get_dbus_sender (NMAuthSubject *subject) +{ + return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender; +} + +gboolean +nm_auth_subject_get_internal (NMAuthSubject *subject) +{ + /* internal requests will have no dbus sender */ + return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender ? FALSE : TRUE; +} + +#if WITH_POLKIT +PolkitSubject * +nm_auth_subject_get_polkit_subject (NMAuthSubject *subject) +{ + return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pk_subject; +} +#endif + +/******************************************************************/ + +static void +nm_auth_subject_init (NMAuthSubject *self) +{ + NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); + + priv->pid = G_MAXULONG; + priv->uid = G_MAXULONG; +} + +static void +finalize (GObject *object) +{ + NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object); + + g_free (priv->dbus_sender); + +#if WITH_POLKIT + if (priv->pk_subject) + g_object_unref (priv->pk_subject); +#endif + + G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object); +} + +static void +nm_auth_subject_class_init (NMAuthSubjectClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate)); + + /* virtual methods */ + object_class->finalize = finalize; +} diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h new file mode 100644 index 0000000000..8f049a8405 --- /dev/null +++ b/src/nm-auth-subject.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef NM_AUTH_SUBJECT_H +#define NM_AUTH_SUBJECT_H + +#include +#include +#include +#include +#include + +#if WITH_POLKIT +#include +#endif + +#define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ()) +#define NM_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject)) +#define NM_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass)) +#define NM_IS_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_SUBJECT)) +#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT)) +#define NM_AUTH_SUBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass)) + +typedef struct { + GObject parent; +} NMAuthSubject; + +typedef struct { + GObjectClass parent; + +} NMAuthSubjectClass; + +GType nm_auth_subject_get_type (void); + +NMAuthSubject *nm_auth_subject_new_from_context (DBusGMethodInvocation *context); + +NMAuthSubject *nm_auth_subject_new_from_message (DBusConnection *connection, DBusMessage *message); + +NMAuthSubject *nm_auth_subject_new_internal (void); + +gulong nm_auth_subject_get_uid (NMAuthSubject *subject); + +const char *nm_auth_subject_get_dbus_sender (NMAuthSubject *subject); + +gboolean nm_auth_subject_get_internal (NMAuthSubject *subject); + +#if WITH_POLKIT +PolkitSubject *nm_auth_subject_get_polkit_subject (NMAuthSubject *subject); +#endif + +#endif /* NM_AUTH_SUBJECT_H */ From 7fe84e0ec7264538d0ab6b55be46ada2758d9fe4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 10:39:23 -0500 Subject: [PATCH 11/32] core: add function to create auth chains from a subjects or contexts The subject already contains all the information we need. --- src/nm-manager-auth.c | 78 +++++++++++++++++++++++++++++++++++++------ src/nm-manager-auth.h | 10 ++++++ 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c index 78b78cfa4f..8d4d0d7cc0 100644 --- a/src/nm-manager-auth.c +++ b/src/nm-manager-auth.c @@ -31,6 +31,7 @@ #include "nm-manager-auth.h" #include "nm-logging.h" #include "nm-dbus-manager.h" +#include "nm-auth-subject.h" struct NMAuthChain { guint32 refcount; @@ -43,6 +44,7 @@ struct NMAuthChain { DBusGMethodInvocation *context; char *owner; gulong user_uid; + NMAuthSubject *subject; GError *error; guint idle_id; @@ -109,6 +111,7 @@ _auth_chain_new (DBusGMethodInvocation *context, DBusMessage *message, const char *dbus_sender, gulong user_uid, + NMAuthSubject *subject, NMAuthChainResultFunc done_func, gpointer user_data) { @@ -125,18 +128,24 @@ _auth_chain_new (DBusGMethodInvocation *context, self->done_func = done_func; self->user_data = user_data; self->context = context; - self->user_uid = user_uid; + + if (subject) { + self->user_uid = nm_auth_subject_get_uid (subject); + self->subject = g_object_ref (subject); + return self; + } if (message) self->owner = g_strdup (dbus_message_get_sender (message)); else if (dbus_sender) self->owner = g_strdup (dbus_sender); + self->user_uid = user_uid; if (user_uid > 0 && !self->owner) { /* Need an owner */ g_warn_if_fail (self->owner); nm_auth_chain_unref (self); - self = NULL; + return NULL; } return self; @@ -159,7 +168,7 @@ nm_auth_chain_new (DBusGMethodInvocation *context, &sender, &sender_uid, NULL)) { - chain = _auth_chain_new (context, NULL, sender, sender_uid, done_func, user_data); + chain = _auth_chain_new (context, NULL, sender, sender_uid, NULL, done_func, user_data); } if (!chain && out_error_desc) @@ -175,7 +184,7 @@ nm_auth_chain_new_raw_message (DBusMessage *message, NMAuthChainResultFunc done_func, gpointer user_data) { - return _auth_chain_new (NULL, message, NULL, user_uid, done_func, user_data); + return _auth_chain_new (NULL, message, NULL, user_uid, NULL, done_func, user_data); } NMAuthChain * @@ -184,7 +193,49 @@ nm_auth_chain_new_dbus_sender (const char *dbus_sender, NMAuthChainResultFunc done_func, gpointer user_data) { - return _auth_chain_new (NULL, NULL, dbus_sender, user_uid, done_func, user_data); + return _auth_chain_new (NULL, NULL, dbus_sender, user_uid, NULL, done_func, user_data); +} + +/* Creates the NMAuthSubject automatically */ +NMAuthChain * +nm_auth_chain_new_context (DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthSubject *subject; + NMAuthChain *chain; + + g_return_val_if_fail (context != NULL, NULL); + + subject = nm_auth_subject_new_from_context (context); + if (!subject) + return NULL; + + chain = nm_auth_chain_new_subject (subject, + context, + done_func, + user_data); + g_object_unref (subject); + return chain; +} + +/* Requires an NMAuthSubject */ +NMAuthChain * +nm_auth_chain_new_subject (NMAuthSubject *subject, + DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthChain *chain; + + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); + chain = _auth_chain_new (context, NULL, NULL, G_MAXULONG, subject, done_func, user_data); + + /* Chains creation from a valid NMAuthSubject cannot fail since the + * subject already has all the necessary auth info. + */ + g_assert (chain); + return chain; } gpointer @@ -423,7 +474,7 @@ _add_call_polkit (NMAuthChain *self, AuthCall *call; g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (self->owner != NULL, FALSE); + g_return_val_if_fail (self->owner || self->subject, FALSE); g_return_val_if_fail (permission != NULL, FALSE); call = auth_call_new (self, permission); @@ -434,10 +485,16 @@ _add_call_polkit (NMAuthChain *self, return FALSE; } - subject = polkit_system_bus_name_new (self->owner); - if (!subject) { - auth_call_schedule_complete_with_error (call, "Failed to create polkit subject"); - return FALSE; + if (self->subject) { + subject = g_object_ref (nm_auth_subject_get_polkit_subject (self->subject)); + g_assert (subject); + } else { + g_assert (self->owner); + subject = polkit_system_bus_name_new (self->owner); + if (!subject) { + auth_call_schedule_complete_with_error (call, "Failed to create polkit subject"); + return FALSE; + } } if (allow_interaction) @@ -497,6 +554,7 @@ nm_auth_chain_unref (NMAuthChain *self) g_object_unref (self->authority); #endif g_free (self->owner); + g_object_unref (self->subject); for (iter = self->calls; iter; iter = g_slist_next (iter)) auth_call_cancel ((AuthCall *) iter->data); diff --git a/src/nm-manager-auth.h b/src/nm-manager-auth.h index ebfb707254..46aa2b9fb1 100644 --- a/src/nm-manager-auth.h +++ b/src/nm-manager-auth.h @@ -27,6 +27,7 @@ #include #include "nm-dbus-manager.h" #include "nm-session-monitor.h" +#include "nm-auth-subject.h" #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" #define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" @@ -70,6 +71,15 @@ NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender, NMAuthChainResultFunc done_func, gpointer user_data); +NMAuthChain *nm_auth_chain_new_context (DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data); + +NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject, + DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data); + gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag); gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag); From e39435a596f8a851329b95d4e9e844ec55ba5b9e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 10:40:11 -0500 Subject: [PATCH 12/32] agents: use NMAuthSubject --- src/settings/nm-agent-manager.c | 37 +++++++++--------- src/settings/nm-secret-agent.c | 67 ++++++++++++++++++--------------- src/settings/nm-secret-agent.h | 8 ++-- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 980b1f1461..33fbbe7ff3 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -206,6 +206,8 @@ agent_register_permissions_done (NMAuthChain *chain, GHashTableIter iter; Request *req; + g_assert (context); + priv->chains = g_slist_remove (priv->chains, chain); if (error) { @@ -270,23 +272,20 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, DBusGMethodInvocation *context) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - char *sender = NULL; + NMAuthSubject *subject; gulong sender_uid = G_MAXULONG; GError *error = NULL, *local = NULL; NMSecretAgent *agent; NMAuthChain *chain; - const char *error_desc = NULL; - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, - context, - &sender, - &sender_uid, - NULL)) { + subject = nm_auth_subject_new_from_context (context); + if (!subject) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, "Unable to determine request sender and UID."); goto done; } + sender_uid = nm_auth_subject_get_uid (subject); if ( 0 != sender_uid && !nm_session_monitor_uid_has_session (priv->session_monitor, @@ -312,7 +311,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, } /* Success, add the new agent */ - agent = nm_secret_agent_new (context, sender, identifier, sender_uid, capabilities); + agent = nm_secret_agent_new (context, subject, identifier, capabilities); if (!agent) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, @@ -324,7 +323,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, nm_secret_agent_get_description (agent)); /* Kick off permissions requests for this agent */ - chain = nm_auth_chain_new (context, agent_register_permissions_done, self, &error_desc); + chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self); if (chain) { nm_auth_chain_set_data (chain, "agent", agent, g_object_unref); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); @@ -334,7 +333,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, } else { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, - error_desc); + "Unable to start agent authentication."); } done: @@ -342,7 +341,7 @@ done: dbus_g_method_return_error (context, error); g_clear_error (&error); g_clear_error (&local); - g_free (sender); + g_clear_object (&subject); } static void @@ -1018,10 +1017,10 @@ get_next_cb (Request *parent) nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY", req, parent->detail, req->setting_name, agent_dbus_owner); - req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner, - nm_secret_agent_get_owner_uid (parent->current), - get_agent_modify_auth_cb, - req); + req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current), + NULL, + get_agent_modify_auth_cb, + req); g_assert (req->chain); /* If the caller is the only user in the connection's permissions, then @@ -1504,10 +1503,10 @@ authority_changed_cb (gpointer user_data) NMAuthChain *chain; /* Kick off permissions requests for this agent */ - chain = nm_auth_chain_new_dbus_sender (nm_secret_agent_get_dbus_owner (agent), - nm_secret_agent_get_owner_uid (agent), - agent_permissions_changed_done, - self); + chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent), + NULL, + agent_permissions_changed_done, + self); g_assert (chain); priv->chains = g_slist_append (priv->chains, chain); diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 7f0e879a3a..66ddc36a2a 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -31,6 +31,7 @@ #include "nm-secret-agent.h" #include "nm-dbus-manager.h" #include "nm-dbus-glib-types.h" +#include "nm-glib-compat.h" #include "nm-logging.h" G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) @@ -40,12 +41,9 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) NMSecretAgentPrivate)) typedef struct { - gboolean disposed; - char *description; - char *owner; + NMAuthSubject *subject; char *identifier; - uid_t owner_uid; char *owner_username; NMSecretAgentCapabilities capabilities; guint32 hash; @@ -106,10 +104,10 @@ nm_secret_agent_get_description (NMSecretAgent *agent) priv = NM_SECRET_AGENT_GET_PRIVATE (agent); if (!priv->description) { - priv->description = g_strdup_printf ("%s/%s/%u", - priv->owner, + priv->description = g_strdup_printf ("%s/%s/%lu", + nm_auth_subject_get_dbus_sender (priv->subject), priv->identifier, - priv->owner_uid); + nm_auth_subject_get_uid (priv->subject)); } return priv->description; @@ -120,7 +118,7 @@ nm_secret_agent_get_dbus_owner (NMSecretAgent *agent) { g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); - return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner; + return nm_auth_subject_get_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject); } const char * @@ -131,16 +129,16 @@ nm_secret_agent_get_identifier (NMSecretAgent *agent) return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier; } -uid_t +gulong nm_secret_agent_get_owner_uid (NMSecretAgent *agent) { - g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXUINT); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG); - return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid; + return nm_auth_subject_get_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject); } const char * -nm_secret_agent_get_owner_username(NMSecretAgent *agent) +nm_secret_agent_get_owner_username (NMSecretAgent *agent) { g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); @@ -156,13 +154,21 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent) } guint32 -nm_secret_agent_get_hash (NMSecretAgent *agent) +nm_secret_agent_get_hash (NMSecretAgent *agent) { g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0); return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; } +NMAuthSubject * +nm_secret_agent_get_subject (NMSecretAgent *agent) +{ + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->subject; +} + /** * nm_secret_agent_add_permission: * @agent: A #NMSecretAgent. @@ -443,9 +449,8 @@ proxy_cleanup (NMSecretAgent *self) NMSecretAgent * nm_secret_agent_new (DBusGMethodInvocation *context, - const char *owner, + NMAuthSubject *subject, const char *identifier, - uid_t owner_uid, NMSecretAgentCapabilities capabilities) { NMSecretAgent *self; @@ -453,10 +458,11 @@ nm_secret_agent_new (DBusGMethodInvocation *context, char *hash_str, *username; struct passwd *pw; - g_return_val_if_fail (owner != NULL, NULL); + g_return_val_if_fail (context != NULL, NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (identifier != NULL, NULL); - pw = getpwuid (owner_uid); + pw = getpwuid (nm_auth_subject_get_uid (subject)); g_return_val_if_fail (pw != NULL, NULL); g_return_val_if_fail (pw->pw_name[0] != '\0', NULL); username = g_strdup (pw->pw_name); @@ -464,19 +470,18 @@ nm_secret_agent_new (DBusGMethodInvocation *context, self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); priv = NM_SECRET_AGENT_GET_PRIVATE (self); - priv->owner = g_strdup (owner); priv->identifier = g_strdup (identifier); - priv->owner_uid = owner_uid; priv->owner_username = g_strdup (username); priv->capabilities = capabilities; + priv->subject = g_object_ref (subject); - hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier); + hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_uid (subject), identifier); priv->hash = g_str_hash (hash_str); g_free (hash_str); priv->proxy = nm_dbus_manager_new_proxy (nm_dbus_manager_get (), context, - owner, + nm_auth_subject_get_dbus_sender (subject), NM_DBUS_PATH_SECRET_AGENT, NM_DBUS_INTERFACE_SECRET_AGENT); g_assert (priv->proxy); @@ -501,21 +506,21 @@ dispose (GObject *object) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); - if (!priv->disposed) { - priv->disposed = TRUE; + g_clear_pointer (&priv->description, g_free); + g_clear_pointer (&priv->identifier, g_free); + g_clear_pointer (&priv->owner_username, g_free); - g_free (priv->description); - g_free (priv->owner); - g_free (priv->identifier); - g_free (priv->owner_username); - - g_slist_free_full (priv->permissions, g_free); + g_slist_free_full (priv->permissions, g_free); + priv->permissions = NULL; + if (priv->requests) { g_hash_table_destroy (priv->requests); - - proxy_cleanup (NM_SECRET_AGENT (object)); + priv->requests = NULL; } + proxy_cleanup (NM_SECRET_AGENT (object)); + g_clear_object (&priv->subject); + G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); } diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index a59182e533..b75f7177db 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -29,6 +29,7 @@ #include #include "nm-dbus-manager.h" #include "nm-settings-flags.h" +#include "nm-auth-subject.h" /* NOTE: ensure these capabilities match those in introspection/nm-secret-agent.xml and * libnm-glib/nm-secret-agent.h. @@ -56,9 +57,8 @@ typedef struct { GType nm_secret_agent_get_type (void); NMSecretAgent *nm_secret_agent_new (DBusGMethodInvocation *context, - const char *owner, + NMAuthSubject *subject, const char *identifier, - uid_t owner_uid, NMSecretAgentCapabilities capabilities); const char *nm_secret_agent_get_description (NMSecretAgent *agent); @@ -67,7 +67,7 @@ const char *nm_secret_agent_get_dbus_owner (NMSecretAgent *agent); const char *nm_secret_agent_get_identifier (NMSecretAgent *agent); -uid_t nm_secret_agent_get_owner_uid (NMSecretAgent *agent); +gulong nm_secret_agent_get_owner_uid (NMSecretAgent *agent); const char *nm_secret_agent_get_owner_username (NMSecretAgent *agent); @@ -75,6 +75,8 @@ NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent guint32 nm_secret_agent_get_hash (NMSecretAgent *agent); +NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent); + void nm_secret_agent_add_permission (NMSecretAgent *agent, const char *permission, gboolean allowed); From f403e6afc06041cd0d9e96743c691a39ee7f2c04 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 11:06:27 -0500 Subject: [PATCH 13/32] settings: use NMAuthSubject in NMSettingsConnection --- src/settings/nm-settings-connection.c | 195 +++++++++++++++----------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index bc6eb17155..59b29ad199 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -994,47 +994,35 @@ pk_auth_cb (NMAuthChain *chain, nm_auth_chain_unref (chain); } -static gboolean -check_user_in_acl (NMConnection *connection, - DBusGMethodInvocation *context, - NMSessionMonitor *session_monitor, - gulong *out_sender_uid, - GError **error) +/** + * _new_auth_subject: + * @context: the D-Bus method invocation context + * @error: on failure, a #GError + * + * Creates an NMAuthSubject for the caller. + * + * Returns: the #NMAuthSubject on success, or %NULL on failure and sets @error + */ +static NMAuthSubject * +_new_auth_subject (DBusGMethodInvocation *context, GError **error) { - gulong sender_uid = G_MAXULONG; - char *error_desc = NULL; + NMAuthSubject *subject; - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (context != NULL, FALSE); - g_return_val_if_fail (session_monitor != NULL, FALSE); - - /* Get the caller's UID */ - if (!nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, NULL, &sender_uid, NULL)) { + subject = nm_auth_subject_new_from_context (context); + if (!subject) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Unable to determine UID of request."); - return FALSE; } - /* Make sure the UID can view this connection */ - if (!nm_auth_uid_in_acl (connection, session_monitor, sender_uid, &error_desc)) { - g_set_error_literal (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - error_desc); - g_free (error_desc); - return FALSE; - } - - if (out_sender_uid) - *out_sender_uid = sender_uid; - return TRUE; + return subject; } static void auth_start (NMSettingsConnection *self, DBusGMethodInvocation *context, + NMAuthSubject *subject, const char *check_permission, AuthCallback callback, gpointer callback_data) @@ -1043,41 +1031,49 @@ auth_start (NMSettingsConnection *self, NMAuthChain *chain; gulong sender_uid = G_MAXULONG; GError *error = NULL; - const char *error_desc = NULL; + char *error_desc = NULL; + + g_return_if_fail (context != NULL); + g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); + + /* Ensure the caller can view this connection */ + if (!nm_auth_uid_in_acl (NM_CONNECTION (self), + priv->session_monitor, + nm_auth_subject_get_uid (subject), + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); - if (!check_user_in_acl (NM_CONNECTION (self), - context, - priv->session_monitor, - &sender_uid, - &error)) { callback (self, context, G_MAXULONG, error, callback_data); g_clear_error (&error); return; } - if (check_permission) { - chain = nm_auth_chain_new (context, pk_auth_cb, self, &error_desc); - if (chain) { - priv->pending_auths = g_slist_append (priv->pending_auths, chain); - - nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL); - nm_auth_chain_set_data (chain, "callback", callback, NULL); - nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL); - nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid); - - nm_auth_chain_add_call (chain, check_permission, TRUE); - } else { - g_set_error_literal (&error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - error_desc); - callback (self, context, G_MAXULONG, error, callback_data); - g_clear_error (&error); - } - } else { + if (!check_permission) { /* Don't need polkit auth, automatic success */ - callback (self, context, sender_uid, NULL, callback_data); + callback (self, context, nm_auth_subject_get_uid (subject), NULL, callback_data); + return; } + + chain = nm_auth_chain_new_subject (subject, context, pk_auth_cb, self); + if (!chain) { + g_set_error_literal (&error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + "Unable to authenticate the request."); + callback (self, context, G_MAXULONG, error, callback_data); + g_clear_error (&error); + return; + } + + priv->pending_auths = g_slist_append (priv->pending_auths, chain); + nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL); + nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid); + nm_auth_chain_add_call (chain, check_permission, TRUE); } /**** DBus method handlers ************************************/ @@ -1184,7 +1180,17 @@ static void impl_settings_connection_get_settings (NMSettingsConnection *self, DBusGMethodInvocation *context) { - auth_start (self, context, NULL, get_settings_auth_cb, NULL); + NMAuthSubject *subject; + GError *error = NULL; + + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, context, subject, NULL, get_settings_auth_cb, NULL); + g_object_unref (subject); + } else { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } typedef struct { @@ -1307,10 +1313,12 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, gboolean save_to_disk) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMAuthSubject *subject = NULL; NMConnection *tmp = NULL; GError *error = NULL; UpdateInfo *info; const char *permission; + char *error_desc = NULL; g_assert (new_settings != NULL || save_to_disk == TRUE); @@ -1318,36 +1326,35 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, * the problem (ex a system settings plugin that can't write connections out) * instead of over D-Bus. */ - if (!check_writable (NM_CONNECTION (self), &error)) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } + if (!check_writable (NM_CONNECTION (self), &error)) + goto error; /* Check if the settings are valid first */ if (new_settings) { tmp = nm_connection_new_from_hash (new_settings, &error); if (!tmp) { g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; + goto error; } } + subject = _new_auth_subject (context, &error); + if (!subject) + goto error; + /* And that the new connection settings will be visible to the user * that's sending the update request. You can't make a connection * invisible to yourself. */ - if (!check_user_in_acl (tmp ? tmp : NM_CONNECTION (self), - context, - priv->session_monitor, - NULL, - &error)) { - dbus_g_method_return_error (context, error); - g_clear_error (&error); - g_object_unref (tmp); - return; + if (!nm_auth_uid_in_acl (tmp ? tmp : NM_CONNECTION (self), + priv->session_monitor, + nm_auth_subject_get_uid (subject), + &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + error_desc); + g_free (error_desc); + goto error; } info = g_malloc0 (sizeof (*info)); @@ -1359,7 +1366,16 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, permission = get_update_modify_permission (NM_CONNECTION (self), tmp ? tmp : NM_CONNECTION (self)); - auth_start (self, context, permission, update_auth_cb, info); + auth_start (self, context, subject, permission, update_auth_cb, info); + g_object_unref (subject); + return; + +error: + g_clear_object (&tmp); + g_clear_object (&subject); + + dbus_g_method_return_error (context, error); + g_clear_error (&error); } static void @@ -1440,6 +1456,7 @@ static void impl_settings_connection_delete (NMSettingsConnection *self, DBusGMethodInvocation *context) { + NMAuthSubject *subject; GError *error = NULL; if (!check_writable (NM_CONNECTION (self), &error)) { @@ -1448,7 +1465,14 @@ impl_settings_connection_delete (NMSettingsConnection *self, return; } - auth_start (self, context, get_modify_permission_basic (self), delete_auth_cb, NULL); + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL); + g_object_unref (subject); + } else { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } /**************************************************************/ @@ -1524,11 +1548,22 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self, const gchar *setting_name, DBusGMethodInvocation *context) { - auth_start (self, - context, - get_modify_permission_basic (self), - dbus_secrets_auth_cb, - g_strdup (setting_name)); + NMAuthSubject *subject; + GError *error = NULL; + + subject = _new_auth_subject (context, &error); + if (subject) { + auth_start (self, + context, + subject, + get_modify_permission_basic (self), + dbus_secrets_auth_cb, + g_strdup (setting_name)); + g_object_unref (subject); + } else { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } /**************************************************************/ From e672401315d6adc9fa9dde0287855d3c20e3dd35 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 11:37:18 -0500 Subject: [PATCH 14/32] settings: use NMAuthSubject in NMSettings --- src/settings/nm-settings.c | 106 ++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index e6187175e9..b5afbd71ab 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1013,6 +1013,8 @@ pk_add_cb (NMAuthChain *chain, const char *perm; gboolean save_to_disk; + g_assert (context); + priv->auths = g_slist_remove (priv->auths, chain); perm = nm_auth_chain_get_data (chain, "perm"); @@ -1092,13 +1094,15 @@ nm_settings_add_connection_dbus (NMSettings *self, { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMSettingConnection *s_con; + NMAuthSubject *subject = NULL; NMAuthChain *chain; GError *error = NULL, *tmp_error = NULL; - gulong caller_uid = G_MAXULONG; char *error_desc = NULL; - const char *auth_error_desc = NULL; const char *perm; + g_return_if_fail (connection != NULL); + g_return_if_fail (context != NULL); + /* Connection must be valid, of course */ if (!nm_connection_verify (connection, &tmp_error)) { error = g_error_new (NM_SETTINGS_ERROR, @@ -1106,9 +1110,7 @@ nm_settings_add_connection_dbus (NMSettings *self, "The connection was invalid: %s", tmp_error ? tmp_error->message : "(unknown)"); g_error_free (tmp_error); - callback (self, NULL, error, context, user_data); - g_error_free (error); - return; + goto done; } /* The kernel doesn't support Ad-Hoc WPA connections well at this time, @@ -1119,9 +1121,7 @@ nm_settings_add_connection_dbus (NMSettings *self, error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "WPA Ad-Hoc disabled due to kernel bugs"); - callback (self, NULL, error, context, user_data); - g_error_free (error); - return; + goto done; } /* Do any of the plugins support adding? */ @@ -1129,32 +1129,29 @@ nm_settings_add_connection_dbus (NMSettings *self, error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "None of the registered plugins support add."); - callback (self, NULL, error, context, user_data); - g_error_free (error); - return; + goto done; } - /* Get the caller's UID */ - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) { + subject = nm_auth_subject_new_from_context (context); + if (!subject) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, - "Unable to determine request UID."); - callback (self, NULL, error, context, user_data); - g_error_free (error); - return; + "Unable to determine UID of request."); + goto done; } /* Ensure the caller's username exists in the connection's permissions, * or that the permissions is empty (ie, visible by everyone). */ - if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) { + if (!nm_auth_uid_in_acl (connection, + priv->session_monitor, + nm_auth_subject_get_uid (subject), + &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, error_desc); g_free (error_desc); - callback (self, NULL, error, context, user_data); - g_error_free (error); - return; + goto done; } /* If the caller is the only user in the connection's permissions, then @@ -1169,23 +1166,29 @@ nm_settings_add_connection_dbus (NMSettings *self, perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; /* Validate the user request */ - chain = nm_auth_chain_new (context, pk_add_cb, self, &auth_error_desc); - if (chain) { - priv->auths = g_slist_append (priv->auths, chain); - nm_auth_chain_add_call (chain, perm, TRUE); - nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL); - nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref); - nm_auth_chain_set_data (chain, "callback", callback, NULL); - nm_auth_chain_set_data (chain, "callback-data", user_data, NULL); - nm_auth_chain_set_data_ulong (chain, "caller-uid", caller_uid); - nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL); - } else { + chain = nm_auth_chain_new_subject (subject, context, pk_add_cb, self); + if (!chain) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, - auth_error_desc); - callback (self, NULL, error, context, user_data); - g_error_free (error); + "Unable to authenticate the request."); + goto done; } + + priv->auths = g_slist_append (priv->auths, chain); + nm_auth_chain_add_call (chain, perm, TRUE); + nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL); + nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", user_data, NULL); + nm_auth_chain_set_data_ulong (chain, "caller-uid", nm_auth_subject_get_uid (subject)); + nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL); + +done: + if (error) + callback (self, NULL, error, context, user_data); + + g_clear_error (&error); + g_clear_object (&subject); } static void @@ -1294,6 +1297,8 @@ pk_hostname_cb (NMAuthChain *chain, GSList *iter; const char *hostname; + g_assert (context); + priv->auths = g_slist_remove (priv->auths, chain); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); @@ -1344,30 +1349,31 @@ impl_settings_save_hostname (NMSettings *self, NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthChain *chain; GError *error = NULL; - const char *error_desc = NULL; /* Do any of the plugins support setting the hostname? */ if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "None of the registered plugins support setting the hostname."); - } else { - chain = nm_auth_chain_new (context, pk_hostname_cb, self, &error_desc); - if (chain) { - priv->auths = g_slist_append (priv->auths, chain); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE); - nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free); - } else { - error = g_error_new_literal (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - error_desc); - } + goto done; } - if (error) { - dbus_g_method_return_error (context, error); - g_error_free (error); + chain = nm_auth_chain_new_context (context, pk_hostname_cb, self); + if (!chain) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + "Unable to authenticate the request."); + goto done; } + + priv->auths = g_slist_append (priv->auths, chain); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE); + nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free); + +done: + if (error) + dbus_g_method_return_error (context, error); + g_clear_error (&error); } static gboolean From 07b07a988ae36070632d100e049fefc1a26bd55c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 11:53:23 -0500 Subject: [PATCH 15/32] core: use NMAuthSubject in the manager for non-activation paths --- src/nm-manager.c | 170 +++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 81 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index eede07c50b..aee73ca6e3 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1769,6 +1769,8 @@ device_auth_done_cb (NMAuthChain *chain, const char *permission; NMDeviceAuthRequestFunc callback; + g_assert (context); + priv->auth_chains = g_slist_remove (priv->auth_chains, chain); permission = nm_auth_chain_get_data (chain, "requested-permission"); @@ -1818,25 +1820,24 @@ device_auth_request_cb (NMDevice *device, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; NMAuthChain *chain; - const char *error_desc = NULL; /* Validate the request */ - chain = nm_auth_chain_new (context, device_auth_done_cb, self, &error_desc); - if (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); - } else { + chain = nm_auth_chain_new_context (context, device_auth_done_cb, self); + if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); + "Unable to authenticate request."); callback (device, context, error, user_data); - g_error_free (error); + g_clear_error (&error); + return; } + + 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); } /* This should really be moved to gsystem. */ @@ -3479,6 +3480,8 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, GError *error = NULL; NMAuthCallResult result; + g_assert (context); + priv->auth_chains = g_slist_remove (priv->auth_chains, chain); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); @@ -3521,7 +3524,6 @@ impl_manager_deactivate_connection (NMManager *self, GError *error = NULL; GSList *iter; NMAuthChain *chain; - const char *error_desc = NULL; /* Find the connection by its object path */ for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { @@ -3537,25 +3539,26 @@ impl_manager_deactivate_connection (NMManager *self, error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "The connection was not active."); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; + goto done; } /* Validate the user request */ - chain = nm_auth_chain_new (context, deactivate_net_auth_done_cb, self, &error_desc); - if (chain) { - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - - nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); - } else { + chain = nm_auth_chain_new_context (context, deactivate_net_auth_done_cb, self); + if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); - dbus_g_method_return_error (context, error); - g_error_free (error); + "Unable to authenticate request."); + goto done; } + + priv->auth_chains = g_slist_append (priv->auth_chains, chain); + nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); + +done: + if (error) + dbus_g_method_return_error (context, error); + g_clear_error (&error); } /* @@ -3815,6 +3818,8 @@ enable_net_done_cb (NMAuthChain *chain, NMAuthCallResult result; gboolean enable; + g_assert (context); + priv->auth_chains = g_slist_remove (priv->auth_chains, chain); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); @@ -3851,7 +3856,6 @@ impl_manager_enable (NMManager *self, NMManagerPrivate *priv; NMAuthChain *chain; GError *error = NULL; - const char *error_desc; g_return_if_fail (NM_IS_MANAGER (self)); @@ -3861,24 +3865,25 @@ impl_manager_enable (NMManager *self, error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "Already %s", enable ? "enabled" : "disabled"); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; + goto done; } - chain = nm_auth_chain_new (context, enable_net_done_cb, self, &error_desc); - if (chain) { - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - - nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE); - } else { + chain = nm_auth_chain_new_context (context, enable_net_done_cb, self); + if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); - dbus_g_method_return_error (context, error); - g_error_free (error); + "Unable to authenticate request."); + goto done; } + + priv->auth_chains = g_slist_append (priv->auth_chains, chain); + nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE); + +done: + if (error) + dbus_g_method_return_error (context, error); + g_clear_error (&error); } /* Permissions */ @@ -3911,6 +3916,8 @@ get_permissions_done_cb (NMAuthChain *chain, GError *ret_error; GHashTable *results; + g_assert (context); + priv->auth_chains = g_slist_remove (priv->auth_chains, chain); if (error) { nm_log_dbg (LOGD_CORE, "Permissions request failed: %s", error->message); @@ -3948,31 +3955,30 @@ impl_manager_get_permissions (NMManager *self, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; - const char *error_desc = NULL; - GError *error; + GError *error = NULL; - chain = nm_auth_chain_new (context, get_permissions_done_cb, self, &error_desc); - if (chain) { - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE); - } else { + chain = nm_auth_chain_new_context (context, get_permissions_done_cb, self); + if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); + "Unable to authenticate request."); dbus_g_method_return_error (context, error); - g_error_free (error); + g_clear_error (&error); + return; } + + priv->auth_chains = g_slist_append (priv->auth_chains, chain); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE); } static gboolean @@ -4073,22 +4079,21 @@ impl_manager_check_connectivity (NMManager *manager, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMAuthChain *chain; - const char *error_desc = NULL; - GError *error; + GError *error = NULL; - /* Validate the user request */ - chain = nm_auth_chain_new (context, check_connectivity_auth_done_cb, manager, &error_desc); - if (chain) { - priv->auth_chains = g_slist_append (priv->auth_chains, chain); - - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); - } else { + /* Validate the request */ + chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, manager); + if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); + "Unable to authenticate request."); dbus_g_method_return_error (context, error); - g_error_free (error); + g_clear_error (&error); + return; } + + priv->auth_chains = g_slist_append (priv->auth_chains, chain); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } void @@ -4344,9 +4349,9 @@ prop_filter (DBusConnection *connection, const char *propiface = NULL; const char *propname = NULL; const char *glib_propname = NULL, *permission = NULL; - gulong caller_uid = G_MAXULONG; DBusMessage *reply = NULL; gboolean set_enabled = FALSE; + NMAuthSubject *subject = NULL; NMAuthChain *chain; GObject *obj; @@ -4406,20 +4411,21 @@ prop_filter (DBusConnection *connection, goto out; } - if (!nm_dbus_manager_get_caller_info_from_message (priv->dbus_mgr, - connection, - message, - NULL, - &caller_uid, - NULL)) { + subject = nm_auth_subject_new_from_message (connection, message);\ + if (!subject) { reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, "Could not determine request UID."); goto out; } /* Validate the user request */ - chain = nm_auth_chain_new_raw_message (message, caller_uid, prop_set_auth_done_cb, self); - g_assert (chain); + chain = nm_auth_chain_new_subject (subject, NULL, prop_set_auth_done_cb, self); + if (!chain) { + reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, + "Could not authenticate request."); + goto out; + } + priv->auth_chains = g_slist_append (priv->auth_chains, chain); nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free); nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free); @@ -4434,6 +4440,8 @@ out: dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); } + g_clear_object (&subject); + return DBUS_HANDLER_RESULT_HANDLED; } From 1126e225727a2d11da9e4bbc66dbd0fb5afea753 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 4 Sep 2013 13:15:34 -0500 Subject: [PATCH 16/32] core: remove unused auth chain creation functions No longer used by anything. --- src/nm-manager-auth.c | 68 +++++++++---------------------------------- src/nm-manager-auth.h | 10 ------- 2 files changed, 13 insertions(+), 65 deletions(-) diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c index 8d4d0d7cc0..57f5c72569 100644 --- a/src/nm-manager-auth.c +++ b/src/nm-manager-auth.c @@ -107,17 +107,16 @@ pk_authority_get (GError **error) #endif static NMAuthChain * -_auth_chain_new (DBusGMethodInvocation *context, - DBusMessage *message, +_auth_chain_new (NMAuthSubject *subject, const char *dbus_sender, gulong user_uid, - NMAuthSubject *subject, + DBusGMethodInvocation *context, NMAuthChainResultFunc done_func, gpointer user_data) { NMAuthChain *self; - g_return_val_if_fail (message || dbus_sender, NULL); + g_return_val_if_fail (subject || user_uid == 0 || dbus_sender, NULL); self = g_malloc0 (sizeof (NMAuthChain)); self->refcount = 1; @@ -132,68 +131,27 @@ _auth_chain_new (DBusGMethodInvocation *context, if (subject) { self->user_uid = nm_auth_subject_get_uid (subject); self->subject = g_object_ref (subject); - return self; - } - - if (message) - self->owner = g_strdup (dbus_message_get_sender (message)); - else if (dbus_sender) + } else { + self->user_uid = user_uid; self->owner = g_strdup (dbus_sender); - - self->user_uid = user_uid; - if (user_uid > 0 && !self->owner) { - /* Need an owner */ - g_warn_if_fail (self->owner); - nm_auth_chain_unref (self); - return NULL; + if (user_uid > 0 && !self->owner) { + /* Need an owner */ + g_warn_if_fail (self->owner); + nm_auth_chain_unref (self); + self = NULL; + } } return self; } -NMAuthChain * -nm_auth_chain_new (DBusGMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data, - const char **out_error_desc) -{ - gulong sender_uid = G_MAXULONG; - char *sender = NULL; - NMAuthChain *chain = NULL; - - g_return_val_if_fail (context != NULL, NULL); - - if (nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), - context, - &sender, - &sender_uid, - NULL)) { - chain = _auth_chain_new (context, NULL, sender, sender_uid, NULL, done_func, user_data); - } - - if (!chain && out_error_desc) - *out_error_desc = "Unable to determine request UID and sender."; - - g_free (sender); - return chain; -} - -NMAuthChain * -nm_auth_chain_new_raw_message (DBusMessage *message, - gulong user_uid, - NMAuthChainResultFunc done_func, - gpointer user_data) -{ - return _auth_chain_new (NULL, message, NULL, user_uid, NULL, done_func, user_data); -} - NMAuthChain * nm_auth_chain_new_dbus_sender (const char *dbus_sender, gulong user_uid, NMAuthChainResultFunc done_func, gpointer user_data) { - return _auth_chain_new (NULL, NULL, dbus_sender, user_uid, NULL, done_func, user_data); + return _auth_chain_new (NULL, dbus_sender, user_uid, NULL, done_func, user_data); } /* Creates the NMAuthSubject automatically */ @@ -229,7 +187,7 @@ nm_auth_chain_new_subject (NMAuthSubject *subject, NMAuthChain *chain; g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - chain = _auth_chain_new (context, NULL, NULL, G_MAXULONG, subject, done_func, user_data); + chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data); /* Chains creation from a valid NMAuthSubject cannot fail since the * subject already has all the necessary auth info. diff --git a/src/nm-manager-auth.h b/src/nm-manager-auth.h index 46aa2b9fb1..43dd639873 100644 --- a/src/nm-manager-auth.h +++ b/src/nm-manager-auth.h @@ -56,16 +56,6 @@ typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, DBusGMethodInvocation *context, gpointer user_data); -NMAuthChain *nm_auth_chain_new (DBusGMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data, - const char **out_error_desc); - -NMAuthChain *nm_auth_chain_new_raw_message (DBusMessage *message, - gulong user_uid, - NMAuthChainResultFunc done_func, - gpointer user_data); - NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender, gulong user_uid, NMAuthChainResultFunc done_func, From bcef4231743ecddb27943fb02a4095faabdbb73e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 12:42:16 -0500 Subject: [PATCH 17/32] core: use NMAuthSubject in D-Bus triggered activation paths --- src/nm-manager.c | 162 ++++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index aee73ca6e3..3b0e4dcc04 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -192,8 +192,7 @@ struct PendingActivation { PendingActivationFunc callback; gpointer user_data; - char *dbus_sender; - gulong sender_uid; + NMAuthSubject *subject; NMAuthChain *chain; const char *wifi_shared_permission; @@ -851,19 +850,17 @@ nm_manager_get_state (NMManager *manager) static PendingActivation * pending_activation_new (NMManager *manager, - char *dbus_sender, - gulong sender_uid, + NMAuthSubject *subject, NMDevice *device, NMConnection *connection, const char *specific_object_path, PendingActivationFunc callback, - gpointer user_data, - GError **error) + gpointer user_data) { PendingActivation *pending; g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (dbus_sender != NULL, NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (callback != NULL, NULL); @@ -880,8 +877,7 @@ pending_activation_new (NMManager *manager, pending->callback = callback; pending->user_data = user_data; - pending->dbus_sender = dbus_sender; - pending->sender_uid = sender_uid; + pending->subject = g_object_ref (subject); return pending; } @@ -919,37 +915,38 @@ pending_auth_done (NMAuthChain *chain, g_clear_error (&tmp_error); } -static void -pending_activation_check_authorized (PendingActivation *pending) +static gboolean +pending_activation_check_authorized (PendingActivation *pending, GError **error) { - GError *error; const char *wifi_permission = NULL; - g_return_if_fail (pending != NULL); + g_return_val_if_fail (pending != NULL, FALSE); /* First check if the user is allowed to use networking at all, giving * the user a chance to authenticate to gain the permission. */ - pending->chain = nm_auth_chain_new_dbus_sender (pending->dbus_sender, - pending->sender_uid, - pending_auth_done, - pending); - if (pending->chain) { - nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); - - /* Shared wifi connections require special permissions too */ - wifi_permission = nm_utils_get_shared_wifi_permission (pending->connection); - if (wifi_permission) { - pending->wifi_shared_permission = wifi_permission; - nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE); - } - } else { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Failed to authorize"); - pending->callback (pending, pending->user_data, error); - g_error_free (error); + pending->chain = nm_auth_chain_new_subject (pending->subject, + NULL, + pending_auth_done, + pending); + if (!pending->chain) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Failed to authorize"); + return FALSE; } + + nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); + + /* Shared wifi connections require special permissions too */ + wifi_permission = nm_utils_get_shared_wifi_permission (pending->connection); + if (wifi_permission) { + pending->wifi_shared_permission = wifi_permission; + nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE); + } + + return TRUE; } static void @@ -958,9 +955,9 @@ pending_activation_destroy (PendingActivation *pending) g_return_if_fail (pending != NULL); g_free (pending->specific_object_path); - g_free (pending->dbus_sender); g_clear_object (&pending->device); g_clear_object (&pending->connection); + g_clear_object (&pending->subject); if (pending->chain) nm_auth_chain_unref (pending->chain); @@ -3129,7 +3126,7 @@ pending_activate (PendingActivation *pending, NM_CONNECTION (new_connection) : pending->connection, pending->specific_object_path, pending->device, - pending->dbus_sender, + nm_auth_subject_get_dbus_sender (pending->subject), &local); if (!ac) { nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", @@ -3141,28 +3138,29 @@ pending_activate (PendingActivation *pending, return ac; } -static gboolean +static NMAuthSubject * validate_activation_request (NMManager *self, DBusGMethodInvocation *context, NMConnection *connection, const char *device_path, NMDevice **out_device, gboolean *out_vpn, - gulong *out_sender_uid, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device = NULL; gboolean vpn = FALSE; + NMAuthSubject *subject = NULL; g_assert (connection); - /* Get caller's UID */ - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, out_sender_uid, NULL)) { + /* Validate the caller */ + subject = nm_auth_subject_new_from_context (context); + if (!subject) { g_set_error_literal (error, - NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, "Failed to get request UID."); - return FALSE; + return NULL; } /* Check whether it's a VPN or not */ @@ -3188,14 +3186,15 @@ validate_activation_request (NMManager *self, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "Device not found"); - return FALSE; + g_object_unref (subject); + return NULL; } if (out_device) *out_device = device; if (out_vpn) *out_vpn = vpn; - return TRUE; + return subject; } /***********************************************************************/ @@ -3232,10 +3231,10 @@ impl_manager_activate_connection (NMManager *self, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); PendingActivation *pending; + NMAuthSubject *subject = NULL; NMConnection *connection; NMDevice *device = NULL; GError *error = NULL; - gulong sender_uid = G_MAXULONG; connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); if (!connection) { @@ -3245,35 +3244,39 @@ impl_manager_activate_connection (NMManager *self, goto error; } - if (!validate_activation_request (self, - context, - connection, - device_path, - &device, - NULL, - &sender_uid, - &error)) + subject = validate_activation_request (self, + context, + connection, + device_path, + &device, + NULL, + &error); + if (!subject) goto error; /* Need to check the caller's permissions and stuff before we can * activate the connection. */ pending = pending_activation_new (self, - dbus_g_method_get_sender (context), - sender_uid, + subject, device, connection, specific_object_path, activation_auth_done, - context, - &error); - if (pending) { - /* Success */ - pending_activation_check_authorized (pending); - return; + context); + g_assert (pending); + + if (!pending_activation_check_authorized (pending, &error)) { + pending_activation_destroy (pending); + goto error; } + /* success */ + g_object_unref (subject); + return; + error: + g_clear_object (&subject); g_assert (error); dbus_g_method_return_error (context, error); g_error_free (error); @@ -3344,10 +3347,10 @@ impl_manager_add_and_activate_connection (NMManager *self, NMConnection *connection = NULL; GSList *all_connections = NULL; PendingActivation *pending; + NMAuthSubject *subject = NULL; GError *error = NULL; NMDevice *device = NULL; gboolean vpn = FALSE; - gulong sender_uid = G_MAXULONG; if (!settings || !g_hash_table_size (settings)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, @@ -3359,14 +3362,14 @@ impl_manager_add_and_activate_connection (NMManager *self, connection = nm_connection_new (); nm_connection_replace_settings (connection, settings, NULL); - if (!validate_activation_request (self, - context, - connection, - device_path, - &device, - &vpn, - &sender_uid, - &error)) + subject = validate_activation_request (self, + context, + connection, + device_path, + &device, + &vpn, + &error); + if (!subject) goto error; all_connections = nm_settings_get_connections (priv->settings); @@ -3401,24 +3404,27 @@ impl_manager_add_and_activate_connection (NMManager *self, * activate the connection. */ pending = pending_activation_new (self, - dbus_g_method_get_sender (context), - sender_uid, + subject, device, connection, specific_object_path, add_and_activate_auth_done, - context, - &error); - if (pending) { - /* Success! */ - g_object_unref (connection); - pending_activation_check_authorized (pending); - return; + context); + g_assert (pending); + + if (!pending_activation_check_authorized (pending, &error)) { + pending_activation_destroy (pending); + goto error; } + g_object_unref (connection); + g_object_unref (subject); + return; /* Success */ + error: g_clear_object (&connection); g_slist_free (all_connections); + g_object_unref (&subject); g_assert (error); dbus_g_method_return_error (context, error); From 0e595abcf3fe783c2d3ac160e7d639c2fcfcca4d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 13:11:47 -0500 Subject: [PATCH 18/32] core: pass NMAuthSubject around activation paths instead of uid + dbus sender --- src/nm-activation-request.c | 44 ++++-------------- src/nm-activation-request.h | 8 +--- src/nm-active-connection.c | 61 +++++++++++++++---------- src/nm-active-connection.h | 6 ++- src/nm-manager.c | 71 +++++++++++------------------ src/nm-manager.h | 3 +- src/nm-policy.c | 7 ++- src/vpn-manager/nm-vpn-connection.c | 6 +-- src/vpn-manager/nm-vpn-connection.h | 4 +- 9 files changed, 88 insertions(+), 122 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 6c331777f3..d0b1934b29 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -52,7 +52,6 @@ typedef struct { typedef struct { guint device_state_id; - char *dbus_sender; GSList *secrets_calls; gboolean shared; GSList *share_rules; @@ -68,14 +67,6 @@ nm_act_request_get_connection (NMActRequest *req) return nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req)); } -const char * -nm_act_request_get_dbus_sender (NMActRequest *req) -{ - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL); - - return NM_ACT_REQUEST_GET_PRIVATE (req)->dbus_sender; -} - /*******************************************************************/ typedef struct { @@ -351,11 +342,7 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) * @connection: the connection to activate @device with * @specific_object: the object path of the specific object (ie, WiFi access point, * etc) that will be used to activate @connection and @device - * @user_requested: pass %TRUE if the activation was requested via D-Bus, - * otherwise %FALSE if requested internally by NM (ie, autoconnect) - * @user_uid: if @user_requested is %TRUE, the Unix UID of the user that requested - * @dbus_sender: if @user_requested is %TRUE, the D-BUS sender that requested - * the activation + * @subject: the #NMAuthSubject representing the requestor of the activation * @device: the device/interface to configure according to @connection * @master: if the activation depends on another device (ie, bond or bridge * or team master to which this device will be enslaved) pass the #NMDevice @@ -368,29 +355,21 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) NMActRequest * nm_act_request_new (NMConnection *connection, const char *specific_object, - gboolean user_requested, - gulong user_uid, - const char *dbus_sender, + NMAuthSubject *subject, NMDevice *device, NMDevice *master) { - GObject *object; - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - object = g_object_new (NM_TYPE_ACT_REQUEST, - NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, - NM_ACTIVE_CONNECTION_INT_DEVICE, device, - NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, - NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested, - NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid, - NM_ACTIVE_CONNECTION_INT_MASTER, master, - NULL); - if (object) - NM_ACT_REQUEST_GET_PRIVATE (object)->dbus_sender = g_strdup (dbus_sender); - - return (NMActRequest *) object; + return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST, + NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, + NM_ACTIVE_CONNECTION_INT_DEVICE, device, + NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, + NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, + NM_ACTIVE_CONNECTION_INT_MASTER, master, + NULL); } static void @@ -445,9 +424,6 @@ dispose (GObject *object) g_slist_free (priv->secrets_calls); priv->secrets_calls = NULL; - g_free (priv->dbus_sender); - priv->dbus_sender = NULL; - G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); } diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index cd645ce9c2..2d5d864b2c 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -48,18 +48,12 @@ GType nm_act_request_get_type (void); NMActRequest *nm_act_request_new (NMConnection *connection, const char *specific_object, - gboolean user_requested, - gulong user_uid, - const char *dbus_sender, + NMAuthSubject *subject, NMDevice *device, NMDevice *master); NMConnection *nm_act_request_get_connection (NMActRequest *req); -gulong nm_act_request_get_user_uid (NMActRequest *req); - -const char *nm_act_request_get_dbus_sender (NMActRequest *req); - gboolean nm_act_request_get_shared (NMActRequest *req); void nm_act_request_set_shared (NMActRequest *req, gboolean shared); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index dadb52c5f4..08ac050b2d 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -48,8 +48,7 @@ typedef struct { NMActiveConnectionState state; gboolean vpn; - gboolean user_requested; - gulong user_uid; + NMAuthSubject *subject; NMDevice *master; } NMActiveConnectionPrivate; @@ -67,8 +66,7 @@ enum { PROP_INT_CONNECTION, PROP_INT_DEVICE, - PROP_INT_USER_REQUESTED, - PROP_INT_USER_UID, + PROP_INT_SUBJECT, PROP_INT_MASTER, LAST_PROP @@ -216,20 +214,31 @@ nm_active_connection_export (NMActiveConnection *self) nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); } +NMAuthSubject * +nm_active_connection_get_subject (NMActiveConnection *self) +{ + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); + + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject; +} + gboolean nm_active_connection_get_user_requested (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_requested; + return !nm_auth_subject_get_internal (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject); } gulong nm_active_connection_get_user_uid (NMActiveConnection *self) { - g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG); + NMActiveConnectionPrivate *priv; - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_uid; + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG); + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + return nm_auth_subject_get_uid (priv->subject); } NMDevice * @@ -255,6 +264,13 @@ nm_active_connection_init (NMActiveConnection *self) { } +static void +constructed (GObject *object) +{ + G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); + g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject); +} + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -273,11 +289,8 @@ set_property (GObject *object, guint prop_id, if (priv->device) g_warn_if_fail (priv->device != priv->master); break; - case PROP_INT_USER_REQUESTED: - priv->user_requested = g_value_get_boolean (value); - break; - case PROP_INT_USER_UID: - priv->user_uid = g_value_get_ulong (value); + case PROP_INT_SUBJECT: + priv->subject = g_value_dup_object (value); break; case PROP_INT_MASTER: g_warn_if_fail (priv->master == NULL); @@ -346,6 +359,9 @@ get_property (GObject *object, guint prop_id, case PROP_MASTER: g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/"); break; + case PROP_INT_SUBJECT: + g_value_set_object (value, priv->subject); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -365,6 +381,7 @@ dispose (GObject *object) g_clear_object (&priv->connection); g_clear_object (&priv->device); g_clear_object (&priv->master); + g_clear_object (&priv->subject); G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object); } @@ -379,6 +396,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) /* virtual methods */ object_class->get_property = get_property; object_class->set_property = set_property; + object_class->constructed = constructed; object_class->dispose = dispose; /* D-Bus exported properties */ @@ -462,19 +480,12 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) NM_TYPE_DEVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_INT_USER_REQUESTED, - g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, - "User requested", - "User requested", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_INT_USER_UID, - g_param_spec_ulong (NM_ACTIVE_CONNECTION_INT_USER_UID, - "User UID", - "User UID (if user requested)", - 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_INT_SUBJECT, + g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, + "Subject", + "Subject", + NM_TYPE_AUTH_SUBJECT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_INT_MASTER, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 96bbfedd75..3d3585e4fd 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -24,6 +24,7 @@ #include #include "nm-types.h" #include "nm-connection.h" +#include "nm-auth-subject.h" #define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ()) #define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection)) @@ -46,8 +47,7 @@ /* Internal non-exported construct-time properties */ #define NM_ACTIVE_CONNECTION_INT_CONNECTION "int-connection" #define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" -#define NM_ACTIVE_CONNECTION_INT_USER_REQUESTED "int-user-requested" -#define NM_ACTIVE_CONNECTION_INT_USER_UID "int-user-uid" +#define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" @@ -91,6 +91,8 @@ void nm_active_connection_set_state (NMActiveConnection *self, NMDevice * nm_active_connection_get_device (NMActiveConnection *self); +NMAuthSubject *nm_active_connection_get_subject (NMActiveConnection *self); + gboolean nm_active_connection_get_user_requested (NMActiveConnection *self); gulong nm_active_connection_get_user_uid (NMActiveConnection *self); diff --git a/src/nm-manager.c b/src/nm-manager.c index 3b0e4dcc04..dd732f8ca1 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -160,9 +160,7 @@ static NMActiveConnection *internal_activate_device (NMManager *manager, NMDevice *device, NMConnection *connection, const char *specific_object, - gboolean user_requested, - gulong sender_uid, - const char *dbus_sender, + NMAuthSubject *subject, gboolean assumed, NMActiveConnection *master, GError **error); @@ -2049,12 +2047,14 @@ add_device (NMManager *self, NMDevice *device) /* If the device has a connection it can assume, do that now */ if (connection && nm_device_can_activate (device, connection)) { NMActiveConnection *ac; + NMAuthSubject *subject; GError *error = NULL; nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection", nm_device_get_iface (device)); - ac = internal_activate_device (self, device, connection, NULL, FALSE, 0, NULL, TRUE, NULL, &error); + subject = nm_auth_subject_new_internal (); + ac = internal_activate_device (self, device, connection, NULL, subject, TRUE, NULL, &error); if (ac) active_connection_add (self, ac); else { @@ -2064,6 +2064,7 @@ add_device (NMManager *self, NMDevice *device) error && error->message ? error->message : "(unknown)"); g_error_free (error); } + g_object_unref (subject); } } @@ -2526,9 +2527,7 @@ internal_activate_device (NMManager *manager, NMDevice *device, NMConnection *connection, const char *specific_object, - gboolean user_requested, - gulong sender_uid, - const char *dbus_sender, + NMAuthSubject *subject, gboolean assumed, NMActiveConnection *master, GError **error) @@ -2539,6 +2538,7 @@ internal_activate_device (NMManager *manager, g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); /* Ensure the requested connection is compatible with the device */ if (!nm_device_check_connection_compatible (device, connection, error)) @@ -2558,9 +2558,7 @@ internal_activate_device (NMManager *manager, req = nm_act_request_new (connection, specific_object, - user_requested, - sender_uid, - dbus_sender, + subject, device, master_device); g_assert (req); @@ -2681,9 +2679,7 @@ is_compatible_with_slave (NMConnection *master, NMConnection *slave) * ensure_master_active_connection: * * @self: the #NMManager - * @dbus_sender: if the request was initiated by a user via D-Bus, the - * dbus sender name of the client that requested the activation; for auto - * activated connections use %NULL + * @subject: the #NMAuthSubject representing the requestor of this activation * @connection: the connection that should depend on @master_connection * @device: the #NMDevice, if any, which will activate @connection * @master_connection: the master connection @@ -2698,7 +2694,7 @@ is_compatible_with_slave (NMConnection *master, NMConnection *slave) */ static NMActiveConnection * ensure_master_active_connection (NMManager *self, - const char *dbus_sender, + NMAuthSubject *subject, NMConnection *connection, NMDevice *device, NMConnection *master_connection, @@ -2754,7 +2750,7 @@ ensure_master_active_connection (NMManager *self, candidate, NULL, master_device, - dbus_sender, + subject, error); if (!master_ac) g_prefix_error (error, "%s", "Master device activation failed: "); @@ -2802,7 +2798,7 @@ ensure_master_active_connection (NMManager *self, master_connection, NULL, candidate, - dbus_sender, + subject, error); if (!master_ac) g_prefix_error (error, "%s", "Master device activation failed: "); @@ -2817,7 +2813,7 @@ ensure_master_active_connection (NMManager *self, master_connection, NULL, NULL, - dbus_sender, + subject, error); if (!master_ac) g_prefix_error (error, "%s", "Master device activation failed: "); @@ -2839,8 +2835,7 @@ static NMActiveConnection * activate_vpn_connection (NMManager *self, NMConnection *connection, const char *specific_object, - gboolean user_requested, - gulong sender_uid, + NMAuthSubject *subject, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -2885,8 +2880,7 @@ activate_vpn_connection (NMManager *self, vpn = nm_vpn_connection_new (connection, device, nm_active_connection_get_path (parent), - user_requested, - sender_uid); + subject); g_assert (vpn); success = nm_vpn_manager_activate_connection (priv->vpn_manager, vpn, error); if (!success) @@ -2900,48 +2894,37 @@ nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, NMDevice *device, - const char *dbus_sender, + NMAuthSubject *subject, GError **error) { NMManagerPrivate *priv; - gulong sender_uid = G_MAXULONG; char *iface; NMDevice *master_device = NULL; NMConnection *master_connection = NULL; NMActiveConnection *master_ac = NULL, *ac = NULL; gboolean matched; + gboolean user_requested; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (error != NULL, NULL); g_return_val_if_fail (*error == NULL, NULL); priv = NM_MANAGER_GET_PRIVATE (manager); - /* Get the UID of the user that originated the request, if any */ - if (dbus_sender) { - if (!nm_dbus_manager_get_unix_user (priv->dbus_mgr, dbus_sender, &sender_uid)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, - "Failed to get unix user for dbus sender"); - return NULL; - } - } else { - /* No sender means an internal/automatic activation request */ - sender_uid = 0; - } - /* VPN ? */ if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { ac = activate_vpn_connection (manager, connection, specific_object, - !!dbus_sender, - sender_uid, + subject, error); goto activated; } + user_requested = !nm_auth_subject_get_internal (subject); + /* Device-based connection */ if (device) { /* If it's a virtual interface make sure the device given by the @@ -2990,7 +2973,7 @@ nm_manager_activate_connection (NMManager *manager, * at this time (the device was manually disconnected/deleted before) */ if (!nm_manager_can_device_auto_connect (manager, iface)) { - if (dbus_sender) { + if (user_requested) { /* Manual activation - allow device auto-activation again */ nm_manager_prevent_device_auto_connect (manager, iface, FALSE); } else { @@ -3034,7 +3017,7 @@ nm_manager_activate_connection (NMManager *manager, /* If this is an autoconnect request, but the device isn't allowing autoconnect * right now, we reject it. */ - if (!dbus_sender && !nm_device_autoconnect_allowed (device)) { + if (!user_requested && !nm_device_autoconnect_allowed (device)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, "%s does not allow automatic connections at this time", nm_device_get_iface (device)); @@ -3073,7 +3056,7 @@ nm_manager_activate_connection (NMManager *manager, } master_ac = ensure_master_active_connection (manager, - dbus_sender, + subject, connection, device, master_connection, @@ -3094,9 +3077,7 @@ nm_manager_activate_connection (NMManager *manager, device, connection, specific_object, - dbus_sender ? TRUE : FALSE, - dbus_sender ? sender_uid : 0, - dbus_sender, + subject, FALSE, master_ac, error); @@ -3126,7 +3107,7 @@ pending_activate (PendingActivation *pending, NM_CONNECTION (new_connection) : pending->connection, pending->specific_object_path, pending->device, - nm_auth_subject_get_dbus_sender (pending->subject), + pending->subject, &local); if (!ac) { nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", diff --git a/src/nm-manager.h b/src/nm-manager.h index 6baf6f4d90..5f848688d9 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -27,6 +27,7 @@ #include #include "nm-device.h" #include "nm-settings.h" +#include "nm-auth-subject.h" #define NM_TYPE_MANAGER (nm_manager_get_type ()) #define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager)) @@ -117,7 +118,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager, NMConnection *connection, const char *specific_object, NMDevice *device, - const char *dbus_sender, /* NULL if automatic */ + NMAuthSubject *subject, GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, diff --git a/src/nm-policy.c b/src/nm-policy.c index 9f1db55cfb..9f480032e2 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1034,14 +1034,16 @@ auto_activate_device (gpointer user_data) best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object); if (best_connection) { GError *error = NULL; + NMAuthSubject *subject; nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.", nm_connection_get_id (best_connection)); + subject = nm_auth_subject_new_internal (); if (!nm_manager_activate_connection (priv->manager, best_connection, specific_object, data->device, - NULL, + subject, &error)) { nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s", nm_connection_get_id (best_connection), @@ -1049,6 +1051,7 @@ auto_activate_device (gpointer user_data) error ? error->message : "(none)"); g_error_free (error); } + g_object_unref (subject); } g_slist_free (connections); @@ -1358,7 +1361,7 @@ activate_secondary_connections (NMPolicy *policy, NM_CONNECTION (settings_con), nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)), device, - nm_act_request_get_dbus_sender (req), + nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), &error); if (ac) { secondary_ac_list = g_slist_append (secondary_ac_list, diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index a3a30e9ae8..129123acdb 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -400,8 +400,7 @@ NMVPNConnection * nm_vpn_connection_new (NMConnection *connection, NMDevice *parent_device, const char *specific_object, - gboolean user_requested, - gulong user_uid) + NMAuthSubject *subject) { g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); @@ -410,8 +409,7 @@ nm_vpn_connection_new (NMConnection *connection, NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, - NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested, - NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid, + NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, NM_ACTIVE_CONNECTION_VPN, TRUE, NULL); } diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index bf5433456d..d0554faee2 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -26,6 +26,7 @@ #include #include "NetworkManagerVPN.h" #include "nm-device.h" +#include "nm-auth-subject.h" #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) #define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnection)) @@ -67,8 +68,7 @@ GType nm_vpn_connection_get_type (void); NMVPNConnection * nm_vpn_connection_new (NMConnection *connection, NMDevice *parent_device, const char *specific_object, - gboolean user_requested, - gulong user_uid); + NMAuthSubject *subject); void nm_vpn_connection_activate (NMVPNConnection *connection); NMConnection * nm_vpn_connection_get_connection (NMVPNConnection *connection); From 4b8cd481dc0f0d5f8da6b71e3097689316f3e129 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 17 Sep 2012 10:53:41 -0500 Subject: [PATCH 19/32] core: add authorization code to NMActiveConnection In preparation for killing PendingActivation; copy and rework the PendingActivation authorization code for NMActiveConnection. --- src/nm-active-connection.c | 116 +++++++++++++++++++++++++++++++++++++ src/nm-active-connection.h | 14 ++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 08ac050b2d..e4bdff0474 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -27,6 +27,8 @@ #include "nm-dbus-manager.h" #include "nm-device.h" #include "nm-settings-connection.h" +#include "nm-manager-auth.h" +#include "NetworkManagerUtils.h" #include "nm-active-connection-glue.h" @@ -50,6 +52,12 @@ typedef struct { NMAuthSubject *subject; NMDevice *master; + + NMAuthChain *chain; + const char *wifi_shared_permission; + NMActiveConnectionAuthResultFunc result_func; + gpointer user_data1; + gpointer user_data2; } NMActiveConnectionPrivate; enum { @@ -259,6 +267,109 @@ nm_active_connection_get_master (NMActiveConnection *self) /****************************************************************/ +static void +auth_done (NMAuthChain *chain, + GError *error, + DBusGMethodInvocation *unused, + gpointer user_data) +{ + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + NMAuthCallResult result; + + g_assert (priv->chain == chain); + g_assert (priv->result_func != NULL); + + /* Must stay alive over the callback */ + g_object_ref (self); + + if (error) { + priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2); + goto done; + } + + /* Caller has had a chance to obtain authorization, so we only need to + * check for 'yes' here. + */ + result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); + if (result != NM_AUTH_CALL_RESULT_YES) { + priv->result_func (self, + FALSE, + "Not authorized to control networking.", + priv->user_data1, + priv->user_data2); + goto done; + } + + if (priv->wifi_shared_permission) { + result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission); + if (result != NM_AUTH_CALL_RESULT_YES) { + priv->result_func (self, + FALSE, + "Not authorized to share connections via wifi.", + priv->user_data1, + priv->user_data2); + goto done; + } + } + + /* Otherwise authorized and available to activate */ + priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2); + +done: + nm_auth_chain_unref (chain); + priv->chain = NULL; + priv->result_func = NULL; + priv->user_data1 = NULL; + priv->user_data2 = NULL; + + g_object_unref (self); +} + +/** + * nm_active_connection_authorize: + * @self: the #NMActiveConnection + * @result_func: function to be called on success or error + * @user_data1: pointer passed to @result_func + * @user_data2: additional pointer passed to @result_func + * + * Checks whether the subject that initiated the active connection (read from + * the #NMActiveConnection::subject property) is authorized to complete this + * activation request. + */ +void +nm_active_connection_authorize (NMActiveConnection *self, + NMActiveConnectionAuthResultFunc result_func, + gpointer user_data1, + gpointer user_data2) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + const char *wifi_permission = NULL; + + g_return_if_fail (result_func != NULL); + g_return_if_fail (priv->chain == NULL); + + priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self); + g_assert (priv->chain); + + /* Check that the subject is allowed to use networking at all */ + nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); + + /* Shared wifi connections require special permissions too */ + wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection); + if (wifi_permission) { + priv->wifi_shared_permission = wifi_permission; + nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE); + } + + /* Wait for authorization */ + priv->result_func = result_func; + priv->user_data1 = user_data1; + priv->user_data2 = user_data2; +} + +/****************************************************************/ + static void nm_active_connection_init (NMActiveConnection *self) { @@ -373,6 +484,11 @@ dispose (GObject *object) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); + if (priv->chain) { + nm_auth_chain_unref (priv->chain); + priv->chain = NULL; + } + g_free (priv->path); priv->path = NULL; g_free (priv->specific_object); diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 3d3585e4fd..e4c097e6f4 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -50,21 +50,31 @@ #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" - typedef struct { GObject parent; } NMActiveConnection; typedef struct { GObjectClass parent; - } NMActiveConnectionClass; GType nm_active_connection_get_type (void); +typedef void (*NMActiveConnectionAuthResultFunc) (NMActiveConnection *self, + gboolean success, + const char *error_desc, + gpointer user_data1, + gpointer user_data2); + +void nm_active_connection_authorize (NMActiveConnection *self, + NMActiveConnectionAuthResultFunc result_func, + gpointer user_data1, + gpointer user_data2); + void nm_active_connection_export (NMActiveConnection *self); NMConnection *nm_active_connection_get_connection (NMActiveConnection *self); + const char * nm_active_connection_get_name (NMActiveConnection *self); const char * nm_active_connection_get_path (NMActiveConnection *self); From 4237df8c216b1a431652799a70819630044690fc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jul 2013 16:26:09 -0500 Subject: [PATCH 20/32] core: allow active connection 'master' to be set after object creation We want to create the object earlier now, and figuring out the master is a lot of code that we don't want to run before creating the object. The master still must be set before exporting the object over D-Bus though, as before. --- src/nm-activation-request.c | 7 +------ src/nm-activation-request.h | 3 +-- src/nm-active-connection.c | 33 ++++++++++++++++++++++++++++----- src/nm-active-connection.h | 2 ++ src/nm-manager.c | 4 ++-- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index d0b1934b29..ce9ee7da82 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -344,9 +344,6 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation * @device: the device/interface to configure according to @connection - * @master: if the activation depends on another device (ie, bond or bridge - * or team master to which this device will be enslaved) pass the #NMDevice - * that this activation request be enslaved to * * Begins activation of @device using the given @connection and other details. * @@ -356,8 +353,7 @@ NMActRequest * nm_act_request_new (NMConnection *connection, const char *specific_object, NMAuthSubject *subject, - NMDevice *device, - NMDevice *master) + NMDevice *device) { g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); @@ -368,7 +364,6 @@ nm_act_request_new (NMConnection *connection, NM_ACTIVE_CONNECTION_INT_DEVICE, device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, - NM_ACTIVE_CONNECTION_INT_MASTER, master, NULL); } diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 2d5d864b2c..87ea41f916 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -49,8 +49,7 @@ GType nm_act_request_get_type (void); NMActRequest *nm_act_request_new (NMConnection *connection, const char *specific_object, NMAuthSubject *subject, - NMDevice *device, - NMDevice *master); + NMDevice *device); NMConnection *nm_act_request_get_connection (NMActRequest *req); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index e4bdff0474..72ee79823d 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -265,6 +265,32 @@ nm_active_connection_get_master (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master; } +/** + * nm_active_connection_set_master: + * @self: the #NMActiveConnection + * @master: if the activation depends on another device (ie, bond or bridge + * master to which this device will be enslaved) pass the #NMDevice that this + * activation request be enslaved to + * + * Sets the master device of the active connection. + */ +void +nm_active_connection_set_master (NMActiveConnection *self, NMDevice *master) +{ + NMActiveConnectionPrivate *priv; + + g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + /* Master is write-once, and must be set before exporting the object */ + g_return_if_fail (priv->master == NULL); + g_return_if_fail (priv->path == NULL); + g_return_if_fail (master != priv->device); + + priv->master = g_object_ref (master); +} + /****************************************************************/ static void @@ -404,10 +430,7 @@ set_property (GObject *object, guint prop_id, priv->subject = g_value_dup_object (value); break; case PROP_INT_MASTER: - g_warn_if_fail (priv->master == NULL); - priv->master = g_value_dup_object (value); - if (priv->master) - g_warn_if_fail (priv->master != priv->device); + nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; case PROP_SPECIFIC_OBJECT: tmp = g_value_get_boxed (value); @@ -608,7 +631,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) "Internal master device", "Internal device", NM_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE)); nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (ac_class), diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index e4c097e6f4..96c7cba72c 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -109,4 +109,6 @@ gulong nm_active_connection_get_user_uid (NMActiveConnection *self); NMDevice * nm_active_connection_get_master (NMActiveConnection *self); +void nm_active_connection_set_master (NMActiveConnection *self, NMDevice *master); + #endif /* NM_ACTIVE_CONNECTION_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index dd732f8ca1..f8cfa7fc9e 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2559,9 +2559,9 @@ internal_activate_device (NMManager *manager, req = nm_act_request_new (connection, specific_object, subject, - device, - master_device); + device); g_assert (req); + nm_active_connection_set_master (NM_ACTIVE_CONNECTION (req), master_device); nm_device_activate (device, req); return NM_ACTIVE_CONNECTION (req); From 3bb2b158cdda573b79a8c209cf25f956e94e9e0d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 27 Aug 2013 12:16:57 -0500 Subject: [PATCH 21/32] core: switch NMActiveConnection master to an NMActiveConnection instead of NMDevice We need to track the master active connection, since it may require authentication or other operations to complete before the device actually starts activating. --- src/devices/nm-device.c | 24 ++++++++++++++--------- src/nm-active-connection.c | 39 ++++++++++++++++++++++++-------------- src/nm-active-connection.h | 5 +++-- src/nm-manager.c | 2 +- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 294aa9918f..5c87525b44 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3445,7 +3445,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *iface; int ifindex; - NMDevice *master; + NMActiveConnection *master; + NMDevice *master_device; /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, 0); @@ -3471,11 +3472,12 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) */ master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request)); if (master) { - if (priv->enslaved == FALSE) { + master_device = nm_active_connection_get_device (master); + if (master_device && priv->enslaved == FALSE) { nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on master '%s'", nm_device_get_iface (self), nm_connection_get_id (nm_device_get_connection (self)), - nm_device_get_iface (master)); + nm_device_get_iface (master_device)); } goto out; } @@ -4425,7 +4427,8 @@ nm_device_activate (NMDevice *self, NMActRequest *req) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); nm_device_activate_schedule_stage3_ip_config_start (self); } else { - NMDevice *master; + NMActiveConnection *master; + NMDevice *master_device; /* HACK: update the state a bit early to avoid a race between the * scheduled stage1 handler and nm_policy_device_change_check() thinking @@ -4437,12 +4440,15 @@ nm_device_activate (NMDevice *self, NMActRequest *req) /* Handle any dependencies this connection might have */ master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (req)); if (master) { - /* Master should at least already be activating */ - g_assert (nm_device_get_state (master) > NM_DEVICE_STATE_DISCONNECTED); + master_device = nm_active_connection_get_device (master); + if (master_device) { + /* Master should at least already be activating */ + g_assert (nm_device_get_state (master_device) > NM_DEVICE_STATE_DISCONNECTED); - g_assert (priv->master == NULL); - priv->master = g_object_ref (master); - nm_device_master_add_slave (master, self); + g_assert (priv->master == NULL); + priv->master = g_object_ref (master_device); + nm_device_master_add_slave (master_device, self); + } } nm_device_activate_schedule_stage1_device_prepare (self); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 72ee79823d..d24c621272 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -51,7 +51,7 @@ typedef struct { gboolean vpn; NMAuthSubject *subject; - NMDevice *master; + NMActiveConnection *master; NMAuthChain *chain; const char *wifi_shared_permission; @@ -257,7 +257,7 @@ nm_active_connection_get_device (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device; } -NMDevice * +NMActiveConnection * nm_active_connection_get_master (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); @@ -269,24 +269,29 @@ nm_active_connection_get_master (NMActiveConnection *self) * nm_active_connection_set_master: * @self: the #NMActiveConnection * @master: if the activation depends on another device (ie, bond or bridge - * master to which this device will be enslaved) pass the #NMDevice that this - * activation request be enslaved to + * master to which this device will be enslaved) pass the #NMActiveConnection + * that this activation request is a child of * - * Sets the master device of the active connection. + * Sets the master active connection of @self. */ void -nm_active_connection_set_master (NMActiveConnection *self, NMDevice *master) +nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master) { NMActiveConnectionPrivate *priv; + NMDevice *master_device; g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master)); priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + /* Master is write-once, and must be set before exporting the object */ g_return_if_fail (priv->master == NULL); g_return_if_fail (priv->path == NULL); - g_return_if_fail (master != priv->device); + + master_device = nm_active_connection_get_device (master); + if (master_device) + g_return_if_fail (master_device != priv->device); priv->master = g_object_ref (master); } @@ -413,6 +418,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); + NMDevice *master_device; const char *tmp; switch (prop_id) { @@ -423,8 +429,10 @@ set_property (GObject *object, guint prop_id, case PROP_INT_DEVICE: g_warn_if_fail (priv->device == NULL); priv->device = g_value_dup_object (value); - if (priv->device) - g_warn_if_fail (priv->device != priv->master); + if (priv->device && priv->master) { + master_device = nm_active_connection_get_device (priv->master); + g_warn_if_fail (priv->device != master_device); + } break; case PROP_INT_SUBJECT: priv->subject = g_value_dup_object (value); @@ -461,6 +469,7 @@ get_property (GObject *object, guint prop_id, { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); GPtrArray *devices; + NMDevice *master_device = NULL; switch (prop_id) { case PROP_CONNECTION: @@ -491,7 +500,9 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->vpn); break; case PROP_MASTER: - g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/"); + if (priv->master) + master_device = nm_active_connection_get_device (priv->master); + g_value_set_boxed (value, master_device ? nm_device_get_path (master_device) : "/"); break; case PROP_INT_SUBJECT: g_value_set_object (value, priv->subject); @@ -628,9 +639,9 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) g_object_class_install_property (object_class, PROP_INT_MASTER, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER, - "Internal master device", - "Internal device", - NM_TYPE_DEVICE, + "Internal master active connection", + "Internal active connection", + NM_TYPE_ACTIVE_CONNECTION, G_PARAM_READWRITE)); nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 96c7cba72c..93723c904e 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -107,8 +107,9 @@ gboolean nm_active_connection_get_user_requested (NMActiveConnection *self) gulong nm_active_connection_get_user_uid (NMActiveConnection *self); -NMDevice * nm_active_connection_get_master (NMActiveConnection *self); +NMActiveConnection *nm_active_connection_get_master (NMActiveConnection *self); -void nm_active_connection_set_master (NMActiveConnection *self, NMDevice *master); +void nm_active_connection_set_master (NMActiveConnection *self, + NMActiveConnection *master); #endif /* NM_ACTIVE_CONNECTION_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index f8cfa7fc9e..f3f2232232 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2561,7 +2561,7 @@ internal_activate_device (NMManager *manager, subject, device); g_assert (req); - nm_active_connection_set_master (NM_ACTIVE_CONNECTION (req), master_device); + nm_active_connection_set_master (NM_ACTIVE_CONNECTION (req), master); nm_device_activate (device, req); return NM_ACTIVE_CONNECTION (req); From 8252357dd1796dd6123a56a10356d0c5496e885b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Aug 2013 09:08:43 -0500 Subject: [PATCH 22/32] core: watch master ActiveConnections and follow master deactivation --- src/nm-activation-request.c | 24 +++++++++++++++++++++++ src/nm-active-connection.c | 30 +++++++++++++++++++++++++++++ src/nm-active-connection.h | 2 ++ src/vpn-manager/nm-vpn-connection.c | 13 +++++++++++++ 4 files changed, 69 insertions(+) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index ce9ee7da82..61d7782d44 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -334,6 +334,28 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), ac_state); } +static void +master_failed (NMActiveConnection *self) +{ + NMDevice *device; + NMDeviceState device_state; + + /* If the connection has an active device, fail it */ + device = nm_active_connection_get_device (self); + if (device) { + device_state = nm_device_get_state (device); + if (nm_device_is_activating (device) || (device_state == NM_DEVICE_STATE_ACTIVATED)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); + return; + } + } + + /* If no device, or the device wasn't active, just move to deactivated state */ + nm_active_connection_set_state (self, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); +} + /********************************************************************/ /** @@ -426,11 +448,13 @@ static void nm_act_request_class_init (NMActRequestClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); + NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (req_class); g_type_class_add_private (req_class, sizeof (NMActRequestPrivate)); /* virtual methods */ object_class->constructed = constructed; object_class->dispose = dispose; + active_class->master_failed = master_failed; } diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index d24c621272..f811dee82f 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -265,6 +265,26 @@ nm_active_connection_get_master (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master; } +static void +master_state_cb (NMActiveConnection *master, + GParamSpec *pspec, + gpointer user_data) +{ + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionState self_state = nm_active_connection_get_state (self); + NMActiveConnectionState master_state = nm_active_connection_get_state (master); + + /* Master is deactivating, so this active connection must also deactivate */ + if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING && + master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + g_signal_handlers_disconnect_by_func (master, + (GCallback) master_state_cb, + self); + if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed) + NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self); + } +} + /** * nm_active_connection_set_master: * @self: the #NMActiveConnection @@ -294,6 +314,10 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m g_return_if_fail (master_device != priv->device); priv->master = g_object_ref (master); + g_signal_connect (priv->master, + "notify::" NM_ACTIVE_CONNECTION_STATE, + (GCallback) master_state_cb, + self); } /****************************************************************/ @@ -530,6 +554,12 @@ dispose (GObject *object) g_clear_object (&priv->connection); g_clear_object (&priv->device); + + if (priv->master) { + g_signal_handlers_disconnect_by_func (priv->master, + (GCallback) master_state_cb, + NM_ACTIVE_CONNECTION (object)); + } g_clear_object (&priv->master); g_clear_object (&priv->subject); diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 93723c904e..1605c3963a 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -56,6 +56,8 @@ typedef struct { typedef struct { GObjectClass parent; + + void (*master_failed) (NMActiveConnection *connection); } NMActiveConnectionClass; GType nm_active_connection_get_type (void); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 129123acdb..ec66732d2f 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -295,6 +295,17 @@ device_state_changed (NMDevice *device, } } +static void +master_failed (NMActiveConnection *self) +{ + NMVPNConnection *connection = NM_VPN_CONNECTION (self); + + /* Master failure fails the VPN */ + nm_vpn_connection_set_vpn_state (connection, + NM_VPN_CONNECTION_STATE_FAILED, + NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); +} + static void add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw) { @@ -1768,6 +1779,7 @@ static void nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) { GObjectClass *object_class = G_OBJECT_CLASS (connection_class); + NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (connection_class); g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate)); @@ -1776,6 +1788,7 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) object_class->constructed = constructed; object_class->dispose = dispose; object_class->finalize = finalize; + active_class->master_failed = master_failed; g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER); From ae116d847ea8dd03549158a35871e7a1c4796c14 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Aug 2013 11:43:50 -0500 Subject: [PATCH 23/32] core: allow ActiveConnection connection to be changed For the case of AddAndActivate, which needs to set the final connection after authentication is done and NMSettings has returned the final connection. --- src/nm-active-connection.c | 15 +++++++++++++++ src/nm-active-connection.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index f811dee82f..2eb88fb35c 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -133,6 +133,21 @@ nm_active_connection_get_connection (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection; } +void +nm_active_connection_set_connection (NMActiveConnection *self, + NMConnection *connection) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + /* Can't change connection after the ActiveConnection is exported over D-Bus */ + g_return_if_fail (priv->path == NULL); + g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection)); + + if (priv->connection) + g_object_unref (priv->connection); + priv->connection = g_object_ref (connection); +} + const char * nm_active_connection_get_path (NMActiveConnection *self) { diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 1605c3963a..a86e171a55 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -77,6 +77,9 @@ void nm_active_connection_export (NMActiveConnection *self); NMConnection *nm_active_connection_get_connection (NMActiveConnection *self); +void nm_active_connection_set_connection (NMActiveConnection *self, + NMConnection *connection); + const char * nm_active_connection_get_name (NMActiveConnection *self); const char * nm_active_connection_get_path (NMActiveConnection *self); From 087e1dfbb9968c5b68c65639ffc9c37f9e629cd3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 27 Sep 2013 17:13:43 -0500 Subject: [PATCH 24/32] core: indicate via a property when master connections are ready for slaves Add a 'master-ready' property to NMActiveConnection that NMDevice can watch for to indicate that the master connection/device is ready to accept slaves. Since the slave device's ActiveConnection is already tracking its master connection, and since ActiveConnections don't enter the ACTIVATING state until their device is ready for slaves, it's pretty trivial to implement this property. --- src/nm-active-connection.c | 66 ++++++++++++++++++++++++++++++++++++++ src/nm-active-connection.h | 3 ++ 2 files changed, 69 insertions(+) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 2eb88fb35c..3de997b9a9 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -52,6 +52,7 @@ typedef struct { NMAuthSubject *subject; NMActiveConnection *master; + gboolean master_ready; NMAuthChain *chain; const char *wifi_shared_permission; @@ -76,10 +77,13 @@ enum { PROP_INT_DEVICE, PROP_INT_SUBJECT, PROP_INT_MASTER, + PROP_INT_MASTER_READY, LAST_PROP }; +static void check_master_ready (NMActiveConnection *self); + /****************************************************************/ NMActiveConnectionState @@ -106,6 +110,8 @@ nm_active_connection_set_state (NMActiveConnection *self, priv->state = new_state; g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE); + check_master_ready (self); + if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection), @@ -280,6 +286,53 @@ nm_active_connection_get_master (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master; } +/** + * nm_active_connection_get_master_ready: + * @self: the #NMActiveConnection + * + * Returns: %TRUE if the connection has a master connection, and that + * master connection is ready to accept slaves. Otherwise %FALSE. + */ +gboolean +nm_active_connection_get_master_ready (NMActiveConnection *self) +{ + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master_ready; +} + +static void +check_master_ready (NMActiveConnection *self) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; + + if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) + return; + if (!priv->master) + return; + if (priv->master_ready) + return; + + /* ActiveConnetions don't enter the ACTIVATING state until they have a + * NMDevice in PREPARE or higher states, so the master active connection's + * device will be ready to accept slaves when the master is in ACTIVATING + * or higher states. + */ + master_state = nm_active_connection_get_state (priv->master); + if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING + || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + priv->master_ready = TRUE; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY); + + /* Also notify clients to recheck the exported 'master' property to + * ensure that if the master connection was created without a device + * that we notify clients when the master device is known. + */ + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_MASTER); + } +} + static void master_state_cb (NMActiveConnection *master, GParamSpec *pspec, @@ -289,6 +342,8 @@ master_state_cb (NMActiveConnection *master, NMActiveConnectionState self_state = nm_active_connection_get_state (self); NMActiveConnectionState master_state = nm_active_connection_get_state (master); + check_master_ready (self); + /* Master is deactivating, so this active connection must also deactivate */ if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING && master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { @@ -333,6 +388,8 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m "notify::" NM_ACTIVE_CONNECTION_STATE, (GCallback) master_state_cb, self); + + check_master_ready (self); } /****************************************************************/ @@ -546,6 +603,9 @@ get_property (GObject *object, guint prop_id, case PROP_INT_SUBJECT: g_value_set_object (value, priv->subject); break; + case PROP_INT_MASTER_READY: + g_value_set_boolean (value, priv->master_ready); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -689,6 +749,12 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) NM_TYPE_ACTIVE_CONNECTION, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_INT_MASTER_READY, + g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY, + "Internal master active connection ready for slaves", + "Internal active connection ready", + FALSE, G_PARAM_READABLE)); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (ac_class), &dbus_glib_nm_active_connection_object_info); diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index a86e171a55..835266b3f1 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -49,6 +49,7 @@ #define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" +#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready" typedef struct { GObject parent; @@ -114,6 +115,8 @@ gulong nm_active_connection_get_user_uid (NMActiveConnection *self); NMActiveConnection *nm_active_connection_get_master (NMActiveConnection *self); +gboolean nm_active_connection_get_master_ready (NMActiveConnection *self); + void nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master); From f95bca2dcf6315ca116e545373ecce6bd360e424 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Sep 2013 09:19:21 -0500 Subject: [PATCH 25/32] core: ensure all devices chain up to parent act_stage1_prepare We'll be moving some code into the NMDevice implementation soon, which currently does nothing other than return success. --- src/devices/nm-device-infiniband.c | 7 ++++++- src/devices/nm-device-modem.c | 5 +++++ src/devices/nm-device-olpc-mesh.c | 5 +++++ src/devices/nm-device-wifi.c | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 4f71c7d7c3..b502fe70e2 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -147,6 +147,7 @@ get_generic_capabilities (NMDevice *dev) static NMActStageReturn act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { + NMActStageReturn ret; NMActRequest *req; NMConnection *connection; NMSettingInfiniband *s_infiniband; @@ -156,6 +157,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + req = nm_device_get_act_request (dev); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -186,7 +191,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) return NM_ACT_STAGE_RETURN_FAILURE; } - return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason); + return NM_ACT_STAGE_RETURN_SUCCESS; } static void diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c index 6ca3c2b84c..0bed60cd80 100644 --- a/src/devices/nm-device-modem.c +++ b/src/devices/nm-device-modem.c @@ -252,8 +252,13 @@ deactivate (NMDevice *device) static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { + NMActStageReturn ret; NMActRequest *req; + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + req = nm_device_get_act_request (device); g_assert (req); diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c index 8a032e45f0..c419daa5e7 100644 --- a/src/devices/nm-device-olpc-mesh.c +++ b/src/devices/nm-device-olpc-mesh.c @@ -252,8 +252,13 @@ static NMActStageReturn act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (dev); + NMActStageReturn ret; gboolean scanning; + ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (dev, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + /* disconnect companion device, if it is connected */ if (nm_device_get_act_request (NM_DEVICE (priv->companion))) { nm_log_info (LOGD_OLPC_MESH, "(%s): disconnecting companion device %s", diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index 716ce9e3b3..e4c16613d9 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -2790,6 +2790,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (dev); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMActStageReturn ret; NMAccessPoint *ap = NULL; NMActRequest *req; NMConnection *connection; @@ -2798,6 +2799,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) GSList *iter; const char *mode; + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage1_prepare (dev, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + req = nm_device_get_act_request (NM_DEVICE (self)); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); From 1768b3abd5581f1fee9a4937f34f26f5b23a1a70 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Sep 2013 09:21:17 -0500 Subject: [PATCH 26/32] core: add slave to master in stage1_prepare, not nm_device_activate() When ActiveConnections take over authentication, it may mean that the master active connection is still handling authentication when the slave starts to activate. Thus the master device may still be in DISCONNECTED state and not ready to enslave the slave. --- src/devices/nm-device.c | 77 +++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5c87525b44..660e26a59d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -288,6 +288,7 @@ typedef struct { /* master interface for bridge/bond/team slave */ NMDevice * master; gboolean enslaved; + guint master_ready_id; /* slave management */ gboolean is_master; @@ -1935,10 +1936,61 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6) return FALSE; } +static void +master_ready_cb (NMActiveConnection *active, + GParamSpec *pspec, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActiveConnection *master; + + g_assert (priv->state == NM_DEVICE_STATE_PREPARE); + + /* Notify a master device that it has a new slave */ + g_assert (nm_active_connection_get_master_ready (active)); + master = nm_active_connection_get_master (active); + + priv->master = g_object_ref (nm_active_connection_get_device (master)); + nm_device_master_add_slave (priv->master, self); + + nm_log_dbg (LOGD_DEVICE, "(%s): master connection ready; master device %s", + nm_device_get_iface (self), + nm_device_get_iface (priv->master)); + + if (priv->master_ready_id) { + g_signal_handler_disconnect (active, priv->master_ready_id); + priv->master_ready_id = 0; + } + + nm_device_activate_schedule_stage2_device_config (self); +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) { - return NM_ACT_STAGE_RETURN_SUCCESS; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); + + if (nm_active_connection_get_master (active)) { + /* If the master connection is ready for slaves, attach ourselves */ + if (nm_active_connection_get_master_ready (active)) + master_ready_cb (active, NULL, self); + else { + nm_log_dbg (LOGD_DEVICE, "(%s): waiting for master connection to become ready", + nm_device_get_iface (self)); + + /* Attach a signal handler and wait for the master connection to begin activating */ + g_assert (priv->master_ready_id == 0); + priv->master_ready_id = g_signal_connect (active, + "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY, + (GCallback) master_ready_cb, + self); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } + } + + return ret; } /* @@ -4024,6 +4076,11 @@ clear_act_request (NMDevice *self) nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + if (priv->master_ready_id) { + g_signal_handler_disconnect (priv->act_request, priv->master_ready_id); + priv->master_ready_id = 0; + } + g_object_unref (priv->act_request); priv->act_request = NULL; } @@ -4427,9 +4484,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); nm_device_activate_schedule_stage3_ip_config_start (self); } else { - NMActiveConnection *master; - NMDevice *master_device; - /* HACK: update the state a bit early to avoid a race between the * scheduled stage1 handler and nm_policy_device_change_check() thinking * that the activation request isn't deferred because the deferred bit @@ -4437,20 +4491,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req) */ nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - /* Handle any dependencies this connection might have */ - master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (req)); - if (master) { - master_device = nm_active_connection_get_device (master); - if (master_device) { - /* Master should at least already be activating */ - g_assert (nm_device_get_state (master_device) > NM_DEVICE_STATE_DISCONNECTED); - - g_assert (priv->master == NULL); - priv->master = g_object_ref (master_device); - nm_device_master_add_slave (master_device, self); - } - } - nm_device_activate_schedule_stage1_device_prepare (self); } } @@ -5033,6 +5073,7 @@ dispose (GObject *object) dnsmasq_cleanup (self); g_warn_if_fail (priv->slaves == NULL); + g_assert (priv->master_ready_id == 0); /* Take the device itself down and clear its IPv4 configuration */ if (nm_device_get_managed (self) && deconfigure) { From a7bab4015ebf12714f6e7ea6303cb46df6465058 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 27 Sep 2013 14:40:18 -0500 Subject: [PATCH 27/32] core: have ActiveConnection track device state instead of subclasses Both NMActRequest and NMVPNConnection need to track their device's state, so instead of both subclasses having to do so, consolidate that code into the superclass. --- src/nm-activation-request.c | 48 ++++----------------- src/nm-active-connection.c | 62 +++++++++++++++++++++++++-- src/nm-active-connection.h | 9 +++- src/nm-policy.c | 12 +++--- src/vpn-manager/nm-vpn-connection.c | 65 +++++++++-------------------- src/vpn-manager/nm-vpn-connection.h | 1 - 6 files changed, 101 insertions(+), 96 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 61d7782d44..922af93a08 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -51,7 +51,6 @@ typedef struct { } ShareRule; typedef struct { - guint device_state_id; GSList *secrets_calls; gboolean shared; GSList *share_rules; @@ -286,15 +285,15 @@ nm_act_request_add_share_rule (NMActRequest *req, /********************************************************************/ static void -device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) +device_state_changed (NMActiveConnection *active, + NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state) { - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - g_return_if_fail (device == nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self))); - /* Set NMActiveConnection state based on the device's state */ - switch (nm_device_get_state (device)) { + switch (new_state) { case NM_DEVICE_STATE_PREPARE: case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: @@ -314,12 +313,6 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; - - /* No longer need to pay attention to device state */ - if (device && priv->device_state_id) { - g_signal_handler_disconnect (device, priv->device_state_id); - priv->device_state_id = 0; - } break; default: break; @@ -327,11 +320,11 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self) if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED || ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (self), FALSE); - nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (self), FALSE); + nm_active_connection_set_default (active, FALSE); + nm_active_connection_set_default6 (active, FALSE); } - nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), ac_state); + nm_active_connection_set_state (active, ac_state); } static void @@ -394,36 +387,13 @@ nm_act_request_init (NMActRequest *req) { } -static void -constructed (GObject *object) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - NMDevice *device; - - G_OBJECT_CLASS (nm_act_request_parent_class)->constructed (object); - - device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - g_assert (device); - priv->device_state_id = g_signal_connect (device, - "notify::" NM_DEVICE_STATE, - G_CALLBACK (device_state_changed), - NM_ACT_REQUEST (object)); -} - static void dispose (GObject *object) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); NMConnection *connection; - NMDevice *device; GSList *iter; - device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - if (device && priv->device_state_id) { - g_signal_handler_disconnect (device, priv->device_state_id); - priv->device_state_id = 0; - } - /* Clear any share rules */ if (priv->share_rules) { nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE); @@ -453,8 +423,8 @@ nm_act_request_class_init (NMActRequestClass *req_class) g_type_class_add_private (req_class, sizeof (NMActRequestPrivate)); /* virtual methods */ - object_class->constructed = constructed; object_class->dispose = dispose; active_class->master_failed = master_failed; + active_class->device_state_changed = device_state_changed; } diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 3de997b9a9..168d92df33 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -44,6 +44,7 @@ typedef struct { char *path; char *specific_object; NMDevice *device; + guint32 device_state_id; gboolean is_default; gboolean is_default6; @@ -119,8 +120,10 @@ nm_active_connection_set_state (NMActiveConnection *self, } if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - /* Device is no longer relevant when deactivated */ - g_clear_object (&priv->device); + /* Device is no longer relevant when deactivated; emit property change + * notification so clients re-read the value, which will be NULL due to + * conditions in get_property(). + */ g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES); } } @@ -278,6 +281,45 @@ nm_active_connection_get_device (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device; } +static void +device_state_changed (NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + if (old_state < NM_DEVICE_STATE_DISCONNECTED) + return; + + if (old_state > NM_DEVICE_STATE_DISCONNECTED) { + /* Ignore disconnects if this ActiveConnection has not yet started + * activating. This is caused by activating a device when it's + * already activated, which causes a deactivating of the device before + * activating the new connection. + */ + if (new_state == NM_DEVICE_STATE_DISCONNECTED && + old_state > NM_DEVICE_STATE_DISCONNECTED && + priv->state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { + return; + } + + /* If the device used to be active, but now is disconnected/failed, we + * no longer care about its state. + */ + if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) { + g_signal_handler_disconnect (device, priv->device_state_id); + priv->device_state_id = 0; + } + } + + /* Let subclasses handle the state change */ + if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed) + NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state); +} + NMActiveConnection * nm_active_connection_get_master (NMActiveConnection *self) { @@ -523,12 +565,18 @@ set_property (GObject *object, guint prop_id, priv->connection = g_value_dup_object (value); break; case PROP_INT_DEVICE: - g_warn_if_fail (priv->device == NULL); + g_return_if_fail (priv->device == NULL); priv->device = g_value_dup_object (value); if (priv->device && priv->master) { master_device = nm_active_connection_get_device (priv->master); g_warn_if_fail (priv->device != master_device); } + if (priv->device) { + priv->device_state_id = g_signal_connect (priv->device, + "state-changed", + G_CALLBACK (device_state_changed), + NM_ACTIVE_CONNECTION (object)); + } break; case PROP_INT_SUBJECT: priv->subject = g_value_dup_object (value); @@ -579,7 +627,7 @@ get_property (GObject *object, guint prop_id, break; case PROP_DEVICES: devices = g_ptr_array_sized_new (1); - if (priv->device) + if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device))); g_value_take_boxed (value, devices); break; @@ -628,6 +676,12 @@ dispose (GObject *object) priv->specific_object = NULL; g_clear_object (&priv->connection); + + if (priv->device_state_id) { + g_assert (priv->device); + g_signal_handler_disconnect (priv->device, priv->device_state_id); + priv->device_state_id = 0; + } g_clear_object (&priv->device); if (priv->master) { diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 835266b3f1..acb2f4dd52 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -58,7 +58,14 @@ typedef struct { typedef struct { GObjectClass parent; - void (*master_failed) (NMActiveConnection *connection); + /* re-emits device state changes as a convenience for subclasses for + * device states >= DISCONNECTED. + */ + void (*device_state_changed) (NMActiveConnection *connection, + NMDevice *device, + NMDeviceState new_state, + NMDeviceState old_state); + void (*master_failed) (NMActiveConnection *connection); } NMActiveConnectionClass; GType nm_active_connection_get_type (void); diff --git a/src/nm-policy.c b/src/nm-policy.c index 9f480032e2..96a85208ad 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -669,7 +669,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) gw_addr = nm_ip4_config_get_gateway (ip4_config); if (vpn) { - NMDevice *parent = nm_vpn_connection_get_parent_device (vpn); + NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); int parent_ifindex = nm_device_get_ip_ifindex (parent); NMIP4Config *parent_ip4 = nm_device_get_ip4_config (parent); guint32 parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0; @@ -683,7 +683,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) } } - default_device = nm_vpn_connection_get_parent_device (vpn); + default_device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); } else { int mss = nm_ip4_config_get_mss (ip4_config); @@ -856,7 +856,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) gw_addr = &in6addr_any; if (vpn) { - NMDevice *parent = nm_vpn_connection_get_parent_device (vpn); + NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); int parent_ifindex = nm_device_get_ip_ifindex (parent); NMIP6Config *parent_ip6 = nm_device_get_ip6_config (parent); guint32 parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0; @@ -873,7 +873,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) } } - default_device6 = nm_vpn_connection_get_parent_device (vpn); + default_device6 = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); } else { int mss = nm_ip6_config_get_mss (ip6_config); @@ -1136,7 +1136,7 @@ process_secondaries (NMPolicy *policy, ac_path = nm_active_connection_get_path (active); if (NM_IS_VPN_CONNECTION (active)) - device = nm_vpn_connection_get_parent_device (NM_VPN_CONNECTION (active)); + device = nm_active_connection_get_device (active); for (iter = priv->pending_secondaries; iter; iter = g_slist_next (iter)) { PendingSecondaryData *secondary_data = (PendingSecondaryData *) iter->data; @@ -1740,7 +1740,7 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn) nm_dns_manager_begin_updates (mgr, __func__); ip_iface = nm_vpn_connection_get_ip_iface (vpn); - parent = nm_vpn_connection_get_parent_device (vpn); + parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); ip4_config = nm_vpn_connection_get_ip4_config (vpn); if (ip4_config) { diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index ec66732d2f..6962e301d0 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -71,9 +71,6 @@ typedef struct { SecretsReq secrets_idx; char *username; - NMDevice *parent_dev; - gulong device_monitor; - NMVPNConnectionState vpn_state; NMVPNConnectionStateReason failure_reason; DBusGProxy *proxy; @@ -163,7 +160,7 @@ call_plugin_disconnect (NMVPNConnection *self) } static void -vpn_cleanup (NMVPNConnection *connection) +vpn_cleanup (NMVPNConnection *connection, NMDevice *parent_dev) { NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); @@ -173,8 +170,8 @@ vpn_cleanup (NMVPNConnection *connection) nm_platform_address_flush (priv->ip_ifindex); } - nm_device_set_vpn4_config (priv->parent_dev, NULL); - nm_device_set_vpn6_config (priv->parent_dev, NULL); + nm_device_set_vpn4_config (parent_dev, NULL); + nm_device_set_vpn6_config (parent_dev, NULL); g_free (priv->banner); priv->banner = NULL; @@ -197,6 +194,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, { NMVPNConnectionPrivate *priv; NMVPNConnectionState old_vpn_state; + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection)); g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); @@ -242,7 +240,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, /* Let dispatcher scripts know we're up and running */ nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP, priv->connection, - priv->parent_dev, + parent_dev, priv->ip_iface, priv->ip4_config, priv->ip6_config, @@ -255,7 +253,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, /* Let dispatcher scripts know we're about to go down */ nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN, priv->connection, - priv->parent_dev, + parent_dev, priv->ip_iface, NULL, NULL, @@ -265,7 +263,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, /* Tear down and clean up the connection */ call_plugin_disconnect (connection); - vpn_cleanup (connection); + vpn_cleanup (connection, parent_dev); /* Fall through */ default: priv->secrets_idx = SECRETS_REQ_SYSTEM; @@ -276,20 +274,17 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, } static void -device_state_changed (NMDevice *device, +device_state_changed (NMActiveConnection *active, + NMDevice *device, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) + NMDeviceState old_state) { - NMVPNConnection *connection = NM_VPN_CONNECTION (user_data); - if (new_state <= NM_DEVICE_STATE_DISCONNECTED) { - nm_vpn_connection_set_vpn_state (connection, + nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active), NM_VPN_CONNECTION_STATE_DISCONNECTED, NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); } else if (new_state == NM_DEVICE_STATE_FAILED) { - nm_vpn_connection_set_vpn_state (connection, + nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active), NM_VPN_CONNECTION_STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); } @@ -655,6 +650,7 @@ static gboolean nm_vpn_connection_apply_config (NMVPNConnection *connection) { NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection)); nm_platform_link_set_up (priv->ip_ifindex); @@ -671,9 +667,9 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection) /* Add any explicit route to the VPN gateway through the parent device */ if (priv->ip4_external_gw) - add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_external_gw); + add_ip4_vpn_gateway_route (parent_dev, priv->ip4_external_gw); if (priv->ip6_external_gw) - add_ip6_vpn_gateway_route (priv->parent_dev, priv->ip6_external_gw); + add_ip6_vpn_gateway_route (parent_dev, priv->ip6_external_gw); nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.", nm_connection_get_id (priv->connection)); @@ -1400,14 +1396,6 @@ nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection) return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex; } -NMDevice * -nm_vpn_connection_get_parent_device (NMVPNConnection *connection) -{ - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); - - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev; -} - guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection) { @@ -1677,23 +1665,12 @@ nm_vpn_connection_init (NMVPNConnection *self) static void constructed (GObject *object) { - NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); NMConnection *connection; - NMDevice *device; G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object); connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object)); - priv->connection = g_object_ref (connection); - - device = (NMDevice *) nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - g_assert (device); - - priv->parent_dev = g_object_ref (device); - - priv->device_monitor = g_signal_connect (device, "state-changed", - G_CALLBACK (device_state_changed), - object); + NM_VPN_CONNECTION_GET_PRIVATE (object)->connection = g_object_ref (connection); } static void @@ -1715,11 +1692,6 @@ dispose (GObject *object) if (priv->ip6_external_gw) g_free (priv->ip6_external_gw); - if (priv->device_monitor) - g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor); - - g_clear_object (&priv->parent_dev); - if (priv->ip4_config) g_object_unref (priv->ip4_config); if (priv->ip6_config) @@ -1758,6 +1730,7 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); + NMDevice *parent_dev; switch (prop_id) { case PROP_VPN_STATE: @@ -1767,7 +1740,8 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, priv->banner ? priv->banner : ""); break; case PROP_MASTER: - g_value_set_boxed (value, nm_device_get_path (priv->parent_dev)); + parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); + g_value_set_boxed (value, parent_dev ? nm_device_get_path (parent_dev) : "/"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1789,6 +1763,7 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) object_class->dispose = dispose; object_class->finalize = finalize; active_class->master_failed = master_failed; + active_class->device_state_changed = device_state_changed; g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER); diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index d0554faee2..b98dcbe629 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -82,7 +82,6 @@ NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connect NMIP6Config * nm_vpn_connection_get_ip6_config (NMVPNConnection *connection); const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection); int nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection); -NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection); guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection); struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection); From 1b37cd03409fa3c0fb26fb6e8093b54b2b7c5d8d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 16 Sep 2013 17:43:31 -0500 Subject: [PATCH 28/32] core: allow ActiveConnections to be created without a device The device may not be created yet (in the case of software devices) when the ActiveConnection is created; in that case we still want to proceed with authorization for the connection, but we'll create the device when authorization is complete. --- src/nm-activation-request.c | 8 +++--- src/nm-active-connection.c | 52 +++++++++++++++++++++++-------------- src/nm-active-connection.h | 4 ++- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 922af93a08..18968f7633 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -358,9 +358,11 @@ master_failed (NMActiveConnection *self) * @specific_object: the object path of the specific object (ie, WiFi access point, * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation - * @device: the device/interface to configure according to @connection + * @device: the device/interface to configure according to @connection; or %NULL + * if the connection describes a software device which will be created during + * connection activation * - * Begins activation of @device using the given @connection and other details. + * Creates a new device-based activation request. * * Returns: the new activation request on success, %NULL on error. */ @@ -371,7 +373,7 @@ nm_act_request_new (NMConnection *connection, NMDevice *device) { g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); + g_return_val_if_fail (!device || NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST, diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 168d92df33..b8971b62ff 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -320,6 +320,33 @@ device_state_changed (NMDevice *device, NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state); } +gboolean +nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) +{ + NMActiveConnectionPrivate *priv; + + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + if (device) { + g_return_val_if_fail (priv->device == NULL, FALSE); + + /* Device obviously can't be its own master */ + g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE); + + priv->device = g_object_ref (device); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE); + + priv->device_state_id = g_signal_connect (device, + "state-changed", + G_CALLBACK (device_state_changed), + self); + } + return TRUE; +} + NMActiveConnection * nm_active_connection_get_master (NMActiveConnection *self) { @@ -410,7 +437,6 @@ void nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master) { NMActiveConnectionPrivate *priv; - NMDevice *master_device; g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master)); @@ -420,10 +446,10 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m /* Master is write-once, and must be set before exporting the object */ g_return_if_fail (priv->master == NULL); g_return_if_fail (priv->path == NULL); - - master_device = nm_active_connection_get_device (master); - if (master_device) - g_return_if_fail (master_device != priv->device); + if (priv->device) { + /* Note, the master ActiveConnection may not yet have a device */ + g_return_if_fail (priv->device != nm_active_connection_get_device (master)); + } priv->master = g_object_ref (master); g_signal_connect (priv->master, @@ -556,7 +582,6 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); - NMDevice *master_device; const char *tmp; switch (prop_id) { @@ -565,18 +590,7 @@ set_property (GObject *object, guint prop_id, priv->connection = g_value_dup_object (value); break; case PROP_INT_DEVICE: - g_return_if_fail (priv->device == NULL); - priv->device = g_value_dup_object (value); - if (priv->device && priv->master) { - master_device = nm_active_connection_get_device (priv->master); - g_warn_if_fail (priv->device != master_device); - } - if (priv->device) { - priv->device_state_id = g_signal_connect (priv->device, - "state-changed", - G_CALLBACK (device_state_changed), - NM_ACTIVE_CONNECTION (object)); - } + nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; case PROP_INT_SUBJECT: priv->subject = g_value_dup_object (value); @@ -787,7 +801,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) "Internal device", "Internal device", NM_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_INT_SUBJECT, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT, diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index acb2f4dd52..fa9e5fde4c 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -44,7 +44,7 @@ #define NM_ACTIVE_CONNECTION_VPN "vpn" #define NM_ACTIVE_CONNECTION_MASTER "master" -/* Internal non-exported construct-time properties */ +/* Internal non-exported properties */ #define NM_ACTIVE_CONNECTION_INT_CONNECTION "int-connection" #define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" @@ -114,6 +114,8 @@ void nm_active_connection_set_state (NMActiveConnection *self, NMDevice * nm_active_connection_get_device (NMActiveConnection *self); +gboolean nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device); + NMAuthSubject *nm_active_connection_get_subject (NMActiveConnection *self); gboolean nm_active_connection_get_user_requested (NMActiveConnection *self); From 8242b79f2923fb95e5c6326b7a20f1382313618b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 27 Sep 2013 10:12:08 -0500 Subject: [PATCH 29/32] policy: only clean up VPN DNS/routing configuration if the VPN got connected It's pointless and wrong to try to clean up DNS and routing configuration if the VPN never got to the point of retrieving that from the server. --- src/nm-policy.c | 52 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 96a85208ad..3cf5f88f59 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1723,8 +1723,6 @@ vpn_connection_activated (NMPolicy *policy, NMVPNConnection *vpn) update_routing_and_dns (policy, TRUE); nm_dns_manager_end_updates (mgr, __func__); - - process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), TRUE); } static void @@ -1757,8 +1755,23 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn) update_routing_and_dns (policy, TRUE); nm_dns_manager_end_updates (mgr, __func__); +} - process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), FALSE); +static void +vpn_connection_state_changed (NMVPNConnection *vpn, + NMVPNConnectionState new_state, + NMVPNConnectionState old_state, + NMVPNConnectionStateReason reason, + NMPolicy *policy) +{ + if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED) + vpn_connection_activated (policy, vpn); + else if (new_state >= NM_VPN_CONNECTION_STATE_FAILED) { + /* Only clean up IP/DNS if the connection ever got past IP_CONFIG */ + if (old_state >= NM_VPN_CONNECTION_STATE_IP_CONFIG_GET && + old_state <= NM_VPN_CONNECTION_STATE_ACTIVATED) + vpn_connection_deactivated (policy, vpn); + } } static void @@ -1766,18 +1779,12 @@ active_connection_state_changed (NMActiveConnection *active, GParamSpec *pspec, NMPolicy *policy) { - switch (nm_active_connection_get_state (active)) { - case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - if (NM_IS_VPN_CONNECTION (active)) - vpn_connection_activated (policy, NM_VPN_CONNECTION (active)); - break; - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: - if (NM_IS_VPN_CONNECTION (active)) - vpn_connection_deactivated (policy, NM_VPN_CONNECTION (active)); - break; - default: - break; - } + NMActiveConnectionState state = nm_active_connection_get_state (active); + + if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) + process_secondaries (policy, active, TRUE); + else if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) + process_secondaries (policy, active, FALSE); } static void @@ -1785,7 +1792,13 @@ active_connection_added (NMManager *manager, NMActiveConnection *active, gpointer user_data) { - NMPolicy *policy = (NMPolicy *) user_data; + NMPolicy *policy = NM_POLICY (user_data); + + if (NM_IS_VPN_CONNECTION (active)) { + g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, + G_CALLBACK (vpn_connection_state_changed), + policy); + } g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE, G_CALLBACK (active_connection_state_changed), @@ -1797,9 +1810,14 @@ active_connection_removed (NMManager *manager, NMActiveConnection *active, gpointer user_data) { + NMPolicy *policy = NM_POLICY (user_data); + + g_signal_handlers_disconnect_by_func (active, + vpn_connection_state_changed, + policy); g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, - (NMPolicy *) user_data); + policy); } /**************************************************************************/ From 625008e48631dcef9d90334a0a2e787c238b0c5b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Oct 2013 17:35:03 -0500 Subject: [PATCH 30/32] policy: track secondary activations by ActiveConnection not path ActiveConnections will (soon) not have a D-Bus path on creation, but only when they are exported after authorization is complete. That means we can't rely on their dbus path in the secondaries code. Instead, track them directly since the path may be NULL. --- src/nm-policy.c | 79 +++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 3cf5f88f59..09833a5b72 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1113,7 +1113,7 @@ static void pending_secondary_data_free (PendingSecondaryData *data) { g_object_unref (data->device); - g_slist_free_full (data->secondaries, g_free); + g_slist_free_full (data->secondaries, g_object_unref); memset (data, 0, sizeof (*data)); g_free (data); } @@ -1124,51 +1124,47 @@ process_secondaries (NMPolicy *policy, gboolean connected) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMDevice *device = NULL; - const char *ac_path; GSList *iter, *iter2; - nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' %s; active path '%s'", - nm_active_connection_get_name (active), - connected ? "SUCCEEDED" : "FAILED", - nm_active_connection_get_path (active)); - - ac_path = nm_active_connection_get_path (active); - - if (NM_IS_VPN_CONNECTION (active)) - device = nm_active_connection_get_device (active); - + /* Loop through devices waiting for secondary connections to activate */ for (iter = priv->pending_secondaries; iter; iter = g_slist_next (iter)) { PendingSecondaryData *secondary_data = (PendingSecondaryData *) iter->data; NMDevice *item_device = secondary_data->device; - if (!device || item_device == device) { - for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) { - char *list_ac_path = (char *) iter2->data; + /* Look for 'active' in each device's secondary connections list */ + for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) { + NMActiveConnection *secondary_active = NM_ACTIVE_CONNECTION (iter2->data); - if (g_strcmp0 (ac_path, list_ac_path) == 0) { - if (connected) { - /* Secondary connection activated */ - secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, list_ac_path); - g_free (list_ac_path); - if (!secondary_data->secondaries) { - /* None secondary UUID remained -> remove the secondary data item */ - priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); - pending_secondary_data_free (secondary_data); - nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE); - return; - } - } else { - /* Secondary connection failed -> do not watch other connections */ - priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); - pending_secondary_data_free (secondary_data); - nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); - return; - } + if (active != secondary_active) + continue; + + if (connected) { + nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' SUCCEEDED; active path '%s'", + nm_active_connection_get_name (active), + nm_active_connection_get_path (active)); + + /* Secondary connection activated */ + secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active); + g_object_unref (secondary_active); + if (!secondary_data->secondaries) { + /* No secondary UUID remained -> remove the secondary data item */ + priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); + pending_secondary_data_free (secondary_data); + nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE); + break; } + } else { + nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' FAILED; active path '%s'", + nm_active_connection_get_name (active), + nm_active_connection_get_path (active)); + + /* Secondary connection failed -> do not watch other connections */ + priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); + pending_secondary_data_free (secondary_data); + nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); + break; } - return; } } } @@ -1363,10 +1359,9 @@ activate_secondary_connections (NMPolicy *policy, device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), &error); - if (ac) { - secondary_ac_list = g_slist_append (secondary_ac_list, - g_strdup (nm_active_connection_get_path (ac))); - } else { + if (ac) + secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); + else { nm_log_warn (LOGD_DEVICE, "Secondary connection '%s' auto-activation failed: (%d) %s", sec_uuid, error ? error->code : 0, @@ -1387,7 +1382,7 @@ activate_secondary_connections (NMPolicy *policy, secondary_data = pending_secondary_data_new (device, secondary_ac_list); priv->pending_secondaries = g_slist_append (priv->pending_secondaries, secondary_data); } else - g_slist_free_full (secondary_ac_list, g_free); + g_slist_free_full (secondary_ac_list, g_object_unref); return success; } From ff7e47a41858881e102ce7c3686962f43d08cce4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Aug 2013 16:19:20 -0500 Subject: [PATCH 31/32] core: kill PendingActivation and move authorization to NMActiveConnection Besides killing PendingActivation, this patch decouples ActiveConnection creation from actually activating that connection. This allows the ActiveConnection to complete authorization asynchronously. This will also be used in the future for handling the DEACTIVATING state of devices (for "pre-down" functionality). --- src/nm-manager.c | 1012 +++++++++++++++++++++------------------------- src/nm-policy.c | 10 + 2 files changed, 473 insertions(+), 549 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index f3f2232232..af663c95ab 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -156,14 +156,14 @@ static void remove_device (NMManager *self, NMDevice *device, gboolean quitting) static void hostname_provider_init (NMHostnameProvider *provider_class); -static NMActiveConnection *internal_activate_device (NMManager *manager, - NMDevice *device, - NMConnection *connection, - const char *specific_object, - NMAuthSubject *subject, - gboolean assumed, - NMActiveConnection *master, - GError **error); +static NMActiveConnection *_new_active_connection (NMManager *self, + NMConnection *connection, + const char *specific_object, + NMDevice *device, + NMAuthSubject *subject, + GError **error); + +static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface); @@ -179,26 +179,6 @@ platform_link_added_cb (NMPlatform *platform, #define SSD_POKE_INTERVAL 120 #define ORIGDEV_TAG "originating-device" -typedef struct PendingActivation PendingActivation; -typedef void (*PendingActivationFunc) (PendingActivation *pending, - gpointer user_data, - GError *error); - -struct PendingActivation { - NMManager *manager; - - PendingActivationFunc callback; - gpointer user_data; - - NMAuthSubject *subject; - NMAuthChain *chain; - const char *wifi_shared_permission; - - NMConnection *connection; - NMDevice *device; - char *specific_object_path; -}; - typedef struct { gboolean user_enabled; gboolean daemon_enabled; @@ -334,12 +314,19 @@ static void active_connection_state_changed (NMActiveConnection *active, GParamSpec *pspec, NMManager *self); -static void -active_connection_removed (NMManager *self, NMActiveConnection *active) +/* Returns: whether to notify D-Bus of the removal or not */ +static gboolean +active_connection_remove (NMManager *self, NMActiveConnection *active) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gboolean notify = !!nm_active_connection_get_path (active); + + priv->active_connections = g_slist_remove (priv->active_connections, active); g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self); g_object_unref (active); + + return notify; } static gboolean @@ -348,24 +335,21 @@ _active_connection_cleanup (gpointer user_data) NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GSList *iter; - gboolean changed = FALSE; priv->ac_cleanup_id = 0; + g_object_freeze_notify (G_OBJECT (self)); iter = priv->active_connections; while (iter) { NMActiveConnection *ac = iter->data; iter = iter->next; if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - priv->active_connections = g_slist_remove (priv->active_connections, ac); - active_connection_removed (self, ac); - changed = TRUE; + if (active_connection_remove (self, ac)) + g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); } } - - if (changed) - g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); + g_object_thaw_notify (G_OBJECT (self)); return FALSE; } @@ -403,7 +387,10 @@ active_connection_add (NMManager *self, NMActiveConnection *active) self); g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active); - g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); + + /* Only notify D-Bus if the active connection is actually exported */ + if (nm_active_connection_get_path (active)) + g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); } const GSList * @@ -424,7 +411,7 @@ active_connection_get_by_path (NMManager *manager, const char *path) for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { NMActiveConnection *candidate = iter->data; - if (strcmp (path, nm_active_connection_get_path (candidate)) == 0) + if (g_strcmp0 (path, nm_active_connection_get_path (candidate)) == 0) return candidate; } return NULL; @@ -846,124 +833,6 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -static PendingActivation * -pending_activation_new (NMManager *manager, - NMAuthSubject *subject, - NMDevice *device, - NMConnection *connection, - const char *specific_object_path, - PendingActivationFunc callback, - gpointer user_data) -{ - PendingActivation *pending; - - g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (callback != NULL, NULL); - - /* A object path of "/" means NULL */ - if (g_strcmp0 (specific_object_path, "/") == 0) - specific_object_path = NULL; - - pending = g_slice_new0 (PendingActivation); - pending->manager = manager; - pending->connection = g_object_ref (connection); - pending->device = g_object_ref (device); - pending->specific_object_path = g_strdup (specific_object_path); - - pending->callback = callback; - pending->user_data = user_data; - pending->subject = g_object_ref (subject); - - return pending; -} - -static void -pending_auth_done (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) -{ - PendingActivation *pending = user_data; - NMAuthCallResult result; - GError *tmp_error = NULL; - - /* Caller has had a chance to obtain authorization, so we only need to - * check for 'yes' here. - */ - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); - if (error) - tmp_error = g_error_copy (error); - else if (result != NM_AUTH_CALL_RESULT_YES) { - tmp_error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Not authorized to control networking."); - } else if (pending->wifi_shared_permission) { - result = nm_auth_chain_get_result (chain, pending->wifi_shared_permission); - if (result != NM_AUTH_CALL_RESULT_YES) { - tmp_error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Not authorized to share connections via wifi."); - } - } - - pending->callback (pending, pending->user_data, tmp_error); - g_clear_error (&tmp_error); -} - -static gboolean -pending_activation_check_authorized (PendingActivation *pending, GError **error) -{ - const char *wifi_permission = NULL; - - g_return_val_if_fail (pending != NULL, FALSE); - - /* First check if the user is allowed to use networking at all, giving - * the user a chance to authenticate to gain the permission. - */ - pending->chain = nm_auth_chain_new_subject (pending->subject, - NULL, - pending_auth_done, - pending); - if (!pending->chain) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Failed to authorize"); - return FALSE; - } - - nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); - - /* Shared wifi connections require special permissions too */ - wifi_permission = nm_utils_get_shared_wifi_permission (pending->connection); - if (wifi_permission) { - pending->wifi_shared_permission = wifi_permission; - nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE); - } - - return TRUE; -} - -static void -pending_activation_destroy (PendingActivation *pending) -{ - g_return_if_fail (pending != NULL); - - g_free (pending->specific_object_path); - g_clear_object (&pending->device); - g_clear_object (&pending->connection); - g_clear_object (&pending->subject); - - if (pending->chain) - nm_auth_chain_unref (pending->chain); - - memset (pending, 0, sizeof (PendingActivation)); - g_slice_free (PendingActivation, pending); -} - /*******************************************************************/ /* Settings stuff via NMSettings */ /*******************************************************************/ @@ -2046,18 +1915,28 @@ add_device (NMManager *self, NMDevice *device) /* If the device has a connection it can assume, do that now */ if (connection && nm_device_can_activate (device, connection)) { - NMActiveConnection *ac; + NMActiveConnection *active; NMAuthSubject *subject; GError *error = NULL; nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection", nm_device_get_iface (device)); + /* Tear down any existing connection */ + if (nm_device_get_act_request (device)) { + nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.", + nm_device_get_iface (device)); + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + subject = nm_auth_subject_new_internal (); - ac = internal_activate_device (self, device, connection, NULL, subject, TRUE, NULL, &error); - if (ac) - active_connection_add (self, ac); - else { + active = _new_active_connection (self, connection, NULL, device, subject, &error); + if (active) { + active_connection_add (self, active); + nm_device_activate (device, NM_ACT_REQUEST (active)); + } else { nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s", nm_connection_get_path (connection), error ? error->code : -1, @@ -2522,51 +2401,6 @@ impl_manager_get_device_by_ip_iface (NMManager *self, return path ? TRUE : FALSE; } -static NMActiveConnection * -internal_activate_device (NMManager *manager, - NMDevice *device, - NMConnection *connection, - const char *specific_object, - NMAuthSubject *subject, - gboolean assumed, - NMActiveConnection *master, - GError **error) -{ - NMActRequest *req; - NMDevice *master_device = NULL; - - g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); - g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - - /* Ensure the requested connection is compatible with the device */ - if (!nm_device_check_connection_compatible (device, connection, error)) - return NULL; - - /* Tear down any existing connection */ - if (nm_device_get_act_request (device)) { - nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.", - nm_device_get_iface (device)); - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } - - if (master) - master_device = nm_active_connection_get_device (master); - - req = nm_act_request_new (connection, - specific_object, - subject, - device); - g_assert (req); - nm_active_connection_set_master (NM_ACTIVE_CONNECTION (req), master); - nm_device_activate (device, req); - - return NM_ACTIVE_CONNECTION (req); -} - /** * find_master: * @self: #NMManager object @@ -2831,19 +2665,208 @@ ensure_master_active_connection (NMManager *self, return NULL; } +static gboolean +_internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error) +{ + g_assert (NM_IS_VPN_CONNECTION (active)); + + return nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager, + NM_VPN_CONNECTION (active), + error); +} + +static gboolean +_internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error) +{ + NMDevice *device, *master_device = NULL; + NMConnection *connection; + NMConnection *master_connection = NULL; + + g_assert (NM_IS_VPN_CONNECTION (active) == FALSE); + + connection = nm_active_connection_get_connection (active); + g_assert (connection); + + device = nm_active_connection_get_device (active); + if (!device) { + char *iface; + + g_assert (connection_needs_virtual_device (connection)); + + iface = get_virtual_iface_name (self, connection, NULL); + g_assert (iface); + + /* Create the software device. Only exception is when: + * - this is an auto-activation *and* the device denies auto-activation + * at this time (the device was manually disconnected/deleted before) + */ + if (!nm_manager_can_device_auto_connect (self, iface)) { + if (nm_active_connection_get_user_requested (active)) { + /* Manual activation - allow device auto-activation again */ + nm_manager_prevent_device_auto_connect (self, iface, FALSE); + } else { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, + "Automatic activation of '%s' not allowed for connection '%s'", + iface, nm_connection_get_id (connection)); + g_free (iface); + return FALSE; + } + } + g_free (iface); + + device = system_create_virtual_device (self, connection); + if (!device) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Failed to create virtual interface"); + return FALSE; + } + + if (!nm_active_connection_set_device (active, device)) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "The device could not be activated with this connection"); + return FALSE; + } + + /* A newly created device, if allowed to be managed by NM, will be + * in the UNAVAILABLE state here. To ensure it can be activated + * immediately, we transition it to DISCONNECTED so it passes the + * nm_device_can_activate() check below. + */ + if ( nm_device_is_available (device) + && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + } + + /* Final connection must be compatible with the device */ + if (!nm_device_check_connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_device_can_activate (device, connection)) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE, + "Device not managed by NetworkManager or unavailable"); + return FALSE; + } + + /* If this is an autoconnect request, but the device isn't allowing autoconnect + * right now, we reject it. + */ + if (!nm_active_connection_get_user_requested (active) && + !nm_device_autoconnect_allowed (device)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, + "%s does not allow automatic connections at this time", + nm_device_get_iface (device)); + return FALSE; + } + + /* Try to find the master connection/device if the connection has a dependency */ + if (!find_master (self, connection, device, &master_connection, &master_device)) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Master connection not found or invalid"); + return FALSE; + } + + /* Ensure there's a master active connection the new connection we're + * activating can depend on. + */ + if (master_connection || master_device) { + NMActiveConnection *master_ac = NULL; + + if (master_connection) { + nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master connection '%s'", + nm_connection_get_id (connection), + nm_connection_get_id (master_connection)); + } + if (master_device) { + nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master device '%s'", + nm_connection_get_id (connection), + nm_device_get_ip_iface (master_device)); + } + + /* Ensure eg bond slave and the candidate master is a bond master */ + if (master_connection && !is_compatible_with_slave (master_connection, connection)) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, + "The master connection was not compatible"); + return FALSE; + } + + master_ac = ensure_master_active_connection (self, + nm_active_connection_get_subject (active), + connection, + device, + master_connection, + master_device, + error); + if (!master_ac) { + if (error) + g_assert (*error); + return FALSE; + } + + nm_active_connection_set_master (active, master_ac); + nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s", + nm_connection_get_id (connection), + nm_active_connection_get_path (master_ac)); + } + + /* Tear down any existing connection */ + if (nm_device_get_act_request (device)) { + nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.", + nm_device_get_iface (device)); + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } + + /* Start the new activation */ + nm_device_activate (device, NM_ACT_REQUEST (active)); + return TRUE; +} + +static gboolean +_internal_activate_generic (NMManager *self, NMActiveConnection *active, GError **error) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gboolean success = FALSE; + + if (NM_IS_VPN_CONNECTION (active)) + success = _internal_activate_vpn (self, active, error); + else + success = _internal_activate_device (self, active, error); + + if (success) { + nm_active_connection_export (active); + g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); + + /* Force an update of the Manager's activating-connection property. + * The device changes state before the AC gets exported, which causes + * the manager's 'activating-connection' property to be NULL since the + * AC only gets a D-Bus path when it's exported. So now that the AC + * is exported, make sure the manager's activating-connection property + * is up-to-date. + */ + policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self); + } + + return success; +} + static NMActiveConnection * -activate_vpn_connection (NMManager *self, - NMConnection *connection, - const char *specific_object, - NMAuthSubject *subject, - GError **error) +_new_vpn_active_connection (NMManager *self, + NMConnection *connection, + const char *specific_object, + NMAuthSubject *subject, + GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *parent = NULL; NMDevice *device = NULL; - GSList *iter; - NMVPNConnection *vpn; - gboolean success = FALSE; if (specific_object) { /* Find the specifc connection the client requested we use */ @@ -2853,16 +2876,8 @@ activate_vpn_connection (NMManager *self, "Base connection for VPN connection not active."); return NULL; } - } else { - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *candidate = iter->data; - - if (nm_active_connection_get_default (candidate)) { - parent = candidate; - break; - } - } - } + } else + parent = priv->primary_connection; if (!parent) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, @@ -2877,20 +2892,66 @@ activate_vpn_connection (NMManager *self, return NULL; } - vpn = nm_vpn_connection_new (connection, - device, - nm_active_connection_get_path (parent), - subject); - g_assert (vpn); - success = nm_vpn_manager_activate_connection (priv->vpn_manager, vpn, error); - if (!success) - g_object_unref (vpn); + return (NMActiveConnection *) nm_vpn_connection_new (connection, + device, + nm_active_connection_get_path (parent), + subject); +} - return success ? NM_ACTIVE_CONNECTION (vpn) : NULL; +static NMActiveConnection * +_new_active_connection (NMManager *self, + NMConnection *connection, + const char *specific_object, + NMDevice *device, + NMAuthSubject *subject, + GError **error) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); + + /* Normalize the specific object */ + if (specific_object && g_strcmp0 (specific_object, "/") == 0) + specific_object = NULL; + + if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { + return _new_vpn_active_connection (self, + connection, + specific_object, + subject, + error); + } + + return (NMActiveConnection *) nm_act_request_new (connection, + specific_object, + subject, + device); +} + +static void +_internal_activation_auth_done (NMActiveConnection *active, + gboolean success, + const char *error_desc, + gpointer user_data1, + gpointer user_data2) +{ + NMManager *self = user_data1; + GError *error = NULL; + + if (success) { + if (_internal_activate_generic (self, active, &error)) + return; + g_assert (error); + } + + active_connection_remove (self, active); + nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s", + nm_connection_get_id (nm_active_connection_get_connection (active)), + error_desc ? error_desc : error->message); + g_clear_error (&error); } NMActiveConnection * -nm_manager_activate_connection (NMManager *manager, +nm_manager_activate_connection (NMManager *self, NMConnection *connection, const char *specific_object, NMDevice *device, @@ -2898,225 +2959,26 @@ nm_manager_activate_connection (NMManager *manager, GError **error) { NMManagerPrivate *priv; - char *iface; - NMDevice *master_device = NULL; - NMConnection *master_connection = NULL; - NMActiveConnection *master_ac = NULL, *ac = NULL; - gboolean matched; - gboolean user_requested; + NMActiveConnection *active; - g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (error != NULL, NULL); g_return_val_if_fail (*error == NULL, NULL); - priv = NM_MANAGER_GET_PRIVATE (manager); + priv = NM_MANAGER_GET_PRIVATE (self); - /* VPN ? */ - if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { - ac = activate_vpn_connection (manager, - connection, - specific_object, - subject, - error); - goto activated; + active = _new_active_connection (self, + connection, + specific_object, + device, + subject, + error); + if (active) { + nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL); + active_connection_add (self, active); } - - user_requested = !nm_auth_subject_get_internal (subject); - - /* Device-based connection */ - if (device) { - /* If it's a virtual interface make sure the device given by the - * path matches the connection's interface details. - */ - if (connection_needs_virtual_device (connection)) { - iface = get_virtual_iface_name (manager, connection, NULL); - if (!iface) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to determine connection's virtual interface name"); - return NULL; - } - - matched = g_str_equal (iface, nm_device_get_ip_iface (device)); - g_free (iface); - if (!matched) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Device given by path did not match connection's virtual interface name"); - return NULL; - } - } - } else { - /* Virtual connections (VLAN, bond, team, etc) may not specify - * a device path because the device may not be created yet, - * or it be given by the connection's properties instead. - * Find the device the connection refers to, or create it - * if needed. - */ - if (!connection_needs_virtual_device (connection)) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "This connection requires an existing device."); - return NULL; - } - - iface = get_virtual_iface_name (manager, connection, NULL); - if (!iface) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to determine connection's virtual interface name"); - return NULL; - } - - device = find_device_by_ip_iface (manager, iface); - if (!device) { - /* Create the software device. Only exception is when: - * - this is an auto-activation *and* the device denies auto-activation - * at this time (the device was manually disconnected/deleted before) - */ - if (!nm_manager_can_device_auto_connect (manager, iface)) { - if (user_requested) { - /* Manual activation - allow device auto-activation again */ - nm_manager_prevent_device_auto_connect (manager, iface, FALSE); - } else { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, - "'%s' does not allow automatic connections at this time => software device '%s' not created for '%s'", - iface, iface, nm_connection_get_id (connection)); - g_free (iface); - return NULL; - } - } - - device = system_create_virtual_device (manager, connection); - if (!device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to create virtual interface '%s'", iface); - g_free (iface); - return NULL; - } - - /* A newly created device, if allowed to be managed by NM, will be - * in the UNAVAILABLE state here. To ensure it can be activated - * immediately, we transition it to DISCONNECTED so it passes the - * nm_device_can_activate() check below. - */ - if ( nm_device_is_available (device) - && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } - } - g_free (iface); - } - - if (!nm_device_can_activate (device, connection)) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE, - "Device not managed by NetworkManager or unavailable"); - return NULL; - } - - /* If this is an autoconnect request, but the device isn't allowing autoconnect - * right now, we reject it. - */ - if (!user_requested && !nm_device_autoconnect_allowed (device)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED, - "%s does not allow automatic connections at this time", - nm_device_get_iface (device)); - return NULL; - } - - /* Try to find the master connection/device if the connection has a dependency */ - if (!find_master (manager, connection, device, &master_connection, &master_device)) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Master connection not found or invalid"); - return NULL; - } - - /* Ensure there's a master active connection the new connection we're - * activating can depend on. - */ - if (master_connection || master_device) { - if (master_connection) { - nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master connection '%s'", - nm_connection_get_id (connection), - nm_connection_get_id (master_connection)); - } - if (master_device) { - nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master device '%s'", - nm_connection_get_id (connection), - nm_device_get_ip_iface (master_device)); - } - - /* Ensure eg bond/team slave and the candidate master is - * a bond/team master - */ - if (master_connection && !is_compatible_with_slave (master_connection, connection)) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, - "The master connection was not compatible"); - return NULL; - } - - master_ac = ensure_master_active_connection (manager, - subject, - connection, - device, - master_connection, - master_device, - error); - if (!master_ac) { - if (error) - g_assert (*error); - return NULL; - } - - nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s", - nm_connection_get_id (connection), - nm_active_connection_get_path (master_ac)); - } - - ac = internal_activate_device (manager, - device, - connection, - specific_object, - subject, - FALSE, - master_ac, - error); - -activated: - if (ac) { - active_connection_add (manager, ac); - nm_active_connection_export (ac); - } - - return ac; -} - -/* Finally activate a pending activation request; on success returns the new - * NMActiveConnection object, otherwise NULL and sets an error. - */ -static NMActiveConnection * -pending_activate (PendingActivation *pending, - NMSettingsConnection *new_connection, - GError **error) -{ - NMActiveConnection *ac = NULL; - GError *local = NULL; - - ac = nm_manager_activate_connection (pending->manager, - new_connection ? - NM_CONNECTION (new_connection) : pending->connection, - pending->specific_object_path, - pending->device, - pending->subject, - &local); - if (!ac) { - nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s", - nm_connection_get_path (pending->connection), - local->code, local->message ? local->message : "(unknown)"); - g_propagate_error (error, local); - } - - return ac; + return active; } static NMAuthSubject * @@ -3133,6 +2995,8 @@ validate_activation_request (NMManager *self, NMAuthSubject *subject = NULL; g_assert (connection); + g_assert (out_device); + g_assert (out_vpn); /* Validate the caller */ subject = nm_auth_subject_new_from_context (context); @@ -3154,53 +3018,81 @@ validate_activation_request (NMManager *self, device_path = NULL; /* And validate it */ - if (device_path) + if (device_path) { device = nm_manager_get_device_by_path (self, device_path); + if (!device) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Device not found"); + goto error; + } + } else { + gboolean is_software = connection_needs_virtual_device (connection); - /* VPN doesn't require a device, but if one is given validate it. - * Device-based connections obviously require a device, unless they are - * for a software device that hasn't been created yet. - */ - if ((device_path && !device) || - (!vpn && !device && !connection_needs_virtual_device (connection))) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Device not found"); - g_object_unref (subject); - return NULL; + /* VPN and software-device connections don't need a device yet */ + if (!vpn && !is_software) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "This connection requires an existing device."); + goto error; + } + + if (is_software) { + /* Look for an existing device with the connection's interface name */ + char *iface; + + iface = get_virtual_iface_name (self, connection, NULL); + if (!iface) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Failed to determine connection's virtual interface name"); + goto error; + } + + device = find_device_by_ip_iface (self, iface); + g_free (iface); + } } - if (out_device) - *out_device = device; - if (out_vpn) - *out_vpn = vpn; + *out_device = device; + *out_vpn = vpn; return subject; + +error: + g_object_unref (subject); + return NULL; } /***********************************************************************/ static void -activation_auth_done (PendingActivation *pending, gpointer user_data, GError *error) +activation_auth_done (NMActiveConnection *active, + gboolean success, + const char *error_desc, + gpointer user_data1, + gpointer user_data2) { - DBusGMethodInvocation *context = user_data; - NMActiveConnection *ac = NULL; - GError *local = NULL; + NMManager *self = user_data1; + DBusGMethodInvocation *context = user_data2; + GError *error = NULL; - if (!error) { - /* Try to activate the connection */ - ac = pending_activate (pending, NULL, &local); - if (!ac) - error = local; + if (success) { + if (_internal_activate_generic (self, active, &error)) { + dbus_g_method_return (context, nm_active_connection_get_path (active)); + return; + } + } else { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); } - if (ac) - dbus_g_method_return (context, nm_active_connection_get_path (ac)); - else - dbus_g_method_return_error (context, error); - - g_clear_error (&local); - pending_activation_destroy (pending); + active_connection_remove (self, active); + dbus_g_method_return_error (context, error); + g_error_free (error); } static void @@ -3211,10 +3103,11 @@ impl_manager_activate_connection (NMManager *self, DBusGMethodInvocation *context) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - PendingActivation *pending; + NMActiveConnection *active = NULL; NMAuthSubject *subject = NULL; NMConnection *connection; NMDevice *device = NULL; + gboolean is_vpn = FALSE; GError *error = NULL; connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); @@ -3230,34 +3123,29 @@ impl_manager_activate_connection (NMManager *self, connection, device_path, &device, - NULL, + &is_vpn, &error); if (!subject) goto error; - /* Need to check the caller's permissions and stuff before we can - * activate the connection. - */ - pending = pending_activation_new (self, - subject, - device, - connection, - specific_object_path, - activation_auth_done, - context); - g_assert (pending); - - if (!pending_activation_check_authorized (pending, &error)) { - pending_activation_destroy (pending); + active = _new_active_connection (self, + connection, + specific_object_path, + device, + subject, + &error); + if (!active) goto error; - } - /* success */ - g_object_unref (subject); + nm_active_connection_authorize (active, activation_auth_done, self, context); + active_connection_add (self, active); + g_clear_object (&subject); return; error: + g_clear_object (&active); g_clear_object (&subject); + g_assert (error); dbus_g_method_return_error (context, error); g_error_free (error); @@ -3265,6 +3153,11 @@ error: /***********************************************************************/ +typedef struct { + NMManager *manager; + NMActiveConnection *active; +} AddAndActivateInfo; + static void activation_add_done (NMSettings *self, NMSettingsConnection *new_connection, @@ -3272,48 +3165,66 @@ activation_add_done (NMSettings *self, DBusGMethodInvocation *context, gpointer user_data) { - PendingActivation *pending = user_data; - NMActiveConnection *ac = NULL; + AddAndActivateInfo *info = user_data; GError *local = NULL; if (!error) { - /* Try to activate the connection */ - ac = pending_activate (pending, new_connection, &local); - if (!ac) - error = local; + nm_active_connection_set_connection (info->active, NM_CONNECTION (new_connection)); + + if (_internal_activate_generic (info->manager, info->active, &local)) { + dbus_g_method_return (context, + nm_connection_get_path (NM_CONNECTION (new_connection)), + nm_active_connection_get_path (info->active)); + goto done; + } + error = local; } - if (ac) { - dbus_g_method_return (context, - nm_connection_get_path (NM_CONNECTION (new_connection)), - nm_active_connection_get_path (ac)); - } else - dbus_g_method_return_error (context, error); + active_connection_remove (info->manager, info->active); + if (error) + dbus_g_method_return_error (context, error); g_clear_error (&local); - pending_activation_destroy (pending); + +done: + g_object_unref (info->active); + g_free (info); } static void -add_and_activate_auth_done (PendingActivation *pending, - gpointer user_data, - GError *error) +add_and_activate_auth_done (NMActiveConnection *active, + gboolean success, + const char *error_desc, + gpointer user_data1, + gpointer user_data2) { - DBusGMethodInvocation *context = user_data; + NMManager *self = user_data1; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + DBusGMethodInvocation *context = user_data2; + AddAndActivateInfo *info; + GError *error = NULL; - if (error) { - dbus_g_method_return_error (context, error); - pending_activation_destroy (pending); - } else { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager); + if (success) { + info = g_malloc0 (sizeof (*info)); + info->manager = self; + info->active = g_object_ref (active); /* Basic sender auth checks performed; try to add the connection */ nm_settings_add_connection_dbus (priv->settings, - pending->connection, + nm_active_connection_get_connection (active), TRUE, context, activation_add_done, - pending); + info); + } else { + active_connection_remove (self, active); + + g_assert (error_desc); + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); + dbus_g_method_return_error (context, error); + g_error_free (error); } } @@ -3327,7 +3238,7 @@ impl_manager_add_and_activate_connection (NMManager *self, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMConnection *connection = NULL; GSList *all_connections = NULL; - PendingActivation *pending; + NMActiveConnection *active; NMAuthSubject *subject = NULL; GError *error = NULL; NMDevice *device = NULL; @@ -3353,6 +3264,14 @@ impl_manager_add_and_activate_connection (NMManager *self, if (!subject) goto error; + /* AddAndActivate() requires a device to complete the connection with */ + if (!device) { + error = g_error_new_literal (NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "This connection requires an existing device."); + goto error; + } + all_connections = nm_settings_get_connections (priv->settings); if (vpn) { /* Try to fill the VPN's connection setting and name at least */ @@ -3381,31 +3300,26 @@ impl_manager_add_and_activate_connection (NMManager *self, g_slist_free (all_connections); all_connections = NULL; - /* Need to check the caller's permissions and stuff before we can - * activate the connection. - */ - pending = pending_activation_new (self, - subject, - device, - connection, - specific_object_path, - add_and_activate_auth_done, - context); - g_assert (pending); - - if (!pending_activation_check_authorized (pending, &error)) { - pending_activation_destroy (pending); + active = _new_active_connection (self, + connection, + specific_object_path, + device, + subject, + &error); + if (!active) goto error; - } + nm_active_connection_authorize (active, add_and_activate_auth_done, self, context); + active_connection_add (self, active); g_object_unref (connection); g_object_unref (subject); - return; /* Success */ + return; error: g_clear_object (&connection); g_slist_free (all_connections); - g_object_unref (&subject); + g_clear_object (&subject); + g_clear_object (&active); g_assert (error); dbus_g_method_return_error (context, error); @@ -4573,7 +4487,6 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; - GSList *iter; if (priv->disposed) { G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object); @@ -4597,8 +4510,8 @@ dispose (GObject *object) priv->ac_cleanup_id = 0; } - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) - active_connection_removed (manager, NM_ACTIVE_CONNECTION (iter->data)); + while (priv->active_connections) + active_connection_remove (manager, NM_ACTIVE_CONNECTION (priv->active_connections->data)); g_slist_free (priv->active_connections); priv->active_connections = NULL; g_clear_object (&priv->primary_connection); @@ -4848,7 +4761,8 @@ get_property (GObject *object, guint prop_id, active = g_ptr_array_sized_new (3); for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data)); - g_ptr_array_add (active, g_strdup (path)); + if (path) + g_ptr_array_add (active, g_strdup (path)); } g_value_take_boxed (value, active); break; @@ -4856,12 +4770,12 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity)); break; case PROP_PRIMARY_CONNECTION: - path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : "/"; - g_value_set_boxed (value, path); + path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : NULL; + g_value_set_boxed (value, path ? path : "/"); break; case PROP_ACTIVATING_CONNECTION: - path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : "/"; - g_value_set_boxed (value, path); + path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : NULL; + g_value_set_boxed (value, path ? path : "/"); break; case PROP_HOSTNAME: g_value_set_string (value, priv->hostname); diff --git a/src/nm-policy.c b/src/nm-policy.c index 09833a5b72..98818047c0 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1232,6 +1232,7 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); ActivateData *data; + const GSList *active_connections, *iter; if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP) return; @@ -1245,6 +1246,15 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds if (!nm_device_autoconnect_allowed (device)) return; + /* If the device already has an activation in-progress or waiting for + * authentication, don't start an auto-activation for it. + */ + active_connections = nm_manager_get_active_connections (priv->manager); + for (iter = active_connections; iter; iter = iter->next) { + if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device) + return; + } + /* Schedule an auto-activation if there isn't one already for this device */ if (find_pending_activation (priv->pending_activation_checks, device) == NULL) { data = activate_data_new (policy, device, delay_seconds); From b3c0756f793f42eed95cc4fc183b189461c188c5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 25 Oct 2013 19:33:01 -0500 Subject: [PATCH 32/32] trivial: add logging for ActiveConnection master-ready tracking --- src/nm-active-connection.c | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index b8971b62ff..c2442d46ab 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -87,6 +87,24 @@ static void check_master_ready (NMActiveConnection *self); /****************************************************************/ +static const char * +state_to_string (NMActiveConnectionState state) +{ + switch (state) { + case NM_ACTIVE_CONNECTION_STATE_UNKNOWN: + return "unknown"; + case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: + return "activating"; + case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: + return "activated"; + case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING: + return "deactivating"; + case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: + return "deactivated"; + } + return "(none)"; +} + NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self) { @@ -376,12 +394,18 @@ check_master_ready (NMActiveConnection *self) NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) + if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (not activating)", self); return; - if (!priv->master) + } + if (!priv->master) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (no master)", self); return; - if (priv->master_ready) + } + if (priv->master_ready) { + nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (already signaled)", self); return; + } /* ActiveConnetions don't enter the ACTIVATING state until they have a * NMDevice in PREPARE or higher states, so the master active connection's @@ -389,8 +413,13 @@ check_master_ready (NMActiveConnection *self) * or higher states. */ master_state = nm_active_connection_get_state (priv->master); + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)", + self, priv->master, state_to_string (master_state), master_state); + if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + nm_log_dbg (LOGD_DEVICE, "(%p): signalling master-ready", self); + priv->master_ready = TRUE; g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY); @@ -413,9 +442,15 @@ master_state_cb (NMActiveConnection *master, check_master_ready (self); + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)", + self, master, state_to_string (master_state), master_state); + /* Master is deactivating, so this active connection must also deactivate */ if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING && master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] '%s' failed", + self, master, nm_active_connection_get_name (master)); + g_signal_handlers_disconnect_by_func (master, (GCallback) master_state_cb, self); @@ -451,6 +486,9 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m g_return_if_fail (priv->device != nm_active_connection_get_device (master)); } + nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection is [%p] %s", + self, master, nm_active_connection_get_name (master)); + priv->master = g_object_ref (master); g_signal_connect (priv->master, "notify::" NM_ACTIVE_CONNECTION_STATE,