diff options
author | Thomas Haller <thaller@redhat.com> | 2018-04-13 09:24:59 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-04-13 09:24:59 +0200 |
commit | f69dbd71fe1f714250cc865b4c2e50fcc95579d2 (patch) | |
tree | c773636a70ab4c3406683d3e1f59ebe69612c434 | |
parent | 786adf969c297fc2e830b43cc9e9b1a154d43216 (diff) | |
parent | 04a42e2748478a6f6c204f94c7c83fa2c9b8dbd9 (diff) |
core: merge branch 'th/settings-cleanup'
https://github.com/NetworkManager/NetworkManager/pull/85
28 files changed, 1247 insertions, 969 deletions
diff --git a/config.h.meson b/config.h.meson index 12b35a66b..06190aae1 100644 --- a/config.h.meson +++ b/config.h.meson @@ -214,9 +214,6 @@ /* Define if you have oFono support (experimental) */ #mesondefine WITH_OFONO -/* whether to compile polkit support */ -#mesondefine WITH_POLKIT - /* Define if you have polkit agent */ #mesondefine WITH_POLKIT_AGENT diff --git a/configure.ac b/configure.ac index a0600e1ca..c703890e1 100644 --- a/configure.ac +++ b/configure.ac @@ -629,26 +629,20 @@ AM_CONDITIONAL(WITH_JSON_VALIDATION, test "${enable_json_validation}" != "no") # we usually compile with polkit support. --enable-polkit=yes|no only sets the # default configuration for main.auth-polkit. User can always enable/disable polkit -# autorization via config. Only when specifying --enable-polkit=disabled, we do -# not compile support. In this case, the user cannot enable polkit authorization via -# configuration. +# autorization via config. AC_ARG_ENABLE(polkit, - AS_HELP_STRING([--enable-polkit=yes|no|disabled], - [set default value for auth-polkit configuration option. This value can be overwritten by NM configuration. 'disabled' compiles NM without any support]), + AS_HELP_STRING([--enable-polkit=yes|no], + [set default value for auth-polkit configuration option. This value can be overwritten by NM configuration. 'disabled' is an alias for 'no']), [enable_polkit=${enableval}], [enable_polkit=yes]) if (test "${enable_polkit}" != "no" -a "${enable_polkit}" != "disabled"); then - enable_polkit=yes + enable_polkit=true AC_DEFINE(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "true", [The default value of the auth-polkit configuration option]) AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, true) else + enable_polkit=false AC_DEFINE(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "false", [The default value of the auth-polkit configuration option]) AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, false) fi -if (test "${enable_polkit}" != "disabled"); then - AC_DEFINE(WITH_POLKIT, 1, [whether to compile polkit support]) -else - AC_DEFINE(WITH_POLKIT, 0, [whether to compile polkit support]) -fi PKG_CHECK_MODULES(POLKIT, [polkit-agent-1 >= 0.97], [have_pk_agent=yes],[have_pk_agent=no]) AC_ARG_ENABLE(polkit-agent, @@ -1341,14 +1335,10 @@ echo echo "Platform:" echo " session tracking: $session_tracking" echo " suspend/resume: $with_suspend_resume" -if test "${enable_polkit}" = "yes"; then - if test "${enable_modify_system}" = "yes"; then - echo " policykit: yes (permissive modify.system) (default: main.auth-polkit=${enable_polkit})" - else - echo " policykit: yes (restrictive modify.system) (default: main.auth-polkit=${enable_polkit})" - fi +if test "${enable_modify_system}" = "yes"; then + echo " policykit: main.auth-polkit=${enable_polkit} (permissive modify.system)" else - echo " policykit: no" + echo " policykit: main.auth-polkit=${enable_polkit} (restrictive modify.system)" fi echo " polkit agent: ${enable_polkit_agent}" echo " selinux: $have_selinux" diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c index 11700666f..f06e1aed4 100644 --- a/libnm-core/nm-simple-connection.c +++ b/libnm-core/nm-simple-connection.c @@ -113,11 +113,16 @@ NMConnection * nm_simple_connection_new_clone (NMConnection *connection) { NMConnection *clone; + const char *path; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); clone = nm_simple_connection_new (); - nm_connection_set_path (clone, nm_connection_get_path (connection)); + + path = nm_connection_get_path (connection); + if (path) + nm_connection_set_path (clone, path); + nm_connection_replace_settings_from_connection (clone, connection); return clone; diff --git a/meson.build b/meson.build index 5f29c16a6..17ddbc4a5 100644 --- a/meson.build +++ b/meson.build @@ -448,7 +448,6 @@ endif config_default_main_auth_polkit = (polkit == 'yes').to_string() config_h.set_quoted('NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT', config_default_main_auth_polkit) -config_h.set10('WITH_POLKIT', enable_polkit) enable_modify_system = get_option('modify_system') diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c0540534e..882e9a86d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -256,7 +256,7 @@ typedef struct _NMDevicePrivate { GSList *pending_actions; GSList *dad6_failed_addrs; - NMDevice *parent_device; + NMDBusTrackObjPath parent_device; char * udi; char * iface; /* may change, could be renamed by user */ @@ -321,9 +321,7 @@ typedef struct _NMDevicePrivate { NMActRequest * queued_act_request; bool queued_act_request_is_waiting_for_carrier:1; - bool act_request_public:1; - NMActRequest *act_request; - gulong act_request_id; + NMDBusTrackObjPath act_request; ActivationHandleData act_handle4; /* for layer2 and IPv4. */ ActivationHandleData act_handle6; guint recheck_assume_id; @@ -1514,12 +1512,9 @@ nm_device_parent_get_ifindex (NMDevice *self) NMDevice * nm_device_parent_get_device (NMDevice *self) { - NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - priv = NM_DEVICE_GET_PRIVATE (self); - return priv->parent_device; + return NM_DEVICE_GET_PRIVATE (self)->parent_device.obj; } static void @@ -1541,7 +1536,7 @@ _parent_set_ifindex (NMDevice *self, NMDevice *parent_device; gboolean changed = FALSE; int old_ifindex; - NMDevice *old_device; + gs_unref_object NMDevice *old_device = NULL; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); @@ -1551,16 +1546,15 @@ _parent_set_ifindex (NMDevice *self, parent_ifindex = 0; old_ifindex = priv->parent_ifindex; - old_device = priv->parent_device; if (priv->parent_ifindex == parent_ifindex) { if (parent_ifindex > 0) { if ( !force_check - && priv->parent_device - && nm_device_get_ifindex (priv->parent_device) == parent_ifindex) + && priv->parent_device.obj + && nm_device_get_ifindex (priv->parent_device.obj) == parent_ifindex) return FALSE; } else { - if (!priv->parent_device) + if (!priv->parent_device.obj) return FALSE; } } else { @@ -1575,24 +1569,23 @@ _parent_set_ifindex (NMDevice *self, } else parent_device = NULL; - if (parent_device != priv->parent_device) { - priv->parent_device = parent_device; + if (parent_device != priv->parent_device.obj) { + old_device = nm_g_object_ref (priv->parent_device.obj); + nm_dbus_track_obj_path_set (&priv->parent_device, parent_device, TRUE); changed = TRUE; } if (changed) { if (priv->parent_ifindex <= 0) _LOGD (LOGD_DEVICE, "parent: clear"); - else if (!priv->parent_device) + else if (!priv->parent_device.obj) _LOGD (LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); else { _LOGD (LOGD_DEVICE, "parent: ifindex %d, device %p, %s", priv->parent_ifindex, - priv->parent_device, nm_device_get_iface (priv->parent_device)); + priv->parent_device.obj, nm_device_get_iface (priv->parent_device.obj)); } - NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device); - - _notify (self, PROP_PARENT); + NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device.obj); } return changed; } @@ -1617,7 +1610,7 @@ nm_device_parent_notify_changed (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); if (priv->parent_ifindex > 0) { - if ( priv->parent_device == change_candidate + if ( priv->parent_device.obj == change_candidate || priv->parent_ifindex == nm_device_get_ifindex (change_candidate)) return _parent_set_ifindex (self, priv->parent_ifindex, device_removed); } @@ -2164,7 +2157,7 @@ nm_device_get_act_request (NMDevice *self) { g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->act_request; + return NM_DEVICE_GET_PRIVATE (self)->act_request.obj; } NMSettingsConnection * @@ -2172,7 +2165,7 @@ nm_device_get_settings_connection (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - return priv->act_request ? nm_act_request_get_settings_connection (priv->act_request) : NULL; + return priv->act_request.obj ? nm_act_request_get_settings_connection (priv->act_request.obj) : NULL; } NMConnection * @@ -2184,7 +2177,7 @@ nm_device_get_applied_connection (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); - return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL; + return priv->act_request.obj ? nm_act_request_get_applied_connection (priv->act_request.obj) : NULL; } gboolean @@ -2192,10 +2185,10 @@ nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFla { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (!priv->act_request) + if (!priv->act_request.obj) return FALSE; - return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request, compare_flags); + return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request.obj, compare_flags); } NMSetting * @@ -4533,7 +4526,7 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the * master to enslave us. */ - if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request)) + if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request.obj)) && !priv->is_enslaved) return; @@ -5726,8 +5719,9 @@ activate_stage1_device_prepare (NMDevice *self) _set_ip_state (self, AF_INET6, IP_NONE); /* Notify the new ActiveConnection along with the state change */ - priv->act_request_public = TRUE; - _notify (self, PROP_ACTIVE_CONNECTION); + nm_dbus_track_obj_path_set (&priv->act_request, + priv->act_request.obj, + TRUE); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); @@ -5763,7 +5757,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); } @@ -5940,7 +5934,7 @@ activate_stage2_device_config (NMDevice *self) if (slave_state == NM_DEVICE_STATE_IP_CONFIG) nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave)); - else if ( priv->act_request + else if ( priv->act_request.obj && nm_device_sys_iface_state_is_external (self) && slave_state <= NM_DEVICE_STATE_DISCONNECTED) nm_device_queue_recheck_assume (info->slave); @@ -5965,10 +5959,10 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); if (!priv->master_ready_handled) { - NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); + NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request.obj); NMActiveConnection *master; master = nm_active_connection_get_master (active); @@ -6256,10 +6250,10 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) NMIP4Config *config; int r; - if (priv->act_request == NULL) + if (priv->act_request.obj == NULL) return; - connection = nm_act_request_get_applied_connection (priv->act_request); + connection = nm_act_request_get_applied_connection (priv->act_request.obj); g_assert (connection); /* Ignore if the connection isn't an AutoIP connection */ @@ -8179,7 +8173,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); guint i; - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); if (!applied_config_get_current (&priv->ac_ip6_config)) applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); @@ -8991,7 +8985,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); /* Add the interface to the specified firewall zone */ if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { @@ -9063,7 +9057,7 @@ nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); activation_source_schedule (self, activate_stage4_ip4_config_timeout, AF_INET); } @@ -9119,7 +9113,7 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); + g_return_if_fail (priv->act_request.obj); activation_source_schedule (self, activate_stage4_ip6_config_timeout, AF_INET6); } @@ -9577,43 +9571,26 @@ nm_device_activate_ip6_state_done (NMDevice *self) /*****************************************************************************/ static void -act_request_set_cb (NMActRequest *act_request, - GParamSpec *pspec, - NMDevice *self) -{ - _notify (self, PROP_ACTIVE_CONNECTION); -} - -static void act_request_set (NMDevice *self, NMActRequest *act_request) { NMDevicePrivate *priv; - gs_unref_object NMActRequest *old_act_requst = NULL; nm_assert (NM_IS_DEVICE (self)); nm_assert (!act_request || NM_IS_ACT_REQUEST (act_request)); priv = NM_DEVICE_GET_PRIVATE (self); - if ( !priv->act_request_public - && priv->act_request == act_request) + if ( !priv->act_request.visible + && priv->act_request.obj == act_request) return; /* always clear the public flag. The few callers that set a new @act_request * don't want that the property is public yet. */ - priv->act_request_public = FALSE; - - nm_clear_g_signal_handler (priv->act_request, &priv->act_request_id); - - old_act_requst = priv->act_request; - priv->act_request = nm_g_object_ref (act_request); + nm_dbus_track_obj_path_set (&priv->act_request, + act_request, + FALSE); if (act_request) { - priv->act_request_id = g_signal_connect (act_request, - "notify::"NM_DBUS_OBJECT_PATH, - G_CALLBACK (act_request_set_cb), - self); - switch (nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request))) { case NM_ACTIVATION_TYPE_EXTERNAL: break; @@ -9630,8 +9607,6 @@ act_request_set (NMDevice *self, NMActRequest *act_request) break; } } - - _notify (self, PROP_ACTIVE_CONNECTION); } static void @@ -10096,7 +10071,7 @@ check_and_reapply_connection (NMDevice *self, } if ( version_id != 0 - && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request)) { + && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH, @@ -10109,10 +10084,10 @@ check_and_reapply_connection (NMDevice *self, *************************************************************************/ if (diffs) - nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request); + nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request.obj); _LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)", - (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request)), + (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request.obj)), diffs ? "" : " (unmodified)"); if (diffs) { @@ -10362,7 +10337,7 @@ get_applied_connection_cb (NMDevice *self, g_dbus_method_invocation_return_value (context, g_variant_new ("(@a{sa{sv}}t)", settings, - nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request))); + nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj))); } static void @@ -10560,7 +10535,7 @@ impl_device_disconnect (NMDBusObject *obj, NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; - if (!priv->act_request) { + if (!priv->act_request.obj) { g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, @@ -10748,8 +10723,8 @@ nm_device_steal_connection (NMDevice *self, NMSettingsConnection *connection) && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) _clear_queued_act_request (priv); - if ( priv->act_request - && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request)) + if ( priv->act_request.obj + && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request.obj)) && priv->state < NM_DEVICE_STATE_DEACTIVATING) { nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -10765,7 +10740,7 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) must_queue = _carrier_wait_check_act_request_must_queue (self, req); - if ( !priv->act_request + if ( !priv->act_request.obj && !must_queue && nm_device_is_real (self)) { _device_activate (self, req); @@ -10780,7 +10755,7 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) _LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect"); /* Deactivate existing activation request first */ - if (priv->act_request) { + if (priv->act_request.obj) { _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -10995,7 +10970,7 @@ nm_device_set_ip_config (NMDevice *self, && (settings_connection = nm_device_get_settings_connection (self)) && NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED) - && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request)) == NM_ACTIVATION_TYPE_EXTERNAL) { + && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request.obj)) == NM_ACTIVATION_TYPE_EXTERNAL) { g_object_freeze_notify (G_OBJECT (settings_connection)); nm_connection_add_setting (NM_CONNECTION (settings_connection), IS_IPv4 @@ -12470,7 +12445,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), nm_setting_connection_get_zone (s_con_applied)) != 0) { - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), @@ -12482,7 +12457,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request); + version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (unsigned long long) version_id); g_object_set (G_OBJECT (s_con_applied), @@ -12841,19 +12816,19 @@ cp_connection_added_or_updated (NMDevice *self, NMConnection *connection) } static void -cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) +cp_connection_added (NMSettings *settings, NMConnection *connection, gpointer user_data) { cp_connection_added_or_updated (user_data, connection); } static void -cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gboolean by_user, gpointer user_data) +cp_connection_updated (NMSettings *settings, NMConnection *connection, gboolean by_user, gpointer user_data) { cp_connection_added_or_updated (user_data, connection); } static void -cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) +cp_connection_removed (NMSettings *settings, NMConnection *connection, gpointer user_data) { NMDevice *self = user_data; @@ -13088,11 +13063,11 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) * above disables them. */ nm_assert (priv->needs_ip6_subnet == FALSE); - if (priv->act_request) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), AF_INET, FALSE); + if (priv->act_request.obj) { + nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request.obj), AF_INET, FALSE); priv->master_ready_handled = FALSE; - nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id); + nm_clear_g_signal_handler (priv->act_request.obj, &priv->master_ready_id); act_request_set (self, NULL); } @@ -13544,7 +13519,7 @@ _set_state_full (NMDevice *self, g_cancellable_cancel (priv->deactivating_cancellable); /* Cache the activation request for the dispatcher */ - req = nm_g_object_ref (priv->act_request); + req = nm_g_object_ref (priv->act_request.obj); if ( state > NM_DEVICE_STATE_UNMANAGED && state <= NM_DEVICE_STATE_ACTIVATED @@ -14792,6 +14767,9 @@ nm_device_init (NMDevice *self) priv->connectivity_state = NM_CONNECTIVITY_UNKNOWN; + nm_dbus_track_obj_path_init (&priv->parent_device, G_OBJECT (self), obj_properties[PROP_PARENT]); + nm_dbus_track_obj_path_init (&priv->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]); + priv->netns = g_object_ref (NM_NETNS_GET); priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT @@ -15030,6 +15008,9 @@ finalize (GObject *object) g_hash_table_unref (priv->ip6_saved_properties); g_hash_table_unref (priv->available_connections); + nm_dbus_track_obj_path_deinit (&priv->parent_device); + nm_dbus_track_obj_path_deinit (&priv->act_request); + G_OBJECT_CLASS (nm_device_parent_class)->finalize (object); /* for testing, NMDeviceTest does not invoke NMDevice::constructed, @@ -15146,9 +15127,6 @@ get_property (GObject *object, guint prop_id, { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GPtrArray *array; - GHashTableIter iter; - NMConnection *connection; GVariantBuilder array_builder; switch (prop_id) { @@ -15223,7 +15201,7 @@ get_property (GObject *object, guint prop_id, g_variant_new ("(uu)", priv->state, priv->state_reason)); break; case PROP_ACTIVE_CONNECTION: - nm_dbus_utils_g_value_set_object_path (value, priv->act_request_public ? priv->act_request : NULL); + g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->act_request)); break; case PROP_DEVICE_TYPE: g_value_set_uint (value, priv->type); @@ -15254,12 +15232,9 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->rfkill_type); break; case PROP_AVAILABLE_CONNECTIONS: - array = g_ptr_array_sized_new (g_hash_table_size (priv->available_connections)); - g_hash_table_iter_init (&iter, priv->available_connections); - while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) - g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection))); - g_ptr_array_add (array, NULL); - g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); + nm_dbus_utils_g_value_set_object_path_from_hash (value, + priv->available_connections, + TRUE); break; case PROP_PHYSICAL_PORT_ID: g_value_set_string (value, priv->physical_port_id); @@ -15268,7 +15243,7 @@ get_property (GObject *object, guint prop_id, g_value_set_object (value, nm_device_get_master (self)); break; case PROP_PARENT: - nm_dbus_utils_g_value_set_object_path (value, priv->parent_device); + g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->parent_device)); break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->hw_addr); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 88074e230..4f6033893 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -28,12 +28,15 @@ #include "settings/nm-settings-connection.h" #include "nm-simple-connection.h" #include "nm-auth-utils.h" +#include "nm-auth-manager.h" #include "nm-auth-subject.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" +#define AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED ((NMAuthManagerCallId *) GINT_TO_POINTER (1)) + typedef struct _NMActiveConnectionPrivate { - NMSettingsConnection *settings_connection; + NMDBusTrackObjPath settings_connection; NMConnection *applied_connection; char *specific_object; NMDevice *device; @@ -59,11 +62,15 @@ typedef struct _NMActiveConnectionPrivate { NMActiveConnection *parent; - NMAuthChain *chain; - const char *wifi_shared_permission; - NMActiveConnectionAuthResultFunc result_func; - gpointer user_data1; - gpointer user_data2; + struct { + NMAuthManagerCallId *call_id_network_control; + NMAuthManagerCallId *call_id_wifi_shared_permission; + + NMActiveConnectionAuthResultFunc result_func; + gpointer user_data1; + gpointer user_data2; + } auth; + } NMActiveConnectionPrivate; NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection, @@ -184,40 +191,24 @@ _settings_connection_updated (NMSettingsConnection *connection, } static void -_settings_connection_removed (NMSettingsConnection *connection, - gpointer user_data) -{ - NMActiveConnection *self = user_data; - - /* Our settings connection is about to drop off. The next active connection - * cleanup is going to tear us down (at least until we grow the capability to - * re-link; in that case we'd just clean the references to the old connection here). - * Let's remove ourselves from the bus so that we're not exposed with a dangling - * reference to the setting connection once it's gone. */ - if (nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))) - nm_dbus_object_unexport (NM_DBUS_OBJECT (self)); -} - -static void _set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connection) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->settings_connection == connection) + if (priv->settings_connection.obj == connection) return; - if (priv->settings_connection) { - g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_updated, self); - g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_removed, self); - g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self); - g_clear_object (&priv->settings_connection); + + if (priv->settings_connection.obj) { + g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_updated, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_notify_flags, self); } if (connection) { - priv->settings_connection = g_object_ref (connection); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, (GCallback) _settings_connection_removed, self); if (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL) g_signal_connect (connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); } + + nm_dbus_track_obj_path_set (&priv->settings_connection, connection, TRUE); } NMActiveConnectionState @@ -275,7 +266,7 @@ nm_active_connection_set_state (NMActiveConnection *self, if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - nm_settings_connection_update_timestamp (priv->settings_connection, + nm_settings_connection_update_timestamp (priv->settings_connection.obj, (guint64) time (NULL), TRUE); } @@ -371,7 +362,7 @@ nm_active_connection_get_settings_connection_id (NMActiveConnection *self) g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; + con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; return con ? nm_connection_get_id (NM_CONNECTION (con)) : NULL; @@ -382,7 +373,7 @@ _nm_active_connection_get_settings_connection (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; } NMSettingsConnection * @@ -456,7 +447,7 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (!priv->settings_connection); + g_return_if_fail (!priv->settings_connection.obj); g_return_if_fail (!priv->applied_connection); /* Can't change connection after the ActiveConnection is exported over D-Bus. @@ -471,7 +462,7 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, _set_settings_connection (self, connection); _set_applied_connection_take (self, - nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection))); + nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj))); } gboolean @@ -483,9 +474,9 @@ nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - g_return_val_if_fail (priv->settings_connection, FALSE); + g_return_val_if_fail (priv->settings_connection.obj, FALSE); - return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, + return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj, priv->applied_connection, compare_flags); } @@ -501,10 +492,10 @@ nm_active_connection_clear_secrets (NMActiveConnection *self) priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, + if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj, priv->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) - nm_connection_clear_secrets ((NMConnection *) priv->settings_connection); + nm_connection_clear_secrets ((NMConnection *) priv->settings_connection.obj); nm_connection_clear_secrets (priv->applied_connection); } @@ -864,11 +855,11 @@ _set_activation_type (NMActiveConnection *self, priv->activation_type = activation_type; - if (priv->settings_connection) { + if (priv->settings_connection.obj) { if (activation_type == NM_ACTIVATION_TYPE_EXTERNAL) - g_signal_connect (priv->settings_connection, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); + g_signal_connect (priv->settings_connection.obj, "notify::"NM_SETTINGS_CONNECTION_FLAGS, (GCallback) _settings_connection_notify_flags, self); else - g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_notify_flags, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_notify_flags, self); } } @@ -914,7 +905,7 @@ _settings_connection_notify_flags (NMSettingsConnection *settings_connection, nm_assert (NM_IS_ACTIVE_CONNECTION (self)); nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection)); nm_assert (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL); - nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection == settings_connection); + nm_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj == settings_connection); if (NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED)) @@ -997,62 +988,93 @@ nm_active_connection_set_parent (NMActiveConnection *self, NMActiveConnection *p /*****************************************************************************/ static void -auth_done (NMAuthChain *chain, +auth_cancel (NMActiveConnection *self) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + if (priv->auth.call_id_network_control) + nm_auth_manager_check_authorization_cancel (priv->auth.call_id_network_control); + if (priv->auth.call_id_wifi_shared_permission) { + if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED) + priv->auth.call_id_wifi_shared_permission = NULL; + else + nm_auth_manager_check_authorization_cancel (priv->auth.call_id_wifi_shared_permission); + } + priv->auth.result_func = NULL; + priv->auth.user_data1 = NULL; + priv->auth.user_data2 = NULL; +} + +static void +auth_complete (NMActiveConnection *self, gboolean result, const char *message) +{ + _nm_unused gs_unref_object NMActiveConnection *self_keep_alive = g_object_ref (self); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + priv->auth.result_func (self, + result, + message, + priv->auth.user_data1, + priv->auth.user_data2); + auth_cancel (self); +} + +static void +auth_done (NMAuthManager *auth_mgr, + NMAuthManagerCallId *auth_call_id, + gboolean is_authorized, + gboolean is_challenge, GError *error, - GDBusMethodInvocation *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); + nm_assert (auth_call_id); + nm_assert (priv->auth.result_func); - if (error) { - priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2); - goto done; + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + if (auth_call_id == priv->auth.call_id_network_control) + priv->auth.call_id_network_control = NULL; + else { + nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission); + priv->auth.call_id_wifi_shared_permission = NULL; + } + return; } - /* 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; - } + result = nm_auth_call_result_eval (is_authorized, is_challenge, error); - if (priv->wifi_shared_permission) { - result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission); + if (auth_call_id == priv->auth.call_id_network_control) { + priv->auth.call_id_network_control = NULL; 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; + auth_complete (self, FALSE, "Not authorized to control networking."); + return; } + } else { + nm_assert (auth_call_id == priv->auth.call_id_wifi_shared_permission); + if (result != NM_AUTH_CALL_RESULT_YES) { + /* we don't fail right away. Instead, we mark that wifi-shared-permissions + * are missing. We prefer to report the failure about network-control. + * Below, we will wait longer for call_id_network_control (if it's still + * pending). */ + priv->auth.call_id_wifi_shared_permission = AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED; + } else + priv->auth.call_id_wifi_shared_permission = NULL; } - /* Otherwise authorized and available to activate */ - priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2); + if (priv->auth.call_id_network_control) + return; -done: - nm_auth_chain_unref (chain); - priv->chain = NULL; - priv->result_func = NULL; - priv->user_data1 = NULL; - priv->user_data2 = NULL; + if (priv->auth.call_id_wifi_shared_permission) { + if (priv->auth.call_id_wifi_shared_permission == AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED) + auth_complete (self, FALSE, "Not authorized to share connections via wifi."); + return; + } - g_object_unref (self); + auth_complete (self, TRUE, NULL); } /** @@ -1080,37 +1102,43 @@ nm_active_connection_authorize (NMActiveConnection *self, const char *wifi_permission = NULL; NMConnection *con; - g_return_if_fail (result_func != NULL); - g_return_if_fail (priv->chain == NULL); + g_return_if_fail (result_func); + g_return_if_fail (!priv->auth.call_id_network_control); + nm_assert (!priv->auth.call_id_wifi_shared_permission); if (initial_connection) { g_return_if_fail (NM_IS_CONNECTION (initial_connection)); - g_return_if_fail (!priv->settings_connection); + g_return_if_fail (!priv->settings_connection.obj); g_return_if_fail (!priv->applied_connection); con = initial_connection; } else { - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection)); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection.obj)); g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection)); con = priv->applied_connection; } - 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); + priv->auth.call_id_network_control = nm_auth_manager_check_authorization (nm_auth_manager_get (), + priv->subject, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + auth_done, + self); /* Shared wifi connections require special permissions too */ wifi_permission = nm_utils_get_shared_wifi_permission (con); if (wifi_permission) { - priv->wifi_shared_permission = wifi_permission; - nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE); + priv->auth.call_id_wifi_shared_permission = nm_auth_manager_check_authorization (nm_auth_manager_get (), + priv->subject, + wifi_permission, + TRUE, + auth_done, + self); } /* Wait for authorization */ - priv->result_func = result_func; - priv->user_data1 = user_data1; - priv->user_data2 = user_data2; + priv->auth.result_func = result_func; + priv->auth.user_data1 = user_data1; + priv->auth.user_data2 = user_data2; } /*****************************************************************************/ @@ -1172,31 +1200,40 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE ((NMActiveConnection *) object); - GPtrArray *devices; + char **strv; NMDevice *master_device = NULL; switch (prop_id) { + + /* note that while priv->settings_connection.obj might not be set initially, + * it will be set before the object is exported on D-Bus. Hence, + * nobody is calling these property getters before the object is + * exported, at which point we will have a valid settings-connection. + * + * Therefore, intentionally not check whether priv->settings_connection.obj + * is set, to get an assertion failure if somebody tries to access the + * getters at the wrong time. */ case PROP_CONNECTION: - g_value_set_string (value, nm_connection_get_path (NM_CONNECTION (priv->settings_connection))); + g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->settings_connection)); break; case PROP_ID: - g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection))); + g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection.obj))); break; case PROP_UUID: - g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection))); + g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection.obj))); break; case PROP_TYPE: - g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection))); + g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection.obj))); break; + case PROP_SPECIFIC_OBJECT: g_value_set_string (value, priv->specific_object ? priv->specific_object : "/"); break; case PROP_DEVICES: - devices = g_ptr_array_sized_new (2); + strv = g_new0 (char *, 2); if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) - g_ptr_array_add (devices, g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (priv->device)))); - g_ptr_array_add (devices, NULL); - g_value_take_boxed (value, (char **) g_ptr_array_free (devices, FALSE)); + strv[0] = g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (priv->device))); + g_value_take_boxed (value, strv); break; case PROP_STATE: if (priv->state_set) @@ -1342,6 +1379,10 @@ nm_active_connection_init (NMActiveConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate); self->_priv = priv; + nm_dbus_track_obj_path_init (&priv->settings_connection, + G_OBJECT (self), + obj_properties[PROP_CONNECTION]); + c_list_init (&self->active_connections_lst); _LOGT ("creating"); @@ -1359,8 +1400,8 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); if ( !priv->applied_connection - && priv->settings_connection) - priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection)); + && priv->settings_connection.obj) + priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj)); _LOGD ("constructed (%s, version-id %llu, type %s)", G_OBJECT_TYPE_NAME (self), @@ -1390,10 +1431,7 @@ dispose (GObject *object) _LOGD ("disposing"); - if (priv->chain) { - nm_auth_chain_unref (priv->chain); - priv->chain = NULL; - } + auth_cancel (self); g_free (priv->specific_object); priv->specific_object = NULL; @@ -1418,6 +1456,17 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object); } +static void +finalize (GObject *object) +{ + NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + nm_dbus_track_obj_path_set (&priv->settings_connection, NULL, FALSE); + + G_OBJECT_CLASS (nm_active_connection_parent_class)->finalize (object); +} + static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( "StateChanged", .args = NM_DEFINE_GDBUS_ARG_INFOS ( @@ -1470,6 +1519,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; + object_class->finalize = finalize; obj_properties[PROP_CONNECTION] = g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "", diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 003d99750..6a8214c82 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -22,6 +22,7 @@ #include "nm-auth-manager.h" +#include "nm-utils/c-list.h" #include "nm-errors.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" @@ -30,6 +31,9 @@ #define POLKIT_OBJECT_PATH "/org/freedesktop/PolicyKit1/Authority" #define POLKIT_INTERFACE "org.freedesktop.PolicyKit1.Authority" +#define CANCELLATION_ID_PREFIX "cancellation-id-" +#define CANCELLATION_TIMEOUT_MS 5000 + /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( @@ -44,13 +48,14 @@ enum { static guint signals[LAST_SIGNAL] = {0}; typedef struct { - gboolean polkit_enabled; -#if WITH_POLKIT - guint call_id_counter; - GCancellable *new_proxy_cancellable; - GSList *queued_calls; + CList calls_lst_head; GDBusProxy *proxy; -#endif + GCancellable *new_proxy_cancellable; + GCancellable *cancel_cancellable; + guint64 call_numid_counter; + bool polkit_enabled:1; + bool disposing:1; + bool shutting_down:1; } NMAuthManagerPrivate; struct _NMAuthManager { @@ -85,6 +90,22 @@ NM_DEFINE_SINGLETON_REGISTER (NMAuthManager); } \ } G_STMT_END +#define _NMLOG2(level, call_id, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + NMAuthManagerCallId *_call_id = (call_id); \ + char __prefix[30] = _NMLOG_PREFIX_NAME; \ + \ + if (_call_id->self != singleton_instance) \ + g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", _call_id->self); \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \ + "%s: call[%"G_GUINT64_FORMAT"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix, \ + _call_id->call_numid \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END + /*****************************************************************************/ gboolean @@ -97,251 +118,323 @@ nm_auth_manager_get_polkit_enabled (NMAuthManager *self) /*****************************************************************************/ -#if WITH_POLKIT - typedef enum { POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0), } PolkitCheckAuthorizationFlags; -typedef struct { - guint call_id; +typedef enum { + IDLE_REASON_AUTHORIZED, + IDLE_REASON_NO_DBUS, +} IdleReason; + +struct _NMAuthManagerCallId { + CList calls_lst; NMAuthManager *self; - GSimpleAsyncResult *simple; - gchar *cancellation_id; GVariant *dbus_parameters; - GCancellable *cancellable; -} CheckAuthData; + GCancellable *dbus_cancellable; + NMAuthManagerCheckAuthorizationCallback callback; + gpointer user_data; + guint64 call_numid; + guint idle_id; + IdleReason idle_reason:8; +}; + +#define cancellation_id_to_str_a(call_numid) \ + nm_sprintf_bufa (NM_STRLEN (CANCELLATION_ID_PREFIX) + 20, \ + CANCELLATION_ID_PREFIX"%"G_GUINT64_FORMAT, \ + (call_numid)) static void -_check_auth_data_free (CheckAuthData *data) +_call_id_free (NMAuthManagerCallId *call_id) { - if (data->dbus_parameters) - g_variant_unref (data->dbus_parameters); - g_object_unref (data->self); - g_object_unref (data->simple); - g_clear_object (&data->cancellable); - g_free (data->cancellation_id); - g_free (data); + c_list_unlink (&call_id->calls_lst); + nm_clear_g_source (&call_id->idle_id); + if (call_id->dbus_parameters) + g_variant_unref (g_steal_pointer (&call_id->dbus_parameters)); + + if (call_id->dbus_cancellable) { + /* we have a pending D-Bus call. We keep the call-id instance alive + * for _call_check_authorize_cb() */ + g_cancellable_cancel (call_id->dbus_cancellable); + return; + } + + g_object_unref (call_id->self); + g_slice_free (NMAuthManagerCallId, call_id); } static void -_call_check_authorization_complete_with_error (CheckAuthData *data, - const char *error_message) +_call_id_invoke_callback (NMAuthManagerCallId *call_id, + gboolean is_authorized, + gboolean is_challenge, + GError *error) { - NMAuthManager *self = data->self; - - _LOGD ("call[%u]: CheckAuthorization failed due to internal error: %s", data->call_id, error_message); - g_simple_async_result_set_error (data->simple, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Authorization check failed: %s", - error_message); - - g_simple_async_result_complete_in_idle (data->simple); - - _check_auth_data_free (data); + c_list_unlink (&call_id->calls_lst); + + call_id->callback (call_id->self, + call_id, + is_authorized, + is_challenge, + error, + call_id->user_data); + _call_id_free (call_id); } static void -cancel_check_authorization_cb (GDBusProxy *proxy, +cancel_check_authorization_cb (GObject *proxy, GAsyncResult *res, gpointer user_data) { - NMAuthManager *self = user_data; - GVariant *value; - GError *error= NULL; - - value = g_dbus_proxy_call_finish (proxy, res, &error); - if (value == NULL) { - g_dbus_error_strip_remote_error (error); - _LOGD ("Error cancelling authorization check: %s", error->message); - g_error_free (error); - } else - g_variant_unref (value); + NMAuthManagerCallId *call_id = user_data; + gs_unref_variant GVariant *value = NULL; + gs_free_error GError *error= NULL; + + value = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _LOG2T (call_id, "cancel request was cancelled"); + else if (error) + _LOG2T (call_id, "cancel request failed: %s", error->message); + else + _LOG2T (call_id, "cancel request succeeded"); - g_object_unref (self); + _call_id_free (call_id); } -typedef struct { - gboolean is_authorized; - gboolean is_challenge; -} CheckAuthorizationResult; - static void -check_authorization_cb (GDBusProxy *proxy, - GAsyncResult *res, - gpointer user_data) +_call_check_authorize_cb (GObject *proxy, + GAsyncResult *res, + gpointer user_data) { - CheckAuthData *data = user_data; - NMAuthManager *self = data->self; - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - GVariant *value; - GError *error = NULL; - - value = _nm_dbus_proxy_call_finish (proxy, res, G_VARIANT_TYPE ("((bba{ss}))"), &error); - if (value == NULL) { - if (data->cancellation_id != NULL && - ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) - && !g_dbus_error_is_remote_error (error))) { - _LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id); - g_dbus_proxy_call (priv->proxy, - "CancelCheckAuthorization", - g_variant_new ("(s)", data->cancellation_id), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* GCancellable */ - (GAsyncReadyCallback) cancel_check_authorization_cb, - g_object_ref (self)); - } else - _LOGD ("call[%u]: CheckAuthorization failed: %s", data->call_id, error->message); - g_dbus_error_strip_remote_error (error); - g_simple_async_result_set_error (data->simple, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Authorization check failed: %s", - error->message); - g_error_free (error); - } else { - CheckAuthorizationResult *result; + NMAuthManagerCallId *call_id = user_data; + NMAuthManager *self; + NMAuthManagerPrivate *priv; + gs_unref_variant GVariant *value = NULL; + gs_free_error GError *error = NULL; + gboolean is_authorized = FALSE; + gboolean is_challenge = FALSE; - result = g_new0 (CheckAuthorizationResult, 1); + /* we need to clear the cancelable, to signal for _call_id_free() that we + * are not in a pending call. + * + * Note how _call_id_free() kept call-id alive, even if the request was + * already cancelled. */ + g_clear_object (&call_id->dbus_cancellable); - g_variant_get (value, - "((bb@a{ss}))", - &result->is_authorized, - &result->is_challenge, - NULL); - g_variant_unref (value); + self = call_id->self; + priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - _LOGD ("call[%u]: CheckAuthorization succeeded: (is_authorized=%d, is_challenge=%d)", data->call_id, result->is_authorized, result->is_challenge); - g_simple_async_result_set_op_res_gpointer (data->simple, result, g_free); + value = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, G_VARIANT_TYPE ("((bba{ss}))"), &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* call_id was cancelled externally, but _call_id_free() kept call_id + * alive (and it has still the reference on @self. */ + + if (!priv->cancel_cancellable) { + /* we do a forced shutdown. There is no more time for cancelling... */ + _call_id_free (call_id); + + /* this shouldn't really happen, because: + * _call_check_authorize() only scheduled the D-Bus request at a time when + * cancel_cancellable was still set. It means, somebody called force-shutdown + * after call-id was schedule. + * force-shutdown should only be called after: + * - cancel all pending requests + * - give enough time to cancel the request and schedule a D-Bus call + * to CancelCheckAuthorization (below), before issuing force-shutdown. */ + g_return_if_reached (); + } + + g_dbus_proxy_call (priv->proxy, + "CancelCheckAuthorization", + g_variant_new ("(s)", + cancellation_id_to_str_a (call_id->call_numid)), + G_DBUS_CALL_FLAGS_NONE, + CANCELLATION_TIMEOUT_MS, + priv->cancel_cancellable, + cancel_check_authorization_cb, + call_id); + return; } - g_simple_async_result_complete (data->simple); + if (!error) { + g_variant_get (value, + "((bb@a{ss}))", + &is_authorized, + &is_challenge, + NULL); + _LOG2T (call_id, "completed: authorized=%d, challenge=%d", + is_authorized, is_challenge); + } else + _LOG2T (call_id, "completed: failed: %s", error->message); - _check_auth_data_free (data); + _call_id_invoke_callback (call_id, is_authorized, is_challenge, error); } static void -_call_check_authorization (CheckAuthData *data) +_call_check_authorize (NMAuthManagerCallId *call_id) { - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (data->self); + NMAuthManager *self = call_id->self; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + + nm_assert (call_id->dbus_parameters); + nm_assert (g_variant_is_floating (call_id->dbus_parameters)); + nm_assert (!call_id->dbus_cancellable); + + call_id->dbus_cancellable = g_cancellable_new (); + + nm_assert (priv->cancel_cancellable); g_dbus_proxy_call (priv->proxy, "CheckAuthorization", - data->dbus_parameters, + g_steal_pointer (&call_id->dbus_parameters), G_DBUS_CALL_FLAGS_NONE, G_MAXINT, /* no timeout */ - data->cancellable, - (GAsyncReadyCallback) check_authorization_cb, - data); - g_clear_object (&data->cancellable); - data->dbus_parameters = NULL; + call_id->dbus_cancellable, + _call_check_authorize_cb, + call_id); } -void -nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self, - NMAuthSubject *subject, - const char *action_id, - gboolean allow_user_interaction, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static gboolean +_call_on_idle (gpointer user_data) +{ + NMAuthManagerCallId *call_id = user_data; + gs_free_error GError *error = NULL; + gboolean is_authorized = FALSE; + gboolean is_challenge = FALSE; + const char *error_msg = NULL; + + call_id->idle_id = 0; + if (call_id->idle_reason == IDLE_REASON_AUTHORIZED) { + is_authorized = TRUE; + _LOG2T (call_id, "completed: authorized=%d, challenge=%d (simulated)", + is_authorized, is_challenge); + } else { + nm_assert (call_id->idle_reason == IDLE_REASON_NO_DBUS); + error_msg = "failure creating GDBusProxy for authorization request"; + _LOG2T (call_id, "completed: failed due to no D-Bus proxy"); + } + + if (error_msg) + g_set_error_literal (&error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, error_msg); + _call_id_invoke_callback (call_id, is_authorized, is_challenge, error); + return G_SOURCE_REMOVE; +} + +/* + * @callback must never be invoked synchronously. + * + * @callback is always invoked exactly once, and never synchronously. + * You may cancel the invocation with nm_auth_manager_check_authorization_cancel(), + * but: you may only do so exactly once, and only before @callback is + * invoked. Even if you cancel the request, @callback will still be invoked + * (synchronously, during the _cancel() callback). + * + * The request keeps @self alive (it needs to do so, because when cancelling a + * request we might need to do an additional CancelCheckAuthorization call, for + * which @self must be live long enough). + */ +NMAuthManagerCallId * +nm_auth_manager_check_authorization (NMAuthManager *self, + NMAuthSubject *subject, + const char *action_id, + gboolean allow_user_interaction, + NMAuthManagerCheckAuthorizationCallback callback, + gpointer user_data) { NMAuthManagerPrivate *priv; + PolkitCheckAuthorizationFlags flags; char subject_buf[64]; GVariantBuilder builder; - PolkitCheckAuthorizationFlags flags; GVariant *subject_value; GVariant *details_value; - CheckAuthData *data; + NMAuthManagerCallId *call_id; - g_return_if_fail (NM_IS_AUTH_MANAGER (self)); - g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); - g_return_if_fail (nm_auth_subject_is_unix_process (subject)); - g_return_if_fail (action_id != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), NULL); + g_return_val_if_fail (NM_IN_SET (nm_auth_subject_get_subject_type (subject), + NM_AUTH_SUBJECT_TYPE_INTERNAL, + NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS), + NULL); + g_return_val_if_fail (action_id, NULL); priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - g_return_if_fail (priv->polkit_enabled); + g_return_val_if_fail (!priv->disposing, NULL); + g_return_val_if_fail (!priv->shutting_down, NULL); flags = allow_user_interaction ? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE; - subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject); - nm_assert (g_variant_is_floating (subject_value)); - - /* ((PolkitDetails *)NULL) */ - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); - details_value = g_variant_builder_end (&builder); - - data = g_new0 (CheckAuthData, 1); - data->call_id = ++priv->call_id_counter; - data->self = g_object_ref (self); - data->simple = g_simple_async_result_new (G_OBJECT (self), - callback, - user_data, - nm_auth_manager_polkit_authority_check_authorization); - if (cancellable != NULL) { - data->cancellation_id = g_strdup_printf ("cancellation-id-%u", data->call_id); - data->cancellable = g_object_ref (cancellable); - } - - data->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)", - subject_value, - action_id, - details_value, - (guint32) flags, - data->cancellation_id != NULL ? data->cancellation_id : ""); - - if (priv->new_proxy_cancellable) { - _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (wait for proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - - priv->queued_calls = g_slist_prepend (priv->queued_calls, data); - } else if (!priv->proxy) { - _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (fails due to invalid DBUS proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - - _call_check_authorization_complete_with_error (data, "invalid DBUS proxy"); + call_id = g_slice_new0 (NMAuthManagerCallId); + call_id->self = g_object_ref (self); + call_id->callback = callback; + call_id->user_data = user_data; + call_id->call_numid = ++priv->call_numid_counter; + c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst); + + if (!priv->polkit_enabled) { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding due to polkit authorization disabled)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + call_id->idle_reason = IDLE_REASON_AUTHORIZED; + call_id->idle_id = g_idle_add (_call_on_idle, call_id); + } else if (nm_auth_subject_is_internal (subject)) { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for internal request)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + call_id->idle_reason = IDLE_REASON_AUTHORIZED; + call_id->idle_id = g_idle_add (_call_on_idle, call_id); + } else if (nm_auth_subject_get_unix_process_uid (subject) == 0) { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for root)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + call_id->idle_reason = IDLE_REASON_AUTHORIZED; + call_id->idle_id = g_idle_add (_call_on_idle, call_id); + } else if ( !priv->proxy + && !priv->new_proxy_cancellable) { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (failing due to invalid DBUS proxy)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + call_id->idle_reason = IDLE_REASON_NO_DBUS; + call_id->idle_id = g_idle_add (_call_on_idle, call_id); } else { - _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); - - _call_check_authorization (data); + subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject); + nm_assert (g_variant_is_floating (subject_value)); + + /* ((PolkitDetails *)NULL) */ + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); + details_value = g_variant_builder_end (&builder); + + call_id->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)", + subject_value, + action_id, + details_value, + (guint32) flags, + cancellation_id_to_str_a (call_id->call_numid)); + if (!priv->proxy) { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (wait for proxy)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + } else { + _LOG2T (call_id, "CheckAuthorization(%s), subject=%s", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); + _call_check_authorize (call_id); + } } + + return call_id; } -gboolean -nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self, - GAsyncResult *res, - gboolean *out_is_authorized, - gboolean *out_is_challenge, - GError **error) +void +nm_auth_manager_check_authorization_cancel (NMAuthManagerCallId *call_id) { - gboolean success = FALSE; - gboolean is_authorized = FALSE; - gboolean is_challenge = FALSE; + NMAuthManager *self; + gs_free_error GError *error = NULL; - g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_if_fail (call_id); - if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) { - CheckAuthorizationResult *result; + self = call_id->self; - result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)); - is_authorized = !!result->is_authorized; - is_challenge = !!result->is_challenge; - success = TRUE; - } - g_assert ((success && !error) || (!success || error)); + g_return_if_fail (NM_IS_AUTH_MANAGER (self)); + g_return_if_fail (!c_list_is_empty (&call_id->calls_lst)); - if (out_is_authorized) - *out_is_authorized = is_authorized; - if (out_is_challenge) - *out_is_challenge = is_challenge; - return success; + nm_assert (c_list_contains (&NM_AUTH_MANAGER_GET_PRIVATE (self)->calls_lst_head, &call_id->calls_lst)); + + nm_utils_error_set_cancelled (&error, FALSE, "NMAuthManager"); + _LOG2T (call_id, "completed: failed due to call cancelled"); + _call_id_invoke_callback (call_id, + FALSE, + FALSE, + error); } /*****************************************************************************/ @@ -350,14 +443,14 @@ static void _emit_changed_signal (NMAuthManager *self) { _LOGD ("emit changed signal"); - g_signal_emit_by_name (self, NM_AUTH_MANAGER_SIGNAL_CHANGED); + g_signal_emit (self, signals[CHANGED_SIGNAL], 0); } static void _log_name_owner (NMAuthManager *self, char **out_name_owner) { NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - char *name_owner; + gs_free char *name_owner = NULL; name_owner = g_dbus_proxy_get_name_owner (priv->proxy); if (name_owner) @@ -365,10 +458,7 @@ _log_name_owner (NMAuthManager *self, char **out_name_owner) else _LOGD ("dbus name owner: none"); - if (out_name_owner) - *out_name_owner = name_owner; - else - g_free (name_owner); + NM_SET_OUT (out_name_owner, g_steal_pointer (&name_owner)); } static void @@ -377,20 +467,16 @@ _dbus_on_name_owner_notify_cb (GObject *object, gpointer user_data) { NMAuthManager *self = user_data; - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - char *name_owner; + gs_free char *name_owner = NULL; - g_return_if_fail (priv->proxy == (void *) object); + nm_assert (NM_AUTH_MANAGER_GET_PRIVATE (self)->proxy == (GDBusProxy *) object); _log_name_owner (self, &name_owner); - if (!name_owner) { /* when the name disappears, we also want to raise a emit signal. * When it appears, we raise one already. */ _emit_changed_signal (self); } - - g_free (name_owner); } static void @@ -398,9 +484,8 @@ _dbus_on_changed_signal_cb (GDBusProxy *proxy, gpointer user_data) { NMAuthManager *self = user_data; - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - g_return_if_fail (priv->proxy == proxy); + nm_assert (NM_AUTH_MANAGER_GET_PRIVATE (self)->proxy == proxy); _LOGD ("dbus signal: \"Changed\""); _emit_changed_signal (self); @@ -411,49 +496,35 @@ _dbus_new_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - NMAuthManager **p_self = user_data; - NMAuthManager *self = NULL; + NMAuthManager *self; NMAuthManagerPrivate *priv; - GError *error = NULL; + gs_free GError *error = NULL; GDBusProxy *proxy; - CheckAuthData *data; + NMAuthManagerCallId *call_id; proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - if (!*p_self) { - _LOGD ("_dbus_new_proxy_cb(): manager destroyed before callback finished. Abort"); - g_clear_object (&proxy); - g_clear_error (&error); - g_free (p_self); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - self = *p_self; - g_object_remove_weak_pointer (G_OBJECT (self), (void **)p_self); - g_free (p_self); + self = user_data; priv = NM_AUTH_MANAGER_GET_PRIVATE (self); - g_return_if_fail (priv->new_proxy_cancellable); - g_return_if_fail (!priv->proxy); - + priv->proxy = proxy; g_clear_object (&priv->new_proxy_cancellable); - priv->queued_calls = g_slist_reverse (priv->queued_calls); - - priv->proxy = proxy; if (!priv->proxy) { - _LOGE ("could not get polkit proxy: %s", error->message); - g_clear_error (&error); - - while (priv->queued_calls) { - data = priv->queued_calls->data; - priv->queued_calls = g_slist_remove (priv->queued_calls, data); + _LOGE ("could not create polkit proxy: %s", error->message); - _call_check_authorization_complete_with_error (data, "error creating DBUS proxy"); + while ((call_id = c_list_first_entry (&priv->calls_lst_head, NMAuthManagerCallId, calls_lst))) { + _LOG2T (call_id, "completed: failed due to no D-Bus proxy after startup"); + _call_id_invoke_callback (call_id, FALSE, FALSE, error); } return; } + priv->cancel_cancellable = g_cancellable_new (); + g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (_dbus_on_name_owner_notify_cb), @@ -464,17 +535,14 @@ _dbus_new_proxy_cb (GObject *source_object, _log_name_owner (self, NULL); - while (priv->queued_calls) { - data = priv->queued_calls->data; - priv->queued_calls = g_slist_remove (priv->queued_calls, data); - _LOGD ("call[%u]: CheckAuthorization invoke now", data->call_id); - _call_check_authorization (data); + while ((call_id = c_list_first_entry (&priv->calls_lst_head, NMAuthManagerCallId, calls_lst))) { + _LOG2T (call_id, "CheckAuthorization invoke now"); + _call_check_authorize (call_id); } + _emit_changed_signal (self); } -#endif - /*****************************************************************************/ NMAuthManager * @@ -485,23 +553,42 @@ nm_auth_manager_get () return singleton_instance; } -/*****************************************************************************/ - -static void -get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +void +nm_auth_manager_force_shutdown (NMAuthManager *self) { - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE ((NMAuthManager *) object); + NMAuthManagerPrivate *priv; - switch (prop_id) { - case PROP_POLKIT_ENABLED: - g_value_set_boolean (value, priv->polkit_enabled); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + g_return_if_fail (NM_IS_AUTH_MANAGER (self)); + + priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + + /* while we have pending requests (NMAuthManagerCallId), the instance + * is kept alive. + * + * Even if the caller cancells all pending call-ids, we still need to keep + * a reference to self, in order to handle pending CancelCheckAuthorization + * requests. + * + * To do a corrdinated shutdown, do the following: + * - cancel all pending NMAuthManagerCallId requests. + * - ensure everybody unrefs the NMAuthManager instance. If by that, the instance + * gets destroyed, the shutdown already completed successfully. + * - Otherwise, the object is kept alive by pending CancelCheckAuthorization requests. + * wait a certain timeout (1 second) for all requests to complete (by watching + * for destruction of NMAuthManager). + * - if that doesn't happen within timeout, issue nm_auth_manager_force_shutdown() and + * wait longer. After that, soon the instance should be destroyed and you + * did a successful shutdown. + * - if the instance was still not destroyed within a short timeout, you leaked + * resources. You cannot properly shutdown. + */ + + priv->shutting_down = TRUE; + nm_clear_g_cancellable (&priv->cancel_cancellable); } +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -523,6 +610,9 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p static void nm_auth_manager_init (NMAuthManager *self) { + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + + c_list_init (&priv->calls_lst_head); } static void @@ -533,16 +623,10 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object); -#if WITH_POLKIT _LOGD ("create auth-manager: polkit %s", priv->polkit_enabled ? "enabled" : "disabled"); if (priv->polkit_enabled) { - NMAuthManager **p_self; - priv->new_proxy_cancellable = g_cancellable_new (); - p_self = g_new (NMAuthManager *, 1); - *p_self = self; - g_object_add_weak_pointer (G_OBJECT (self), (void **) p_self); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, @@ -551,14 +635,8 @@ constructed (GObject *object) POLKIT_INTERFACE, priv->new_proxy_cancellable, _dbus_new_proxy_cb, - p_self); + self); } -#else - if (priv->polkit_enabled) - _LOGW ("create auth-manager: polkit disabled at compile time. All authentication requests will fail"); - else - _LOGD ("create auth-manager: polkit disabled at compile time"); -#endif } NMAuthManager * @@ -585,23 +663,22 @@ static void dispose (GObject *object) { NMAuthManager* self = NM_AUTH_MANAGER (object); -#if WITH_POLKIT NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); -#endif + gs_free_error GError *error_disposing = NULL; _LOGD ("dispose"); -#if WITH_POLKIT - /* since we take a reference for each queued call, we don't expect to have any queued calls in dispose() */ - g_assert (!priv->queued_calls); + nm_assert (!c_list_is_empty (&priv->calls_lst_head)); + + priv->disposing = TRUE; nm_clear_g_cancellable (&priv->new_proxy_cancellable); + nm_clear_g_cancellable (&priv->cancel_cancellable); if (priv->proxy) { g_signal_handlers_disconnect_by_data (priv->proxy, self); g_clear_object (&priv->proxy); } -#endif G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object); } @@ -611,7 +688,6 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->get_property = get_property; object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; @@ -619,7 +695,7 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) obj_properties[PROP_POLKIT_ENABLED] = g_param_spec_boolean (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "", FALSE, - G_PARAM_READWRITE | + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -628,11 +704,7 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) signals[CHANGED_SIGNAL] = g_signal_new (NM_AUTH_MANAGER_SIGNAL_CHANGED, NM_TYPE_AUTH_MANAGER, G_SIGNAL_RUN_LAST, - 0, /* class offset */ - NULL, /* accumulator */ - NULL, /* accumulator data */ + 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); + G_TYPE_NONE, 0); } - diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h index e66ef78c1..fe7ee787d 100644 --- a/src/nm-auth-manager.h +++ b/src/nm-auth-manager.h @@ -23,6 +23,31 @@ #include "nm-auth-subject.h" +/*****************************************************************************/ + +typedef enum { + NM_AUTH_CALL_RESULT_UNKNOWN, + NM_AUTH_CALL_RESULT_YES, + NM_AUTH_CALL_RESULT_AUTH, + NM_AUTH_CALL_RESULT_NO, +} NMAuthCallResult; + +static inline NMAuthCallResult +nm_auth_call_result_eval (gboolean is_authorized, + gboolean is_challenge, + GError *error) +{ + if (error) + return NM_AUTH_CALL_RESULT_UNKNOWN; + if (is_authorized) + return NM_AUTH_CALL_RESULT_YES; + if (is_challenge) + return NM_AUTH_CALL_RESULT_AUTH; + return NM_AUTH_CALL_RESULT_NO; +} + +/*****************************************************************************/ + #define NM_TYPE_AUTH_MANAGER (nm_auth_manager_get_type ()) #define NM_AUTH_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_MANAGER, NMAuthManager)) #define NM_AUTH_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_MANAGER, NMAuthManagerClass)) @@ -42,23 +67,28 @@ GType nm_auth_manager_get_type (void); NMAuthManager *nm_auth_manager_setup (gboolean polkit_enabled); NMAuthManager *nm_auth_manager_get (void); +void nm_auth_manager_force_shutdown (NMAuthManager *self); + gboolean nm_auth_manager_get_polkit_enabled (NMAuthManager *self); -#if WITH_POLKIT - -void nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self, - NMAuthSubject *subject, - const char *action_id, - gboolean allow_user_interaction, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self, - GAsyncResult *res, - gboolean *out_is_authorized, - gboolean *out_is_challenge, - GError **error); - -#endif +/*****************************************************************************/ + +typedef struct _NMAuthManagerCallId NMAuthManagerCallId; + +typedef void (*NMAuthManagerCheckAuthorizationCallback) (NMAuthManager *self, + NMAuthManagerCallId *call_id, + gboolean is_authorized, + gboolean is_challenge, + GError *error, + gpointer user_data); + +NMAuthManagerCallId *nm_auth_manager_check_authorization (NMAuthManager *self, + NMAuthSubject *subject, + const char *action_id, + gboolean allow_user_interaction, + NMAuthManagerCheckAuthorizationCallback callback, + gpointer user_data); + +void nm_auth_manager_check_authorization_cancel (NMAuthManagerCallId *call_id); #endif /* NM_AUTH_MANAGER_H */ diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index 5d92f36d6..cba118250 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -34,19 +34,16 @@ /*****************************************************************************/ struct NMAuthChain { - GHashTable *data; + GHashTable *data_hash; CList auth_call_lst_head; GDBusMethodInvocation *context; NMAuthSubject *subject; - GError *error; NMAuthChainResultFunc done_func; gpointer user_data; - guint idle_id; - guint32 refcount; bool done:1; @@ -55,9 +52,8 @@ struct NMAuthChain { typedef struct { CList auth_call_lst; NMAuthChain *chain; - GCancellable *cancellable; + NMAuthManagerCallId *call_id; char *permission; - guint call_idle_id; } AuthCall; /*****************************************************************************/ @@ -75,8 +71,8 @@ _ASSERT_call (AuthCall *call) static void auth_call_free (AuthCall *call) { - nm_clear_g_source (&call->call_idle_id); - nm_clear_g_cancellable (&call->cancellable); + if (call->call_id) + nm_auth_manager_check_authorization_cancel (call->call_id); c_list_unlink_stale (&call->auth_call_lst); g_free (call->permission); g_slice_free (AuthCall, call); @@ -123,7 +119,9 @@ _get_data (NMAuthChain *self, const char *tag) { ChainData *tmp; - tmp = g_hash_table_lookup (self->data, &tag); + if (!self->data_hash) + return NULL; + tmp = g_hash_table_lookup (self->data_hash, &tag); return tmp ? tmp->data : NULL; } @@ -156,7 +154,10 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) g_return_val_if_fail (self, NULL); g_return_val_if_fail (tag, NULL); - tmp = g_hash_table_lookup (self->data, &tag); + if (!self->data_hash) + return NULL; + + tmp = g_hash_table_lookup (self->data_hash, &tag); if (!tmp) return NULL; @@ -164,7 +165,7 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) /* Make sure the destroy handler isn't called when freeing */ tmp->destroy = NULL; - g_hash_table_remove (self->data, tmp); + g_hash_table_remove (self->data_hash, tmp); return value; } @@ -177,10 +178,15 @@ nm_auth_chain_set_data (NMAuthChain *self, g_return_if_fail (self); g_return_if_fail (tag); - if (data == NULL) - g_hash_table_remove (self->data, &tag); - else { - g_hash_table_add (self->data, + if (data == NULL) { + if (self->data_hash) + g_hash_table_remove (self->data_hash, &tag); + } else { + if (!self->data_hash) { + self->data_hash = g_hash_table_new_full (nm_pstr_hash, nm_pstr_equal, + NULL, chain_data_free); + } + g_hash_table_add (self->data_hash, chain_data_new (tag, data, data_destroy)); } } @@ -210,17 +216,16 @@ nm_auth_chain_get_subject (NMAuthChain *self) /*****************************************************************************/ static gboolean -auth_chain_finish (gpointer user_data) +auth_chain_finish (NMAuthChain *self) { - NMAuthChain *self = user_data; - - self->idle_id = 0; self->done = TRUE; /* Ensure we stay alive across the callback */ + nm_assert (self->refcount == 1); self->refcount++; - self->done_func (self, self->error, self->context, self->user_data); - nm_auth_chain_unref (self); + self->done_func (self, NULL, self->context, self->user_data); + nm_assert (NM_IN_SET (self->refcount, 1, 2)); + nm_auth_chain_destroy (self); return FALSE; } @@ -233,71 +238,42 @@ auth_call_complete (AuthCall *call) self = call->chain; - c_list_unlink (&call->auth_call_lst); - - if (c_list_is_empty (&self->auth_call_lst_head)) { - nm_assert (!self->idle_id && !self->done); - self->idle_id = g_idle_add (auth_chain_finish, self); - } + nm_assert (!self->done); auth_call_free (call); -} - -static gboolean -auth_call_complete_idle_cb (gpointer user_data) -{ - AuthCall *call = user_data; - - _ASSERT_call (call); - call->call_idle_id = 0; - auth_call_complete (call); - return G_SOURCE_REMOVE; + if (c_list_is_empty (&self->auth_call_lst_head)) { + /* we are on an idle-handler or a clean call-stack (non-reentrant). */ + auth_chain_finish (self); + } } -#if WITH_POLKIT static void -pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data) +pk_call_cb (NMAuthManager *auth_manager, + NMAuthManagerCallId *call_id, + gboolean is_authorized, + gboolean is_challenge, + GError *error, + gpointer user_data) { AuthCall *call; - gs_free_error GError *error = NULL; - gboolean is_authorized = FALSE, is_challenge = FALSE; - guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN; - - nm_auth_manager_polkit_authority_check_authorization_finish (NM_AUTH_MANAGER (object), - result, - &is_authorized, - &is_challenge, - &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - nm_log_dbg (LOGD_CORE, "callback already cancelled"); + NMAuthCallResult call_result; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } call = user_data; - g_clear_object (&call->cancellable); + nm_assert (call->call_id == call_id); - if (error) { - /* Don't ruin the chain. Just leave the result unknown. */ - nm_log_warn (LOGD_CORE, "error requesting auth for %s: %s", - call->permission, error->message); - } else { - if (is_authorized) { - /* Caller has the permission */ - call_result = NM_AUTH_CALL_RESULT_YES; - } else if (is_challenge) { - /* Caller could authenticate to get the permission */ - call_result = NM_AUTH_CALL_RESULT_AUTH; - } else - call_result = NM_AUTH_CALL_RESULT_NO; - } + call->call_id = NULL; + + call_result = nm_auth_call_result_eval (is_authorized, is_challenge, error); nm_auth_chain_set_data (call->chain, call->permission, GUINT_TO_POINTER (call_result), NULL); auth_call_complete (call); } -#endif void nm_auth_chain_add_call (NMAuthChain *self, @@ -308,42 +284,21 @@ nm_auth_chain_add_call (NMAuthChain *self, NMAuthManager *auth_manager = nm_auth_manager_get (); g_return_if_fail (self); - g_return_if_fail (permission && *permission); g_return_if_fail (self->subject); + g_return_if_fail (!self->done); + g_return_if_fail (permission && *permission); g_return_if_fail (nm_auth_subject_is_unix_process (self->subject) || nm_auth_subject_is_internal (self->subject)); - g_return_if_fail (!self->idle_id && !self->done); call = g_slice_new0 (AuthCall); call->chain = self; call->permission = g_strdup (permission); c_list_link_tail (&self->auth_call_lst_head, &call->auth_call_lst); - - if ( nm_auth_subject_is_internal (self->subject) - || nm_auth_subject_get_unix_process_uid (self->subject) == 0 - || !nm_auth_manager_get_polkit_enabled (auth_manager)) { - /* Root user or non-polkit always gets the permission */ - nm_auth_chain_set_data (self, permission, GUINT_TO_POINTER (NM_AUTH_CALL_RESULT_YES), NULL); - call->call_idle_id = g_idle_add (auth_call_complete_idle_cb, call); - } else { - /* Non-root always gets authenticated when using polkit */ -#if WITH_POLKIT - call->cancellable = g_cancellable_new (); - nm_auth_manager_polkit_authority_check_authorization (auth_manager, - self->subject, - permission, - allow_interaction, - call->cancellable, - pk_call_cb, - call); -#else - if (!call->chain->error) { - call->chain->error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Polkit support is disabled at compile time"); - } - call->call_idle_id = g_idle_add (auth_call_complete_idle_cb, call); -#endif - } + call->call_id = nm_auth_manager_check_authorization (auth_manager, + self->subject, + permission, + allow_interaction, + pk_call_cb, + call); } /*****************************************************************************/ @@ -386,7 +341,6 @@ nm_auth_chain_new_subject (NMAuthSubject *subject, self = g_slice_new0 (NMAuthChain); c_list_init (&self->auth_call_lst_head); self->refcount = 1; - self->data = g_hash_table_new_full (nm_pstr_hash, nm_pstr_equal, NULL, chain_data_free); self->done_func = done_func; self->user_data = user_data; self->context = context ? g_object_ref (context) : NULL; @@ -395,36 +349,36 @@ nm_auth_chain_new_subject (NMAuthSubject *subject, } /** - * nm_auth_chain_unref: + * nm_auth_chain_destroy: * @self: the auth-chain * - * Unrefs the auth-chain. By unrefing the auth-chain, you also cancel + * Destroys the auth-chain. By destroying the auth-chain, you also cancel * the receipt of the done-callback. IOW, the callback will not be invoked. * - * The only exception is, if you call nm_auth_chain_unref() from inside + * The only exception is, if may call nm_auth_chain_destroy() from inside * the callback. In this case, @self stays alive until the callback returns. + * + * Note that you might only destroy an auth-chain exactly once, and never + * after the callback was handled. */ void -nm_auth_chain_unref (NMAuthChain *self) +nm_auth_chain_destroy (NMAuthChain *self) { AuthCall *call; g_return_if_fail (self); - g_return_if_fail (self->refcount > 0); + g_return_if_fail (NM_IN_SET (self->refcount, 1, 2)); if (--self->refcount > 0) return; - nm_clear_g_source (&self->idle_id); - nm_clear_g_object (&self->subject); nm_clear_g_object (&self->context); while ((call = c_list_first_entry (&self->auth_call_lst_head, AuthCall, auth_call_lst))) auth_call_free (call); - g_clear_error (&self->error); - nm_clear_pointer (&self->data, g_hash_table_destroy); + nm_clear_pointer (&self->data_hash, g_hash_table_destroy); g_slice_free (NMAuthChain, self); } diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h index 335edb5b3..a641c49df 100644 --- a/src/nm-auth-utils.h +++ b/src/nm-auth-utils.h @@ -23,14 +23,9 @@ #include "nm-connection.h" -typedef struct NMAuthChain NMAuthChain; +#include "nm-auth-manager.h" -typedef enum { - NM_AUTH_CALL_RESULT_UNKNOWN, - NM_AUTH_CALL_RESULT_YES, - NM_AUTH_CALL_RESULT_AUTH, - NM_AUTH_CALL_RESULT_NO, -} NMAuthCallResult; +typedef struct NMAuthChain NMAuthChain; typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, GError *error, @@ -62,7 +57,7 @@ void nm_auth_chain_add_call (NMAuthChain *chain, const char *permission, gboolean allow_interaction); -void nm_auth_chain_unref (NMAuthChain *chain); +void nm_auth_chain_destroy (NMAuthChain *chain); /* Caller must free returned error description */ gboolean nm_auth_is_subject_in_acl (NMConnection *connection, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index a9f9255be..2a50f8f81 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2234,7 +2234,13 @@ _log_connection_sort_names (LogConnectionSettingData *setting_data, GArray *sort } void -nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix) +nm_utils_log_connection_diff (NMConnection *connection, + NMConnection *diff_base, + guint32 level, + guint64 domain, + const char *name, + const char *prefix, + const char *dbus_path) { GHashTable *connection_diff = NULL; GArray *sorted_hashes; @@ -2310,7 +2316,6 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, if (print_header) { GError *err_verify = NULL; - const char *path = nm_connection_get_path (connection); const char *t1, *t2; t1 = nm_connection_get_connection_type (connection); @@ -2320,12 +2325,12 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, prefix, name, connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), diff_base, G_OBJECT_TYPE_NAME (diff_base), NM_PRINT_FMT_QUOTE_STRING (t2), - NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); + NM_PRINT_FMT_QUOTED (dbus_path, " [", dbus_path, "]", "")); } else { nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s/%s%s%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), - NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); + NM_PRINT_FMT_QUOTED (dbus_path, " [", dbus_path, "]", "")); } print_header = FALSE; @@ -3645,7 +3650,8 @@ nm_utils_setpgid (gpointer unused G_GNUC_UNUSED) /** * nm_utils_g_value_set_strv: * @value: a #GValue, initialized to store a #G_TYPE_STRV - * @strings: a #GPtrArray of strings + * @strings: a #GPtrArray of strings. %NULL values are not + * allowed. * * Converts @strings to a #GStrv and stores it in @value. */ @@ -3653,11 +3659,13 @@ void nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings) { char **strv; - int i; + guint i; strv = g_new (char *, strings->len + 1); - for (i = 0; i < strings->len; i++) + for (i = 0; i < strings->len; i++) { + nm_assert (strings->pdata[i]); strv[i] = g_strdup (strings->pdata[i]); + } strv[i] = NULL; g_value_take_boxed (value, strv); diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 33773ab67..6b3682aa8 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -231,7 +231,12 @@ const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, i int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b); -void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); +void nm_utils_log_connection_diff (NMConnection *connection, + NMConnection *diff_base, + guint32 level, guint64 domain, + const char *name, + const char *prefix, + const char *dbus_path); gint64 nm_utils_get_monotonic_timestamp_ns (void); gint64 nm_utils_get_monotonic_timestamp_us (void); diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c index cd3a23509..014f30f40 100644 --- a/src/nm-dbus-object.c +++ b/src/nm-dbus-object.c @@ -37,9 +37,13 @@ nm_dbus_object_set_quitting (void) /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE (NMDBusObject, - PROP_PATH, -); +enum { + EXPORTED_CHANGED, + + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_ABSTRACT_TYPE (NMDBusObject, nm_dbus_object, G_TYPE_OBJECT); @@ -53,6 +57,12 @@ G_DEFINE_ABSTRACT_TYPE (NMDBusObject, nm_dbus_object, G_TYPE_OBJECT); /*****************************************************************************/ +static void +_emit_exported_changed (NMDBusObject *self) +{ + g_signal_emit (self, signals[EXPORTED_CHANGED], 0); +} + static char * _create_export_path (NMDBusObjectClass *klass) { @@ -107,6 +117,8 @@ nm_dbus_object_export (NMDBusObject *self) g_return_val_if_fail (!self->internal.path, self->internal.path); + nm_assert (!self->internal.is_unexporting); + self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self)); self->internal.export_version_id = ++id_counter; @@ -115,7 +127,7 @@ nm_dbus_object_export (NMDBusObject *self) _nm_dbus_manager_obj_export (self); - _notify (self, PROP_PATH); + _emit_exported_changed (self); return self->internal.path; } @@ -135,12 +147,27 @@ nm_dbus_object_unexport (NMDBusObject *self) _LOGT ("unexport: \"%s\"", self->internal.path); + /* note that we emit the signal *before* actually unexporting the object. + * The reason is, that listeners want to use this signal to know that + * the object goes away, and clear their D-Bus path to this object. + * + * But this must happen before we actually unregister the object, so + * that we first emit a D-Bus signal that other objects no longer + * reference this object, before finally unregistering the object itself. + * + * The inconvenient part is, that at this point nm_dbus_object_get_path() + * still returns the path. So, the callee needs to handle that. Possibly + * by using "nm_dbus_object_get_path_still_exported()". */ + self->internal.is_unexporting = TRUE; + + _emit_exported_changed (self); + _nm_dbus_manager_obj_unexport (self); g_clear_pointer (&self->internal.path, g_free); self->internal.export_version_id = 0; - _notify (self, PROP_PATH); + self->internal.is_unexporting = FALSE; } /*****************************************************************************/ @@ -205,22 +232,6 @@ nm_dbus_object_emit_signal (NMDBusObject *self, /*****************************************************************************/ static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDBusObject *self = NM_DBUS_OBJECT (object); - - switch (prop_id) { - case PROP_PATH: - g_value_set_string (value, self->internal.path); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void dispatch_properties_changed (GObject *object, guint n_pspecs, GParamSpec **pspecs) @@ -284,10 +295,11 @@ dispose (GObject *object) g_warn_if_reached (); nm_dbus_object_unexport (self); } - } else if (nm_clear_g_free (&self->internal.path)) { + } else if (self->internal.path) { /* FIXME: do a proper, coordinate shutdown, so that no objects stay * alive nor exported. */ - _notify (self, PROP_PATH); + _emit_exported_changed (self); + nm_clear_g_free (&self->internal.path); } G_OBJECT_CLASS (nm_dbus_object_parent_class)->dispose (object); @@ -302,14 +314,13 @@ nm_dbus_object_class_init (NMDBusObjectClass *klass) object_class->constructed = constructed; object_class->dispose = dispose; - object_class->get_property = get_property; object_class->dispatch_properties_changed = dispatch_properties_changed; - obj_properties[PROP_PATH] = - g_param_spec_string (NM_DBUS_OBJECT_PATH, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + signals[EXPORTED_CHANGED] = + g_signal_new (NM_DBUS_OBJECT_EXPORTED_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/nm-dbus-object.h b/src/nm-dbus-object.h index f6629289a..947ea6c7d 100644 --- a/src/nm-dbus-object.h +++ b/src/nm-dbus-object.h @@ -82,7 +82,7 @@ extern const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics; #define NM_IS_DBUS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DBUS_OBJECT)) #define NM_DBUS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DBUS_OBJECT, NMDBusObjectClass)) -#define NM_DBUS_OBJECT_PATH "path" +#define NM_DBUS_OBJECT_EXPORTED_CHANGED "exported-changed" /* NMDBusObject and NMDBusManager cooperate strongly. Hence, there is an * internal data structure attached to the NMDBusObject accessible to both of them. */ @@ -99,6 +99,7 @@ struct _NMDBusObjectInternal { * unexported, or even re-exported afterwards. If that happens, we want * to fail the request. For that, we keep track of a version id. */ guint64 export_version_id; + bool is_unexporting:1; }; struct _NMDBusObject { @@ -169,6 +170,18 @@ nm_dbus_object_is_exported (NMDBusObject *self) return !!nm_dbus_object_get_path (self); } +static inline const char * +nm_dbus_object_get_path_still_exported (NMDBusObject *self) +{ + g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); + + /* like nm_dbus_object_get_path(), however, while unexporting + * (exported-changed signal), returns %NULL instead of the path. */ + return self->internal.is_unexporting + ? NULL + : self->internal.path; +} + const char *nm_dbus_object_export (NMDBusObject *self); void nm_dbus_object_unexport (NMDBusObject *self); diff --git a/src/nm-dbus-utils.c b/src/nm-dbus-utils.c index 2464ff79f..5a57206c7 100644 --- a/src/nm-dbus-utils.c +++ b/src/nm-dbus-utils.c @@ -121,6 +121,20 @@ nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object) } void +nm_dbus_utils_g_value_set_object_path_still_exported (GValue *value, gpointer object) +{ + const char *path; + + g_return_if_fail (!object || NM_IS_DBUS_OBJECT (object)); + + if ( object + && (path = nm_dbus_object_get_path_still_exported (object))) + g_value_set_string (value, path); + else + g_value_set_string (value, "/"); +} + +void nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value, GHashTable *hash /* has keys of NMDBusObject type. */, gboolean expect_all_exported) @@ -152,4 +166,143 @@ nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value, g_value_take_boxed (value, strv); } +const char ** +nm_dbus_utils_get_paths_for_clist (const CList *lst_head, + gssize lst_len, + guint member_offset, + gboolean expect_all_exported) +{ + const CList *iter; + const char **strv; + const char *path; + gsize i, n; + + nm_assert (lst_head); + + if (lst_len < 0) + n = c_list_length (lst_head); + else { + n = lst_len; + nm_assert (n == c_list_length (lst_head)); + } + + i = 0; + strv = g_new (const char *, n + 1); + c_list_for_each (iter, lst_head) { + NMDBusObject *obj = (NMDBusObject *) (((const char *) iter) - member_offset); + + path = nm_dbus_object_get_path (obj); + if (!path) { + nm_assert (expect_all_exported); + continue; + } + + nm_assert (i < n); + strv[i++] = path; + } + nm_assert (i <= n); + strv[i] = NULL; + + return strv; +} + /*****************************************************************************/ + +void +nm_dbus_track_obj_path_init (NMDBusTrackObjPath *track, + GObject *target, + const GParamSpec *pspec) +{ + nm_assert (track); + nm_assert (G_IS_OBJECT (target)); + nm_assert (G_IS_PARAM_SPEC (pspec)); + + track->_obj = NULL; + track->_notify_target = target; + track->_notify_pspec = pspec; + track->_notify_signal_id = 0; + track->_visible = FALSE; +} + +void +nm_dbus_track_obj_path_deinit (NMDBusTrackObjPath *track) +{ + /* we allow deinit() to be called multiple times (e.g. from + * dispose(), which must be re-entrant). */ + nm_assert (track); + nm_assert (!track->_notify_target || G_IS_OBJECT (track->_notify_target)); + + nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id); + track->_notify_target = NULL; + track->_notify_pspec = NULL; + track->_visible = FALSE; + nm_clear_g_object (&track->_obj); +} + +void +nm_dbus_track_obj_path_notify (const NMDBusTrackObjPath *track) +{ + nm_assert (track); + nm_assert (G_IS_OBJECT (track->_notify_target)); + nm_assert (G_IS_PARAM_SPEC (track->_notify_pspec)); + + g_object_notify_by_pspec (track->_notify_target, + (GParamSpec *) track->_notify_pspec); +} + +const char * +nm_dbus_track_obj_path_get (const NMDBusTrackObjPath *track) +{ + nm_assert (track); + nm_assert (G_IS_OBJECT (track->_notify_target)); + + return track->obj && track->visible + ? nm_dbus_object_get_path_still_exported (track->obj) + : NULL; +} + +static void +_track_obj_exported_changed (NMDBusObject *obj, + NMDBusTrackObjPath *track) +{ + nm_dbus_track_obj_path_notify (track); +} + +void +nm_dbus_track_obj_path_set (NMDBusTrackObjPath *track, + gpointer obj, + gboolean visible) +{ + gs_unref_object NMDBusObject *old_obj = NULL; + const char *old_path; + + nm_assert (track); + nm_assert (G_IS_OBJECT (track->_notify_target)); + + g_return_if_fail (!obj || NM_IS_DBUS_OBJECT (obj)); + + if ( track->obj == obj + && track->visible == !!visible) + return; + + old_path = nm_dbus_track_obj_path_get (track); + + track->_visible = visible; + + if (track->obj != obj) { + nm_clear_g_signal_handler (track->obj, &track->_notify_signal_id); + + old_obj = track->obj; + track->_obj = nm_g_object_ref (obj); + + if (obj) { + track->_notify_signal_id = g_signal_connect (obj, + NM_DBUS_OBJECT_EXPORTED_CHANGED, + G_CALLBACK (_track_obj_exported_changed), + track); + } + } + + if (!nm_streq0 (old_path, nm_dbus_track_obj_path_get (track))) + nm_dbus_track_obj_path_notify (track); +} diff --git a/src/nm-dbus-utils.h b/src/nm-dbus-utils.h index 1d9c92ec3..e7e930e93 100644 --- a/src/nm-dbus-utils.h +++ b/src/nm-dbus-utils.h @@ -164,10 +164,49 @@ GVariant *nm_dbus_utils_get_property (GObject *obj, /*****************************************************************************/ +struct CList; + +const char **nm_dbus_utils_get_paths_for_clist (const struct CList *lst_head, + gssize lst_len, + guint member_offset, + gboolean expect_all_exported); + void nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object); +void nm_dbus_utils_g_value_set_object_path_still_exported (GValue *value, gpointer object); + void nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value, GHashTable *hash, gboolean expect_all_exported); +/*****************************************************************************/ + +typedef struct { + union { + gpointer const obj; + gpointer _obj; + }; + GObject *_notify_target; + const GParamSpec *_notify_pspec; + gulong _notify_signal_id; + union { + const bool visible; + bool _visible; + }; +} NMDBusTrackObjPath; + +void nm_dbus_track_obj_path_init (NMDBusTrackObjPath *track, + GObject *target, + const GParamSpec *pspec); + +void nm_dbus_track_obj_path_deinit (NMDBusTrackObjPath *track); + +void nm_dbus_track_obj_path_notify (const NMDBusTrackObjPath *track); + +const char *nm_dbus_track_obj_path_get (const NMDBusTrackObjPath *track); + +void nm_dbus_track_obj_path_set (NMDBusTrackObjPath *track, + gpointer obj, + gboolean visible); + #endif /* __NM_DBUS_UTILS_H__ */ diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 2f88d468e..235134c87 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -579,7 +579,7 @@ _dispatcher_call (NMDispatcherAction action, const char *connection_path; const char *filename; - connection_path = nm_connection_get_path (NM_CONNECTION (settings_connection)); + connection_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (settings_connection)); if (connection_path) { g_variant_builder_add (&connection_props, "{sv}", NMD_CONNECTION_PROPS_PATH, diff --git a/src/nm-manager.c b/src/nm-manager.c index c8fad9dbb..612f41562 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -953,7 +953,7 @@ _reload_auth_cb (NMAuthChain *chain, g_dbus_method_invocation_return_value (context, NULL); out: - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -2100,7 +2100,7 @@ device_auth_done_cb (NMAuthChain *chain, nm_auth_chain_get_data (chain, "user-data")); g_clear_error (&error); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -2392,7 +2392,7 @@ recheck_assume_connection (NMManager *self, if (!active) { _LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s", - nm_connection_get_path (NM_CONNECTION (connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), error->message); g_error_free (error); @@ -4517,7 +4517,7 @@ activation_add_done (NMSettings *settings, g_dbus_method_invocation_return_value ( context, g_variant_new ("(oo)", - nm_connection_get_path (NM_CONNECTION (new_connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (new_connection)), nm_dbus_object_get_path (NM_DBUS_OBJECT (active)))); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, nm_active_connection_get_settings_connection (active), @@ -4796,7 +4796,7 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, NULL); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -5138,7 +5138,7 @@ sleep_auth_done_cb (NMAuthChain *chain, g_dbus_method_invocation_return_value (context, NULL); } - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } #endif @@ -5276,7 +5276,7 @@ enable_net_done_cb (NMAuthChain *chain, g_dbus_method_invocation_take_error (context, ret_error); } - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -5384,7 +5384,7 @@ get_permissions_done_cb (NMAuthChain *chain, g_variant_new ("(a{ss})", &results)); } - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -5606,7 +5606,7 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, } out: - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -6017,7 +6017,7 @@ out: g_dbus_method_invocation_return_dbus_error (invocation, error_name, error_message); else g_dbus_method_invocation_return_value (invocation, NULL); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } void @@ -6152,7 +6152,7 @@ checkpoint_auth_done_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, variant); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -6830,7 +6830,7 @@ dispose (GObject *object) g_slice_free (PlatformLinkCbData, data); } - g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); + g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_destroy); priv->auth_chains = NULL; nm_clear_g_source (&priv->devices_inited_id); diff --git a/src/nm-policy.c b/src/nm-policy.c index 61efee556..9f845c1b0 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -2321,10 +2321,9 @@ _deactivate_if_active (NMPolicy *self, NMSettingsConnection *connection) nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - NMActiveConnectionState state = nm_active_connection_get_state (ac); if ( nm_active_connection_get_settings_connection (ac) == connection - && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { + && (nm_active_connection_get_state (ac) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { if (!nm_manager_deactivate_connection (priv->manager, ac, NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, diff --git a/src/nm-types.h b/src/nm-types.h index 0d5277e3a..e48a6e2a1 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -38,7 +38,6 @@ typedef struct _NMDBusManager NMDBusManager; typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; typedef struct _NMArpingManager NMArpingManager; -typedef struct _NMConnectionProvider NMConnectionProvider; typedef struct _NMConnectivity NMConnectivity; typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index b2cdc7d92..00aa3a086 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -360,7 +360,7 @@ agent_register_permissions_done (NMAuthChain *chain, request_add_agent (c_list_entry (iter, Request, lst_request), agent); } - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static NMSecretAgent * @@ -539,7 +539,7 @@ request_free (Request *req) g_object_unref (req->con.connection); g_free (req->con.path); if (req->con.chain) - nm_auth_chain_unref (req->con.chain); + nm_auth_chain_destroy (req->con.chain); if (req->request_type == REQUEST_TYPE_CON_GET) { g_free (req->con.get.setting_name); g_strfreev (req->con.get.hints); @@ -810,7 +810,7 @@ request_remove_agent (Request *req, NMSecretAgent *agent) case REQUEST_TYPE_CON_DEL: if (req->con.chain) { /* This cancels the pending authorization requests. */ - nm_auth_chain_unref (req->con.chain); + nm_auth_chain_destroy (req->con.chain); req->con.chain = NULL; } break; @@ -1047,7 +1047,7 @@ _con_get_request_start_validated (NMAuthChain *chain, _con_get_request_start_proceed (req, req->con.current_has_modify); } - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -1541,7 +1541,7 @@ agent_permissions_changed_done (NMAuthChain *chain, nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected); nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -1616,7 +1616,7 @@ cancel_more: goto cancel_more; } - g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref); + g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_destroy); priv->chains = NULL; if (priv->agents) { diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 713395420..9e87a35ba 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -32,6 +32,7 @@ #include "nm-config-data.h" #include "nm-dbus-interface.h" #include "nm-session-monitor.h" +#include "nm-auth-manager.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-agent-manager.h" @@ -80,7 +81,8 @@ typedef struct _NMSettingsConnectionPrivate { NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4; - GSList *pending_auths; /* List of pending authentication requests */ + /* List of pending authentication requests */ + CList auth_lst_head; CList call_ids_lst_head; /* in-progress secrets requests */ @@ -581,7 +583,7 @@ _update_prepare (NMSettingsConnection *self, if (!nm_connection_normalize (new_connection, NULL, NULL, error)) return FALSE; - if ( nm_connection_get_path (NM_CONNECTION (self)) + if ( nm_dbus_object_get_path (NM_DBUS_OBJECT (self)) && g_strcmp0 (nm_settings_connection_get_uuid (self), nm_connection_get_uuid (new_connection)) != 0) { /* Updating the UUID is not allowed once the path is exported. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -661,8 +663,10 @@ nm_settings_connection_update (NMSettingsConnection *self, NM_SETTING_COMPARE_FLAG_EXACT)) { gs_unref_object NMConnection *simple = NULL; - if (log_diff_name) - nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); + if (log_diff_name) { + nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ", + nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); + } /* Make a copy of agent-owned secrets because they won't be present in * the connection returned by plugins, as plugins return only what was @@ -798,7 +802,7 @@ nm_settings_connection_delete (NMSettingsConnection *self, for_agents = nm_simple_connection_new_clone (NM_CONNECTION (self)); nm_connection_clear_secrets (for_agents); nm_agent_manager_delete_secrets (priv->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), for_agents); g_object_unref (for_agents); @@ -1295,7 +1299,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr); call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), NM_CONNECTION (self), subject, existing_secrets, @@ -1359,7 +1363,7 @@ nm_settings_connection_cancel_secrets (NMSettingsConnection *self, _get_secrets_cancel (self, call_id, FALSE); } -/**** User authorization **************************************/ +/*****************************************************************************/ typedef void (*AuthCallback) (NMSettingsConnection *self, GDBusMethodInvocation *context, @@ -1367,46 +1371,61 @@ typedef void (*AuthCallback) (NMSettingsConnection *self, GError *error, gpointer data); -static void -pk_auth_cb (NMAuthChain *chain, - GError *chain_error, - GDBusMethodInvocation *context, - gpointer user_data) -{ - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; - NMAuthCallResult result; - const char *perm; +typedef struct { + CList auth_lst; + NMAuthManagerCallId *call_id; + NMSettingsConnection *self; AuthCallback callback; gpointer callback_data; + GDBusMethodInvocation *invocation; NMAuthSubject *subject; +} AuthData; + +static void +pk_auth_cb (NMAuthManager *auth_manager, + NMAuthManagerCallId *auth_call_id, + gboolean is_authorized, + gboolean is_challenge, + GError *auth_error, + gpointer user_data) +{ + AuthData *auth_data = user_data; + NMSettingsConnection *self; + gs_free_error GError *error = NULL; + + nm_assert (auth_data); + nm_assert (NM_IS_SETTINGS_CONNECTION (auth_data->self)); + + self = auth_data->self; - priv->pending_auths = g_slist_remove (priv->pending_auths, chain); + auth_data->call_id = NULL; - perm = nm_auth_chain_get_data (chain, "perm"); - g_assert (perm); - result = nm_auth_chain_get_result (chain, perm); + c_list_unlink (&auth_data->auth_lst); - /* If our NMSettingsConnection is already gone, do nothing */ - if (chain_error) { + if (g_error_matches (auth_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "Error checking authorization: connection was deleted"); + } else if (auth_error) { error = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Error checking authorization: %s", - chain_error->message ? chain_error->message : "(unknown)"); - } else if (result != NM_AUTH_CALL_RESULT_YES) { + auth_error->message); + } else if (nm_auth_call_result_eval (is_authorized, is_challenge, auth_error) != NM_AUTH_CALL_RESULT_YES) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, - "Insufficient privileges."); + "Insufficient privileges"); } - callback = nm_auth_chain_get_data (chain, "callback"); - callback_data = nm_auth_chain_get_data (chain, "callback-data"); - subject = nm_auth_chain_get_data (chain, "subject"); - callback (self, context, subject, error, callback_data); + auth_data->callback (self, + auth_data->invocation, + auth_data->subject, + error, + auth_data->callback_data); - g_clear_error (&error); - nm_auth_chain_unref (chain); + g_object_unref (auth_data->invocation); + g_object_unref (auth_data->subject); + g_slice_free (AuthData, auth_data); } /** @@ -1434,59 +1453,57 @@ _new_auth_subject (GDBusMethodInvocation *context, GError **error) return subject; } +/* may either invoke callback synchronously or asynchronously. */ static void auth_start (NMSettingsConnection *self, - GDBusMethodInvocation *context, + GDBusMethodInvocation *invocation, NMAuthSubject *subject, const char *check_permission, AuthCallback callback, gpointer callback_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - NMAuthChain *chain; - GError *error = NULL; + AuthData *auth_data; char *error_desc = NULL; - g_return_if_fail (context != NULL); - g_return_if_fail (NM_IS_AUTH_SUBJECT (subject)); + nm_assert (nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); + nm_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); + nm_assert (NM_IS_AUTH_SUBJECT (subject)); /* Ensure the caller can view this connection */ if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self), subject, &error_desc)) { + gs_free_error GError *error = NULL; + error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, error_desc); g_free (error_desc); - callback (self, context, subject, error, callback_data); - g_clear_error (&error); + callback (self, invocation, subject, error, callback_data); return; } if (!check_permission) { /* Don't need polkit auth, automatic success */ - callback (self, context, 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, subject, error, callback_data); - g_clear_error (&error); + callback (self, invocation, subject, NULL, callback_data); 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 (chain, "subject", g_object_ref (subject), g_object_unref); - nm_auth_chain_add_call (chain, check_permission, TRUE); + auth_data = g_slice_new (AuthData); + auth_data->self = self; + auth_data->callback = callback; + auth_data->callback_data = callback_data; + auth_data->invocation = g_object_ref (invocation); + auth_data->subject = g_object_ref (subject); + c_list_link_tail (&priv->auth_lst_head, &auth_data->auth_lst); + auth_data->call_id = nm_auth_manager_check_authorization (nm_auth_manager_get (), + subject, + check_permission, + TRUE, + pk_auth_cb, + auth_data); } /**** DBus method handlers ************************************/ @@ -1789,7 +1806,7 @@ update_auth_cb (NMSettingsConnection *self, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); nm_agent_manager_save_secrets (info->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), for_agent, info->subject); } @@ -2065,7 +2082,7 @@ get_modify_permission_basic (NMSettingsConnection *self) * request affects more than just the caller, require 'modify.system'. */ s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); - g_assert (s_con); + nm_assert (s_con); if (nm_setting_connection_get_num_permissions (s_con) == 1) return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; @@ -2210,7 +2227,7 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, /* Tell agents to remove secrets for this connection */ nm_agent_manager_delete_secrets (priv->agent_mgr, - nm_connection_get_path (NM_CONNECTION (self)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), NM_CONNECTION (self)); nm_settings_connection_update (self, @@ -2274,11 +2291,15 @@ void nm_settings_connection_signal_remove (NMSettingsConnection *self) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + AuthData *auth_data; if (priv->removed) return; priv->removed = TRUE; + while ((auth_data = c_list_first_entry (&priv->auth_lst_head, AuthData, auth_lst))) + nm_auth_manager_check_authorization_cancel (auth_data->call_id); + nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), &interface_info_settings_connection, &signal_info_removed, @@ -2963,8 +2984,11 @@ nm_settings_connection_init (NMSettingsConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionPrivate); self->_priv = priv; + c_list_init (&self->_connections_lst); + priv->ready = TRUE; c_list_init (&priv->call_ids_lst_head); + c_list_init (&priv->auth_lst_head); priv->session_monitor = g_object_ref (nm_session_monitor_get ()); priv->session_changed_id = g_signal_connect (priv->session_monitor, @@ -3000,6 +3024,9 @@ dispose (GObject *object) _LOGD ("disposing"); + nm_assert (c_list_is_empty (&self->_connections_lst)); + nm_assert (c_list_is_empty (&priv->auth_lst_head)); + /* Cancel in-progress secrets requests */ if (priv->agent_mgr) { c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) @@ -3017,10 +3044,6 @@ dispose (GObject *object) g_clear_object (&priv->system_secrets); g_clear_object (&priv->agent_secrets); - /* Cancel PolicyKit requests */ - g_slist_free_full (priv->pending_auths, (GDestroyNotify) nm_auth_chain_unref); - priv->pending_auths = NULL; - g_clear_pointer (&priv->seen_bssids, g_hash_table_destroy); set_visible (self, FALSE); diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index f5b317931..555a1d128 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -104,6 +104,7 @@ struct _NMSettingsConnectionPrivate; struct _NMSettingsConnection { NMDBusObject parent; struct _NMSettingsConnectionPrivate *_priv; + CList _connections_lst; }; struct _NMSettingsConnectionClass { diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index ade117de5..20346929d 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -62,6 +62,7 @@ #include "nm-utils.h" #include "nm-core-internal.h" +#include "nm-utils/nm-c-list.h" #include "nm-dbus-object.h" #include "devices/nm-device-ethernet.h" #include "nm-settings-connection.h" @@ -119,17 +120,21 @@ typedef struct { GSList *auths; GSList *plugins; - gboolean connections_loaded; - GHashTable *connections; + + CList connections_lst_head; + NMSettingsConnection **connections_cached_list; GSList *unmanaged_specs; GSList *unrecognized_specs; - gboolean started; - gboolean startup_complete; - NMHostnameManager *hostname_manager; + guint connections_len; + + bool started:1; + bool startup_complete:1; + bool connections_loaded:1; + } NMSettingsPrivate; struct _NMSettings { @@ -166,27 +171,29 @@ static void connection_ready_changed (NMSettingsConnection *conn, GParamSpec *pspec, gpointer user_data); +static void default_wired_clear_tag (NMSettings *self, + NMDevice *device, + NMSettingsConnection *connection, + gboolean add_to_no_auto_default); + /*****************************************************************************/ static void check_startup_complete (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GHashTableIter iter; NMSettingsConnection *conn; if (priv->startup_complete) return; - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) { + c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst) { if (!nm_settings_connection_get_ready (conn)) return; } /* the connection_ready_changed signal handler is no longer needed. */ - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) + c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst) g_signal_handlers_disconnect_by_func (conn, G_CALLBACK (connection_ready_changed), self); priv->startup_complete = TRUE; @@ -249,48 +256,25 @@ load_connections (NMSettings *self) unrecognized_specs_changed (NULL, self); } -void -nm_settings_for_each_connection (NMSettings *self, - NMSettingsForEachFunc for_each_func, - gpointer user_data) -{ - NMSettingsPrivate *priv; - GHashTableIter iter; - gpointer data; - - g_return_if_fail (NM_IS_SETTINGS (self)); - g_return_if_fail (for_each_func != NULL); - - priv = NM_SETTINGS_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) - for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data); -} - static void impl_settings_list_connections (NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, + GDBusConnection *dbus_connection, const char *sender, GDBusMethodInvocation *invocation, GVariant *parameters) { NMSettings *self = NM_SETTINGS (obj); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - gs_unref_ptrarray GPtrArray *connections = NULL; - GHashTableIter iter; - gpointer key; - - connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, &key, NULL)) - g_ptr_array_add (connections, key); - g_ptr_array_add (connections, NULL); + gs_free const char **strv = NULL; + strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head, + priv->connections_len, + G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst), + TRUE); g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(^ao)", connections->pdata)); + g_variant_new ("(^ao)", strv)); } NMSettingsConnection * @@ -298,16 +282,14 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) { NMSettingsPrivate *priv; NMSettingsConnection *candidate; - GHashTableIter iter; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); g_return_val_if_fail (uuid != NULL, NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) { - if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0) + c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) { + if (nm_streq (uuid, nm_settings_connection_get_uuid (candidate))) return candidate; } @@ -360,7 +342,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", - nm_connection_get_path (NM_CONNECTION (connection)))); + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)))); return; error: @@ -368,19 +350,23 @@ error: } static void -_clear_connections_cached_list (NMSettingsConnection ***p_connections_cached_list) +_clear_connections_cached_list (NMSettingsPrivate *priv) { + if (!priv->connections_cached_list) + return; + + nm_assert (priv->connections_len == NM_PTRARRAY_LEN (priv->connections_cached_list)); + #if NM_MORE_ASSERTS /* set the pointer to a bogus value. This makes it more apparent * if somebody has a reference to the cached list and still uses * it. That is a bug, this code just tries to make it blow up * more eagerly. */ - if (*p_connections_cached_list) { - NMSettingsConnection **p = *p_connections_cached_list; - memset (p, 0xdeaddead, sizeof (NMSettingsConnection *) * (NM_PTRARRAY_LEN (p) + 1)); - } + memset (priv->connections_cached_list, + 0xdeaddead, + sizeof (NMSettingsConnection *) * (priv->connections_len + 1)); #endif - g_clear_pointer (p_connections_cached_list, g_free); + nm_clear_g_free (&priv->connections_cached_list); } /** @@ -398,37 +384,33 @@ _clear_connections_cached_list (NMSettingsConnection ***p_connections_cached_lis NMSettingsConnection *const* nm_settings_get_connections (NMSettings *self, guint *out_len) { - GHashTableIter iter; NMSettingsPrivate *priv; - guint l, i; NMSettingsConnection **v; NMSettingsConnection *con; + guint i; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - if (G_LIKELY (priv->connections_cached_list)) { - NM_SET_OUT (out_len, g_hash_table_size (priv->connections)); - return priv->connections_cached_list; - } + nm_assert (priv->connections_len == c_list_length (&priv->connections_lst_head)); - l = g_hash_table_size (priv->connections); + if (G_UNLIKELY (!priv->connections_cached_list)) { + v = g_new (NMSettingsConnection *, priv->connections_len + 1); - v = g_new (NMSettingsConnection *, (gsize) l + 1); + i = 0; + c_list_for_each_entry (con, &priv->connections_lst_head, _connections_lst) { + nm_assert (i < priv->connections_len); + v[i++] = con; + } + nm_assert (i == priv->connections_len); + v[i] = NULL; - i = 0; - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) { - nm_assert (i < l); - v[i++] = con; + priv->connections_cached_list = v; } - nm_assert (i == l); - v[i] = NULL; - NM_SET_OUT (out_len, l); - priv->connections_cached_list = v; - return v; + NM_SET_OUT (out_len, priv->connections_len); + return priv->connections_cached_list; } /** @@ -495,28 +477,41 @@ NMSettingsConnection * nm_settings_get_connection_by_path (NMSettings *self, const char *path) { NMSettingsPrivate *priv; + NMSettingsConnection *connection; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (path, NULL); priv = NM_SETTINGS_GET_PRIVATE (self); - return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path); + connection = (NMSettingsConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); + if ( !connection + || !NM_IS_SETTINGS_CONNECTION (connection)) + return NULL; + + nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); + return connection; } gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection) { - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data; + NMSettingsConnection *candidate = NULL; + const char *path; - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) - if (data == connection) - return TRUE; + g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE); - return FALSE; + path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)); + if (path) + candidate = nm_settings_get_connection_by_path (self, path); + + nm_assert (!candidate || candidate == connection); + nm_assert (!!candidate == nm_c_list_contains_entry (&NM_SETTINGS_GET_PRIVATE (self)->connections_lst_head, + connection, + _connections_lst)); + return !!candidate; } const GSList * @@ -844,28 +839,24 @@ connection_flags_changed (NMSettingsConnection *connection, } static void -_emit_connection_removed (NMSettings *self, - NMSettingsConnection *connection) -{ - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_settings, - &signal_info_connection_removed, - "(o)", - nm_connection_get_path (NM_CONNECTION (connection))); - - g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection); -} - -static void connection_removed (NMSettingsConnection *connection, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - const char *cpath = nm_connection_get_path (NM_CONNECTION (connection)); + NMDevice *device; - if (!g_hash_table_lookup (priv->connections, cpath)) - g_return_if_reached (); - g_object_ref (connection); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (!c_list_is_empty (&connection->_connections_lst)); + nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); + + /* When the default wired connection is removed (either deleted or saved to + * a new persistent connection by a plugin), write the MAC address of the + * wired device to the config file and don't create a new default wired + * connection for that device again. + */ + device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); + if (device) + default_wired_clear_tag (self, device, connection, TRUE); /* Disconnect signal handlers, as plugins might still keep references * to the connection (and thus the signal handlers would still be live) @@ -877,22 +868,30 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self); - g_object_unref (self); /* Forget about the connection internally */ - g_hash_table_remove (priv->connections, (gpointer) cpath); - _clear_connections_cached_list (&priv->connections_cached_list); + _clear_connections_cached_list (priv); + priv->connections_len--; + c_list_unlink (&connection->_connections_lst); - _emit_connection_removed (self, connection); + if (priv->connections_loaded) { + _notify (self, PROP_CONNECTIONS); - /* Re-emit for listeners like NMPolicy */ - _notify (self, PROP_CONNECTIONS); - if (nm_dbus_object_is_exported (NM_DBUS_OBJECT (connection))) - nm_dbus_object_unexport (NM_DBUS_OBJECT (connection)); + nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), + &interface_info_settings, + &signal_info_connection_removed, + "(o)", + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))); + } - check_startup_complete (self); + nm_dbus_object_unexport (NM_DBUS_OBJECT (connection)); - g_object_unref (connection); + if (priv->connections_loaded) + g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection); + + g_object_ref (connection); + + check_startup_complete (self); } #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" @@ -940,19 +939,16 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GError *error = NULL; - GHashTableIter iter; - gpointer data; const char *path; NMSettingsConnection *existing; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); + g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (connection))); - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) { - /* prevent duplicates */ - if (data == connection) - return; + /* prevent duplicates */ + if (!c_list_is_empty (&connection->_connections_lst)) { + nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); + return; } if (!nm_connection_normalize (NM_CONNECTION (connection), NULL, NULL, &error)) { @@ -990,7 +986,6 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Evil openconnect migration hack */ openconnect_migrate_hack (NM_CONNECTION (connection)); - g_object_ref (self); /* This one unexports the connection, it needs to run late to give the active * connection a chance to deal with its reference to this settings connection. */ g_signal_connect_after (connection, NM_SETTINGS_CONNECTION_REMOVED, @@ -1006,17 +1001,15 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) self); } - /* Export the connection over D-Bus */ - g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); - path = nm_dbus_object_export (NM_DBUS_OBJECT (connection)); - nm_connection_set_path (NM_CONNECTION (connection), path); + _clear_connections_cached_list (priv); - g_hash_table_insert (priv->connections, - (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), - g_object_ref (connection)); - _clear_connections_cached_list (&priv->connections_cached_list); + priv->connections_len++; + c_list_link_tail (&priv->connections_lst_head, &connection->_connections_lst); - nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ "); + path = nm_dbus_object_export (NM_DBUS_OBJECT (connection)); + + nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ", + path); /* Only emit the individual connection-added signal after connections * have been initially loaded. @@ -1026,7 +1019,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) &interface_info_settings, &signal_info_new_connection, "(o)", - nm_connection_get_path (NM_CONNECTION (connection))); + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))); g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection); _notify (self, PROP_CONNECTIONS); @@ -1077,14 +1070,14 @@ nm_settings_add_connection (NMSettings *self, NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; NMSettingsConnection *added = NULL; - GHashTableIter citer; - NMConnection *candidate = NULL; + NMSettingsConnection *candidate = NULL; + const char *uuid; + + uuid = nm_connection_get_uuid (connection); /* Make sure a connection with this UUID doesn't already exist */ - g_hash_table_iter_init (&citer, priv->connections); - while (g_hash_table_iter_next (&citer, NULL, (gpointer *) &candidate)) { - if (g_strcmp0 (nm_connection_get_uuid (connection), - nm_connection_get_uuid (candidate)) == 0) { + c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) { + if (nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate)))) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_UUID_EXISTS, @@ -1152,7 +1145,7 @@ send_agent_owned_secrets (NMSettings *self, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); nm_agent_manager_save_secrets (priv->agent_mgr, - nm_connection_get_path (NM_CONNECTION (connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), for_agent, subject); g_object_unref (for_agent); @@ -1212,7 +1205,7 @@ pk_add_cb (NMAuthChain *chain, send_agent_owned_secrets (self, added, subject); g_clear_error (&error); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } /* FIXME: remove if/when kernel supports adhoc wpa */ @@ -1365,9 +1358,9 @@ settings_add_connection_add_cb (NMSettings *self, g_dbus_method_invocation_return_gerror (context, error); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, NULL, subject, error->message); } else { - g_dbus_method_invocation_return_value ( - context, - g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(o)", + nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)))); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL, subject, NULL); } @@ -1570,7 +1563,7 @@ pk_hostname_cb (NMAuthChain *chain, else g_dbus_method_invocation_return_value (context, NULL); - nm_auth_chain_unref (chain); + nm_auth_chain_destroy (chain); } static void @@ -1618,27 +1611,24 @@ static gboolean have_connection_for_device (NMSettings *self, NMDevice *device) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data; NMSettingConnection *s_con; NMSettingWired *s_wired; const char *setting_hwaddr; const char *perm_hw_addr; + NMSettingsConnection *connection; g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); perm_hw_addr = nm_device_get_permanent_hw_address (device); /* Find a wired connection locked to the given MAC address, if any */ - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) { - NMConnection *connection = NM_CONNECTION (data); + c_list_for_each_entry (connection, &priv->connections_lst_head, _connections_lst) { const char *ctype, *iface; - if (!nm_device_check_connection_compatible (device, connection)) + if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) continue; - s_con = nm_connection_get_setting_connection (connection); + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); iface = nm_setting_connection_get_interface_name (s_con); if (iface && strcmp (iface, nm_device_get_iface (device)) != 0) @@ -1649,7 +1639,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device) && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) continue; - s_wired = nm_connection_get_setting_wired (connection); + s_wired = nm_connection_get_setting_wired (NM_CONNECTION (connection)); if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) { /* No wired setting; therefore the PPPoE connection applies to any device */ @@ -1677,26 +1667,6 @@ have_connection_for_device (NMSettings *self, NMDevice *device) return FALSE; } -static void default_wired_clear_tag (NMSettings *self, - NMDevice *device, - NMSettingsConnection *connection, - gboolean add_to_no_auto_default); - -static void -default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSettings *self) -{ - NMDevice *device; - - /* When the default wired connection is removed (either deleted or saved to - * a new persistent connection by a plugin), write the MAC address of the - * wired device to the config file and don't create a new default wired - * connection for that device again. - */ - device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ()); - if (device) - default_wired_clear_tag (self, device, connection, TRUE); -} - static void default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, gboolean by_user, NMSettings *self) { @@ -1729,7 +1699,6 @@ default_wired_clear_tag (NMSettings *self, g_object_set_qdata (G_OBJECT (connection), _default_wired_device_quark (), NULL); g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), NULL); - g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_removed_cb), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); if (add_to_no_auto_default) @@ -1781,8 +1750,6 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (default_wired_connection_updated_by_user_cb), self); - g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED, - G_CALLBACK (default_wired_connection_removed_cb), self); _LOGI ("(%s): created default wired connection '%s'", nm_device_get_iface (device), @@ -1855,10 +1822,8 @@ nm_settings_start (NMSettings *self, GError **error) /* Load the plugins; fail if a plugin is not found. */ plugins = nm_config_data_get_plugins (nm_config_get_data_orig (priv->config), TRUE); - if (!load_plugins (self, (const char **) plugins, error)) { - g_object_unref (self); + if (!load_plugins (self, (const char **) plugins, error)) return FALSE; - } load_connections (self); check_startup_complete (self); @@ -1883,18 +1848,19 @@ get_property (GObject *object, guint prop_id, NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); const GSList *specs, *iter; - GHashTableIter citer; - GPtrArray *array; - const char *path; + guint i; + char **strvs; + const char **strv; switch (prop_id) { case PROP_UNMANAGED_SPECS: - array = g_ptr_array_new (); specs = nm_settings_get_unmanaged_specs (self); - for (iter = specs; iter; iter = g_slist_next (iter)) - g_ptr_array_add (array, g_strdup (iter->data)); - g_ptr_array_add (array, NULL); - g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); + strvs = g_new (char *, g_slist_length ((GSList *) specs) + 1); + i = 0; + for (iter = specs; iter; iter = iter->next) + strvs[i++] = g_strdup (iter->data); + strvs[i] = NULL; + g_value_take_boxed (value, strvs); break; case PROP_HOSTNAME: g_value_set_string (value, @@ -1906,12 +1872,11 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)); break; case PROP_CONNECTIONS: - array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); - g_hash_table_iter_init (&citer, priv->connections); - while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL)) - g_ptr_array_add (array, g_strdup (path)); - g_ptr_array_add (array, NULL); - g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); + strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head, + priv->connections_len, + G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst), + TRUE); + g_value_take_boxed (value, nm_utils_strv_make_deep_copied (strv)); break; case PROP_STARTUP_COMPLETE: g_value_set_boolean (value, nm_settings_get_startup_complete (self)); @@ -1929,7 +1894,7 @@ nm_settings_init (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); + c_list_init (&priv->connections_lst_head); priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); priv->config = g_object_ref (nm_config_get ()); @@ -1947,7 +1912,7 @@ dispose (GObject *object) NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref); + g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_destroy); priv->auths = NULL; g_object_unref (priv->agent_mgr); @@ -1968,8 +1933,9 @@ finalize (GObject *object) NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - g_hash_table_destroy (priv->connections); - _clear_connections_cached_list (&priv->connections_cached_list); + _clear_connections_cached_list (priv); + + nm_assert (c_list_is_empty (&priv->connections_lst_head)); g_slist_free_full (priv->unmanaged_specs, g_free); g_slist_free_full (priv->unrecognized_specs, g_free); diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 2a5a5053c..7d56f7b43 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -70,14 +70,6 @@ NMSettings *nm_settings_get (void); NMSettings *nm_settings_new (void); gboolean nm_settings_start (NMSettings *self, GError **error); -typedef void (*NMSettingsForEachFunc) (NMSettings *settings, - NMSettingsConnection *connection, - gpointer user_data); - -void nm_settings_for_each_connection (NMSettings *settings, - NMSettingsForEachFunc for_each_func, - gpointer user_data); - typedef void (*NMSettingsAddCallback) (NMSettings *settings, NMSettingsConnection *connection, GError *error, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index e66ecfdcc..2d95b535a 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -326,21 +326,21 @@ update_connection (SettingsPluginIfcfg *self, if (new_unmanaged || new_unrecognized) { if (!old_unmanaged && !old_unrecognized) { + /* ref connection first, because we put it into priv->connections below. + * Emitting signal-removed might otherwise delete it. */ g_object_ref (connection_by_uuid); + /* Unexport the connection by telling the settings service it's * been removed. */ nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid)); - /* Remove the path so that claim_connection() doesn't complain later when - * interface gets managed and connection is re-added. */ - nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL); /* signal_remove() will end up removing the connection from our hash, * so add it back now. */ g_hash_table_insert (priv->connections, g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))), - connection_by_uuid); + connection_by_uuid/*<< took reference above*/); } } else { if (old_unmanaged /* && !new_unmanaged */) { @@ -372,7 +372,9 @@ update_connection (SettingsPluginIfcfg *self, _LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else _LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new); + g_hash_table_insert (priv->connections, + g_strdup (uuid), + connection_new /* take reference */); g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), @@ -748,7 +750,7 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, return; } - path = nm_connection_get_path (NM_CONNECTION (connection)); + path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)); if (!path) { g_dbus_method_invocation_return_error (context, NM_SETTINGS_ERROR, diff --git a/src/tests/config/nm-test-device.c b/src/tests/config/nm-test-device.c index 3ec866f5e..496315834 100644 --- a/src/tests/config/nm-test-device.c +++ b/src/tests/config/nm-test-device.c @@ -57,7 +57,7 @@ nm_test_device_init (NMTestDevice *self) } /* We jump over NMDevice's construct/destruct methods, which require NMPlatform - * and NMConnectionProvider to be initialized. + * and NMSettings to be initialized. */ static void constructed (GObject *object) diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 632f2c33c..38eaf25e9 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -232,13 +232,13 @@ test_nm_utils_log_connection_diff (void) connection = nm_simple_connection_new (); nm_connection_add_setting (connection, nm_setting_connection_new ()); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> "); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test1", ">>> ", NULL); nm_connection_add_setting (connection, nm_setting_wired_new ()); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> "); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test2", ">>> ", NULL); connection2 = nm_simple_connection_new_clone (connection); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> "); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test3", ">>> ", NULL); g_object_set (nm_connection_get_setting_connection (connection), NM_SETTING_CONNECTION_ID, "id", @@ -248,24 +248,24 @@ test_nm_utils_log_connection_diff (void) NM_SETTING_CONNECTION_ID, "id2", NM_SETTING_CONNECTION_MASTER, "master2", NULL); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> "); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test4", ">>> ", NULL); nm_connection_add_setting (connection, nm_setting_802_1x_new ()); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> "); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test5", ">>> ", NULL); g_object_set (nm_connection_get_setting_802_1x (connection), NM_SETTING_802_1X_PASSWORD, "id2", NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, NULL); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> "); - nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> "); - nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> "); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test6", ">>> ", NULL); + nm_utils_log_connection_diff (connection, connection2, LOGL_DEBUG, LOGD_CORE, "test7", ">>> ", NULL); + nm_utils_log_connection_diff (connection2, connection, LOGL_DEBUG, LOGD_CORE, "test8", ">>> ", NULL); g_clear_object (&connection); g_clear_object (&connection2); connection = nmtst_create_minimal_connection ("id-vpn-1", NULL, NM_SETTING_VPN_SETTING_NAME, NULL); - nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test-vpn-1", ">>> "); + nm_utils_log_connection_diff (connection, NULL, LOGL_DEBUG, LOGD_CORE, "test-vpn-1", ">>> ", NULL); g_clear_object (&connection); } |