auth-manager: drop GDBusProxy and use GDBusConnection directly

Aside avoiding the unnecessary overhead of GDBusProxy, this simplifies
NMAuthManager because the instance is ready from the start to use D-Bus.

Previously, in the early phase requests needed to be queued until
GDBusProxy could be created asynchronously. Now, there is nothing
asynchronous involved during construction of the NMAuthManager (and
of course there are no blocking calls).
This commit is contained in:
Thomas Haller 2019-05-04 12:46:17 +02:00
parent 458a5e6531
commit 6153cb0000

View file

@ -23,6 +23,7 @@
#include "nm-auth-manager.h"
#include "c-list/src/c-list.h"
#include "nm-glib-aux/nm-dbus-aux.h"
#include "nm-errors.h"
#include "nm-core-internal.h"
#include "nm-dbus-manager.h"
@ -50,13 +51,15 @@ static guint signals[LAST_SIGNAL] = {0};
typedef struct {
CList calls_lst_head;
GDBusProxy *proxy;
GCancellable *new_proxy_cancellable;
GCancellable *cancel_cancellable;
GDBusConnection *dbus_connection;
GCancellable *shutdown_cancellable;
guint64 call_numid_counter;
bool polkit_enabled:1;
guint name_owner_changed_id;
guint changed_signal_id;
bool dbus_has_owner:1;
bool disposing:1;
bool shutting_down:1;
bool polkit_enabled_construct_only:1;
} NMAuthManagerPrivate;
struct _NMAuthManager {
@ -114,7 +117,7 @@ nm_auth_manager_get_polkit_enabled (NMAuthManager *self)
{
g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
return NM_AUTH_MANAGER_GET_PRIVATE (self)->polkit_enabled;
return NM_AUTH_MANAGER_GET_PRIVATE (self)->dbus_connection != NULL;
}
/*****************************************************************************/
@ -132,7 +135,6 @@ typedef enum {
struct _NMAuthManagerCallId {
CList calls_lst;
NMAuthManager *self;
GVariant *dbus_parameters;
GCancellable *dbus_cancellable;
NMAuthManagerCheckAuthorizationCallback callback;
gpointer user_data;
@ -142,7 +144,7 @@ struct _NMAuthManagerCallId {
};
#define cancellation_id_to_str_a(call_numid) \
nm_sprintf_bufa (NM_STRLEN (CANCELLATION_ID_PREFIX) + 20, \
nm_sprintf_bufa (NM_STRLEN (CANCELLATION_ID_PREFIX) + 60, \
CANCELLATION_ID_PREFIX"%"G_GUINT64_FORMAT, \
(call_numid))
@ -151,8 +153,6 @@ _call_id_free (NMAuthManagerCallId *call_id)
{
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
@ -183,7 +183,7 @@ _call_id_invoke_callback (NMAuthManagerCallId *call_id,
}
static void
cancel_check_authorization_cb (GObject *proxy,
cancel_check_authorization_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
@ -191,7 +191,7 @@ cancel_check_authorization_cb (GObject *proxy,
gs_unref_variant GVariant *value = NULL;
gs_free_error GError *error= NULL;
value = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error);
value = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
_LOG2T (call_id, "cancel request was cancelled");
else if (error)
@ -225,18 +225,18 @@ _call_check_authorize_cb (GObject *proxy,
self = call_id->self;
priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
value = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, G_VARIANT_TYPE ("((bba{ss}))"), &error);
value = g_dbus_connection_call_finish (G_DBUS_CONNECTION (proxy), res, &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) {
if (!priv->shutdown_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
* shutdown_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
@ -245,15 +245,19 @@ _call_check_authorize_cb (GObject *proxy,
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);
g_dbus_connection_call (priv->dbus_connection,
POLKIT_SERVICE,
POLKIT_OBJECT_PATH,
POLKIT_INTERFACE,
"CancelCheckAuthorization",
g_variant_new ("(s)",
cancellation_id_to_str_a (call_id->call_numid)),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NONE,
CANCELLATION_TIMEOUT_MS,
priv->shutdown_cancellable,
cancel_check_authorization_cb,
call_id);
return;
}
@ -271,30 +275,6 @@ _call_check_authorize_cb (GObject *proxy,
_call_id_invoke_callback (call_id, is_authorized, is_challenge, error);
}
static void
_call_check_authorize (NMAuthManagerCallId *call_id)
{
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",
g_steal_pointer (&call_id->dbus_parameters),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT, /* no timeout */
call_id->dbus_cancellable,
_call_check_authorize_cb,
call_id);
}
static gboolean
_call_on_idle (gpointer user_data)
{
@ -345,9 +325,6 @@ nm_auth_manager_check_authorization (NMAuthManager *self,
NMAuthManagerPrivate *priv;
PolkitCheckAuthorizationFlags flags;
char subject_buf[64];
GVariantBuilder builder;
GVariant *subject_value;
GVariant *details_value;
NMAuthManagerCallId *call_id;
g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), NULL);
@ -375,7 +352,7 @@ nm_auth_manager_check_authorization (NMAuthManager *self,
};
c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst);
if (!priv->polkit_enabled) {
if (!priv->dbus_connection) {
_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);
@ -387,12 +364,12 @@ nm_auth_manager_check_authorization (NMAuthManager *self,
_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 {
GVariant *parameters;
GVariantBuilder builder;
GVariant *subject_value;
GVariant *details_value;
subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject);
nm_assert (g_variant_is_floating (subject_value));
@ -400,18 +377,31 @@ nm_auth_manager_check_authorization (NMAuthManager *self,
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);
}
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));
_LOG2T (call_id, "CheckAuthorization(%s), subject=%s", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
call_id->dbus_cancellable = g_cancellable_new ();
nm_assert (priv->shutdown_cancellable);
g_dbus_connection_call (priv->dbus_connection,
POLKIT_SERVICE,
POLKIT_OBJECT_PATH,
POLKIT_INTERFACE,
"CheckAuthorization",
parameters,
G_VARIANT_TYPE ("((bba{ss}))"),
G_DBUS_CALL_FLAGS_NONE,
G_MAXINT, /* no timeout */
call_id->dbus_cancellable,
_call_check_authorize_cb,
call_id);
}
return call_id;
@ -450,108 +440,85 @@ _emit_changed_signal (NMAuthManager *self)
}
static void
_log_name_owner (NMAuthManager *self, char **out_name_owner)
name_owner_changed (NMAuthManager *self,
const char *owner,
gboolean force_changed_signal)
{
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
gs_free char *name_owner = NULL;
gboolean had_owner;
name_owner = g_dbus_proxy_get_name_owner (priv->proxy);
if (name_owner)
_LOGD ("dbus name owner: '%s'", name_owner);
owner = nm_str_not_empty (owner);
if (!owner)
_LOGT ("D-Bus name for PolKit has no owner");
else
_LOGD ("dbus name owner: none");
_LOGT ("D-Bus name for PolKit has owner %s", owner);
NM_SET_OUT (out_name_owner, g_steal_pointer (&name_owner));
}
had_owner = priv->dbus_has_owner;
priv->dbus_has_owner = !!owner;
static void
_dbus_on_name_owner_notify_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NMAuthManager *self = user_data;
gs_free char *name_owner = NULL;
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);
if (!priv->dbus_has_owner) {
if ( had_owner
|| force_changed_signal) {
/* when the name disappears, we also want to raise a emit signal.
* When it appears, we raise one already. */
_emit_changed_signal (self);
}
}
}
static void
_dbus_on_changed_signal_cb (GDBusProxy *proxy,
gpointer user_data)
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)
{
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 (user_data, new_owner, FALSE);
}
static void
get_name_owner_cb (const char *name_owner,
GError *error,
gpointer user_data)
{
if ( !name_owner
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
/* until now the name-owner state was undecided. Pass TRUE to name_owner_changed()
* so we force emitting a a changed signal (iff we have no name owner). */
name_owner_changed (user_data, name_owner, TRUE);
}
static void
changed_signal_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;
nm_assert (NM_AUTH_MANAGER_GET_PRIVATE (self)->proxy == proxy);
_LOGD ("dbus signal: \"Changed\"");
_emit_changed_signal (self);
}
static void
_dbus_new_proxy_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
NMAuthManager *self;
NMAuthManagerPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
NMAuthManagerCallId *call_id;
proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
priv->proxy = proxy;
g_clear_object (&priv->new_proxy_cancellable);
if (!priv->proxy) {
_LOGE ("could not create polkit proxy: %s", error->message);
again:
c_list_for_each_entry (call_id, &priv->calls_lst_head, calls_lst) {
if (call_id->dbus_parameters) {
_LOG2T (call_id, "completed: failed due to no D-Bus proxy after startup");
_call_id_invoke_callback (call_id, FALSE, FALSE, error);
goto again;
}
}
return;
}
priv->cancel_cancellable = g_cancellable_new ();
g_signal_connect (priv->proxy,
"notify::g-name-owner",
G_CALLBACK (_dbus_on_name_owner_notify_cb),
self);
_nm_dbus_signal_connect (priv->proxy, "Changed", NULL,
G_CALLBACK (_dbus_on_changed_signal_cb),
self);
_log_name_owner (self, NULL);
c_list_for_each_entry (call_id, &priv->calls_lst_head, calls_lst) {
if (call_id->dbus_parameters) {
_LOG2T (call_id, "CheckAuthorization invoke now");
_call_check_authorize (call_id);
}
}
_emit_changed_signal (self);
}
/*****************************************************************************/
NMAuthManager *
@ -593,7 +560,7 @@ nm_auth_manager_force_shutdown (NMAuthManager *self)
*/
priv->shutting_down = TRUE;
nm_clear_g_cancellable (&priv->cancel_cancellable);
nm_clear_g_cancellable (&priv->shutdown_cancellable);
}
/*****************************************************************************/
@ -606,7 +573,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *p
switch (prop_id) {
case PROP_POLKIT_ENABLED:
/* construct-only */
priv->polkit_enabled = !!g_value_get_boolean (value);
priv->polkit_enabled_construct_only = !!g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -629,36 +596,51 @@ constructed (GObject *object)
{
NMAuthManager *self = NM_AUTH_MANAGER (object);
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
GDBusConnection *dbus_connection;
NMLogLevel logl = LOGL_DEBUG;
const char *create_message;
G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object);
if (!priv->polkit_enabled) {
if (!priv->polkit_enabled_construct_only) {
create_message = "polkit disabled";
goto out;
}
dbus_connection = NM_MAIN_DBUS_CONNECTION_GET;
if (!dbus_connection) {
priv->polkit_enabled = FALSE;
priv->dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET);
if (!priv->dbus_connection) {
/* This warrants an info level message. */
logl = LOGL_INFO;
create_message = "D-Bus connection not available. Polkit is disabled and all requests are authenticated.";
goto out;
}
priv->new_proxy_cancellable = g_cancellable_new ();
g_dbus_proxy_new (dbus_connection,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
POLKIT_SERVICE,
POLKIT_OBJECT_PATH,
POLKIT_INTERFACE,
priv->new_proxy_cancellable,
_dbus_new_proxy_cb,
self);
priv->shutdown_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);
nm_dbus_connection_call_get_name_owner (priv->dbus_connection,
POLKIT_SERVICE,
-1,
priv->shutdown_cancellable,
get_name_owner_cb,
self);
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);
create_message = "polkit enabled";
out:
@ -697,15 +679,17 @@ dispose (GObject *object)
priv->disposing = TRUE;
nm_clear_g_cancellable (&priv->new_proxy_cancellable);
nm_clear_g_cancellable (&priv->cancel_cancellable);
nm_clear_g_cancellable (&priv->shutdown_cancellable);
if (priv->proxy) {
g_signal_handlers_disconnect_by_data (priv->proxy, self);
g_clear_object (&priv->proxy);
}
nm_clear_g_dbus_connection_signal (priv->dbus_connection,
&priv->name_owner_changed_id);
nm_clear_g_dbus_connection_signal (priv->dbus_connection,
&priv->changed_signal_id);
G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object);
g_clear_object (&priv->dbus_connection);
}
static void