diff options
author | Thomas Haller <thaller@redhat.com> | 2020-04-11 08:17:56 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-04-21 09:37:27 +0200 |
commit | b307ebf9a43a172db7c85587f8b57ebcc733ec80 (patch) | |
tree | 21f18d0c89a7caa905795754ca01ec093a06dde2 | |
parent | 938aca3fabe62b65a4b5474866768aeb8d356190 (diff) | |
download | NetworkManager-b307ebf9a43a172db7c85587f8b57ebcc733ec80.tar.gz |
auth-manager: watch PolicyKit name owner to emit changed signal when name owner appearsth/auth-manager-name-owner
We shall emit a changed signal when PolicyKit changes. That implies also
emitting the signal when PolicyKit starts. Watch the name owner for
that.
Note that I don't manager to actually receive the "Changed" signal from
PolicyKit. There is some bug there, but I am out of ideas.
-rw-r--r-- | src/nm-auth-manager.c | 171 |
1 files changed, 144 insertions, 27 deletions
diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 88e6cb9433..5b3702ecb6 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -37,11 +37,14 @@ static guint signals[LAST_SIGNAL] = {0}; typedef struct { CList calls_lst_head; GDBusConnection *dbus_connection; - GCancellable *shutdown_cancellable; + GCancellable *main_cancellable; + char *name_owner; guint64 call_numid_counter; - guint changed_signal_id; + guint changed_id; + guint name_owner_changed_id; bool disposing:1; bool shutting_down:1; + bool got_name_owner:1; NMAuthPolkitMode auth_polkit_mode:3; } NMAuthManagerPrivate; @@ -105,6 +108,12 @@ nm_auth_manager_get_polkit_enabled (NMAuthManager *self) /*****************************************************************************/ +static void +_emit_changed_signal (NMAuthManager *self) +{ + g_signal_emit (self, signals[CHANGED_SIGNAL], 0); +} + typedef enum { POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0), @@ -204,17 +213,18 @@ _call_check_authorize_cb (GObject *proxy, priv = NM_AUTH_MANAGER_GET_PRIVATE (self); value = g_dbus_connection_call_finish (G_DBUS_CONNECTION (proxy), res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + + if (nm_utils_error_is_cancelled (error)) { /* call_id was cancelled externally, but _call_id_free() kept call_id * alive (and it has still the reference on @self. */ - if (!priv->shutdown_cancellable) { + if (!priv->main_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 - * shutdown_cancellable was still set. It means, somebody called force-shutdown + * nm_auth_manager_check_authorization() only scheduled the D-Bus request at a time when + * main_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 @@ -233,7 +243,7 @@ _call_check_authorize_cb (GObject *proxy, G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NONE, CANCELLATION_TIMEOUT_MS, - priv->shutdown_cancellable, + priv->main_cancellable, cancel_check_authorization_cb, call_id); return; @@ -357,7 +367,7 @@ nm_auth_manager_check_authorization (NMAuthManager *self, call_id->dbus_cancellable = g_cancellable_new (); - nm_assert (priv->shutdown_cancellable); + nm_assert (priv->main_cancellable); g_dbus_connection_call (priv->dbus_connection, POLKIT_SERVICE, @@ -411,9 +421,95 @@ changed_signal_cb (GDBusConnection *connection, gpointer user_data) { NMAuthManager *self = user_data; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + gboolean valid_sender; - _LOGD ("dbus signal: \"Changed\""); - g_signal_emit (self, signals[CHANGED_SIGNAL], 0); + nm_assert (nm_streq0 (signal_name, "Changed")); + + valid_sender = nm_streq0 (priv->name_owner, sender_name); + + _LOGD ("dbus-signal: \"Changed\" notification%s", valid_sender ? "" : " (ignore)"); + + if (valid_sender) + _emit_changed_signal (self); +} + +static void +_name_owner_changed (NMAuthManager *self, + const char *name_owner, + gboolean is_initial) +{ + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + gboolean is_changed; + gs_free char *old_name_owner = NULL; + + if (is_initial) + priv->got_name_owner = TRUE; + else { + if (!priv->got_name_owner) + return; + } + + name_owner = nm_str_not_empty (name_owner); + + is_changed = !nm_streq0 (priv->name_owner, name_owner); + if (is_changed) { + old_name_owner = g_steal_pointer (&priv->name_owner); + priv->name_owner = g_strdup (name_owner); + } else { + if (!is_initial) + return; + } + + if (!priv->name_owner) { + if (is_initial) + _LOGT ("name-owner: polkit not running"); + else + _LOGT ("name-owner: polkit stopped (was %s)", old_name_owner); + } else { + if (is_initial) + _LOGT ("name-owner: polkit is running (now %s)", priv->name_owner); + else if (old_name_owner) + _LOGT ("name-owner: polkit restarted (now %s, was %s)", priv->name_owner, old_name_owner); + else + _LOGT ("name-owner: polkit started (now %s)", priv->name_owner); + } + + if (priv->name_owner) + _emit_changed_signal (self); +} + +static void +_name_owner_changed_cb (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMAuthManager *self = user_data; + const char *new_owner; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) + return; + + g_variant_get (parameters, + "(&s&s&s)", + NULL, + NULL, + &new_owner); + + _name_owner_changed (self, new_owner, FALSE); +} + +static void +_name_owner_get_cb (const char *name_owner, + GError *error, + gpointer user_data) +{ + if (!nm_utils_error_is_cancelled (error)) + _name_owner_changed (user_data, name_owner, TRUE); } /*****************************************************************************/ @@ -435,14 +531,17 @@ nm_auth_manager_force_shutdown (NMAuthManager *self) priv = NM_AUTH_MANAGER_GET_PRIVATE (self); + /* FIXME(shutdown): ensure we properly call this API during shutdown as + * described next. */ + /* 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 + * Even if the caller cancels 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: + * To do a coordinated 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. @@ -457,7 +556,7 @@ nm_auth_manager_force_shutdown (NMAuthManager *self) */ priv->shutting_down = TRUE; - nm_clear_g_cancellable (&priv->shutdown_cancellable); + nm_clear_g_cancellable (&priv->main_cancellable); } /*****************************************************************************/ @@ -523,18 +622,31 @@ constructed (GObject *object) goto out; } - priv->shutdown_cancellable = g_cancellable_new (); - - priv->changed_signal_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, - POLKIT_SERVICE, - POLKIT_INTERFACE, - "Changed", - POLKIT_OBJECT_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - changed_signal_cb, - self, - NULL); + priv->main_cancellable = g_cancellable_new (); + + priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection, + POLKIT_SERVICE, + _name_owner_changed_cb, + self, + NULL); + + priv->changed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + POLKIT_SERVICE, + POLKIT_INTERFACE, + "Changed", + POLKIT_OBJECT_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + changed_signal_cb, + self, + NULL); + + nm_dbus_connection_call_get_name_owner (priv->dbus_connection, + POLKIT_SERVICE, + -1, + priv->main_cancellable, + _name_owner_get_cb, + self); create_message = "polkit enabled"; @@ -578,14 +690,19 @@ dispose (GObject *object) priv->disposing = TRUE; - nm_clear_g_cancellable (&priv->shutdown_cancellable); + nm_clear_g_cancellable (&priv->main_cancellable); nm_clear_g_dbus_connection_signal (priv->dbus_connection, - &priv->changed_signal_id); + &priv->name_owner_changed_id); + + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->changed_id); G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object); g_clear_object (&priv->dbus_connection); + + nm_clear_g_free (&priv->name_owner); } static void |