diff options
Diffstat (limited to 'src/core/nm-auth-manager.c')
| -rw-r--r-- | src/core/nm-auth-manager.c | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/src/core/nm-auth-manager.c b/src/core/nm-auth-manager.c new file mode 100644 index 00000000..9470838c --- /dev/null +++ b/src/core/nm-auth-manager.c @@ -0,0 +1,751 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2014 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#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" +#include "NetworkManagerUtils.h" + +#define POLKIT_SERVICE "org.freedesktop.PolicyKit1" +#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(PROP_POLKIT_ENABLED, ); + +enum { + CHANGED_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = {0}; + +typedef struct { + CList calls_lst_head; + GDBusConnection *dbus_connection; + GCancellable * main_cancellable; + char * name_owner; + guint64 call_numid_counter; + 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; + +struct _NMAuthManager { + GObject parent; + NMAuthManagerPrivate _priv; +}; + +struct _NMAuthManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE(NMAuthManager, nm_auth_manager, G_TYPE_OBJECT) + +#define NM_AUTH_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAuthManager, NM_IS_AUTH_MANAGER) + +NM_DEFINE_SINGLETON_REGISTER(NMAuthManager); + +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "auth" +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + char __prefix[30] = _NMLOG_PREFIX_NAME; \ + \ + if ((self) != singleton_instance) \ + g_snprintf(__prefix, \ + sizeof(__prefix), \ + ""_NMLOG_PREFIX_NAME \ + "[%p]", \ + (self)); \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + 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 +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)->dbus_connection != NULL; +} + +/*****************************************************************************/ + +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), +} PolkitCheckAuthorizationFlags; + +struct _NMAuthManagerCallId { + CList calls_lst; + NMAuthManager * self; + GCancellable * dbus_cancellable; + NMAuthManagerCheckAuthorizationCallback callback; + gpointer user_data; + guint64 call_numid; + guint idle_id; + bool idle_is_authorized : 1; +}; + +#define cancellation_id_to_str_a(call_numid) \ + nm_sprintf_bufa(NM_STRLEN(CANCELLATION_ID_PREFIX) + 60, \ + CANCELLATION_ID_PREFIX "%" G_GUINT64_FORMAT, \ + (call_numid)) + +static void +_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_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_id_invoke_callback(NMAuthManagerCallId *call_id, + gboolean is_authorized, + gboolean is_challenge, + GError * error) +{ + 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(GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMAuthManagerCallId *call_id = user_data; + gs_unref_variant GVariant *value = NULL; + gs_free_error GError *error = NULL; + + 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) + _LOG2T(call_id, "cancel request failed: %s", error->message); + else + _LOG2T(call_id, "cancel request succeeded"); + + _call_id_free(call_id); +} + +static void +_call_check_authorize_cb(GObject *proxy, GAsyncResult *res, gpointer user_data) +{ + 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; + + /* 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); + + self = call_id->self; + priv = NM_AUTH_MANAGER_GET_PRIVATE(self); + + value = g_dbus_connection_call_finish(G_DBUS_CONNECTION(proxy), res, &error); + + 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->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: + * 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 + * - 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_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->main_cancellable, + cancel_check_authorization_cb, + call_id); + return; + } + + 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); + + _call_id_invoke_callback(call_id, is_authorized, is_challenge, error); +} + +static gboolean +_call_on_idle(gpointer user_data) +{ + NMAuthManagerCallId *call_id = user_data; + gboolean is_authorized; + gboolean is_challenge = FALSE; + + is_authorized = call_id->idle_is_authorized; + call_id->idle_id = 0; + + _LOG2T(call_id, + "completed: authorized=%d, challenge=%d (simulated)", + is_authorized, + is_challenge); + + _call_id_invoke_callback(call_id, is_authorized, is_challenge, NULL); + 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]; + NMAuthManagerCallId * call_id; + + 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_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; + + call_id = g_slice_new(NMAuthManagerCallId); + *call_id = (NMAuthManagerCallId){ + .self = g_object_ref(self), + .callback = callback, + .user_data = user_data, + .call_numid = ++priv->call_numid_counter, + .idle_is_authorized = TRUE, + }; + c_list_link_tail(&priv->calls_lst_head, &call_id->calls_lst); + + if (nm_auth_subject_get_subject_type(subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL) { + _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_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_id = g_idle_add(_call_on_idle, call_id); + } else if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) { + _LOG2T(call_id, + "CheckAuthorization(%s), subject=%s (PolicyKit disabled and always %s authorization " + "to non-root user)", + action_id, + nm_auth_subject_to_string(subject, subject_buf, sizeof(subject_buf)), + priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL ? "grant" : "deny"); + call_id->idle_is_authorized = (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL); + 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_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); + + 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->main_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; +} + +void +nm_auth_manager_check_authorization_cancel(NMAuthManagerCallId *call_id) +{ + NMAuthManager *self; + gs_free_error GError *error = NULL; + + g_return_if_fail(call_id); + + self = call_id->self; + + g_return_if_fail(NM_IS_AUTH_MANAGER(self)); + g_return_if_fail(!c_list_is_empty(&call_id->calls_lst)); + + 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); +} + +/*****************************************************************************/ + +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; + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE(self); + gboolean valid_sender; + + 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); +} + +/*****************************************************************************/ + +NMAuthManager * +nm_auth_manager_get() +{ + g_return_val_if_fail(singleton_instance, NULL); + + return singleton_instance; +} + +void +nm_auth_manager_force_shutdown(NMAuthManager *self) +{ + NMAuthManagerPrivate *priv; + + g_return_if_fail(NM_IS_AUTH_MANAGER(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 cancels all pending call-ids, we still need to keep + * a reference to self, in order to handle pending CancelCheckAuthorization + * requests. + * + * 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. + * - 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->main_cancellable); +} + +/*****************************************************************************/ + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE(object); + int v_int; + + switch (prop_id) { + case PROP_POLKIT_ENABLED: + /* construct-only */ + v_int = g_value_get_int(value); + g_return_if_fail(NM_IN_SET(v_int, + NM_AUTH_POLKIT_MODE_ROOT_ONLY, + NM_AUTH_POLKIT_MODE_ALLOW_ALL, + NM_AUTH_POLKIT_MODE_USE_POLKIT)); + priv->auth_polkit_mode = v_int; + nm_assert(priv->auth_polkit_mode == v_int); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_auth_manager_init(NMAuthManager *self) +{ + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE(self); + + c_list_init(&priv->calls_lst_head); + priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY; +} + +static void +constructed(GObject *object) +{ + NMAuthManager * self = NM_AUTH_MANAGER(object); + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE(self); + NMLogLevel logl = LOGL_DEBUG; + const char * create_message; + + G_OBJECT_CLASS(nm_auth_manager_parent_class)->constructed(object); + + if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) { + if (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ROOT_ONLY) + create_message = "polkit disabled, root-only"; + else + create_message = "polkit disabled, allow-all"; + goto out; + } + + 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 only root will be authorized."; + priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY; + goto out; + } + + 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"; + +out: + _NMLOG(logl, "create auth-manager: %s", create_message); +} + +NMAuthManager * +nm_auth_manager_setup(NMAuthPolkitMode auth_polkit_mode) +{ + NMAuthManager *self; + + g_return_val_if_fail(!singleton_instance, singleton_instance); + nm_assert(NM_IN_SET(auth_polkit_mode, + NM_AUTH_POLKIT_MODE_ROOT_ONLY, + NM_AUTH_POLKIT_MODE_ALLOW_ALL, + NM_AUTH_POLKIT_MODE_USE_POLKIT)); + + self = g_object_new(NM_TYPE_AUTH_MANAGER, + NM_AUTH_MANAGER_POLKIT_ENABLED, + (int) auth_polkit_mode, + NULL); + _LOGD("set instance"); + + singleton_instance = self; + nm_singleton_instance_register(); + + nm_log_dbg(LOGD_CORE, + "setup %s singleton (" NM_HASH_OBFUSCATE_PTR_FMT ")", + "NMAuthManager", + NM_HASH_OBFUSCATE_PTR(singleton_instance)); + + return self; +} + +static void +dispose(GObject *object) +{ + NMAuthManager * self = NM_AUTH_MANAGER(object); + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE(self); + + _LOGD("dispose"); + + nm_assert(c_list_is_empty(&priv->calls_lst_head)); + + priv->disposing = TRUE; + + nm_clear_g_cancellable(&priv->main_cancellable); + + 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_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 +nm_auth_manager_class_init(NMAuthManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->set_property = set_property; + object_class->constructed = constructed; + object_class->dispose = dispose; + + obj_properties[PROP_POLKIT_ENABLED] = + g_param_spec_int(NM_AUTH_MANAGER_POLKIT_ENABLED, + "", + "", + NM_AUTH_POLKIT_MODE_ROOT_ONLY, + NM_AUTH_POLKIT_MODE_USE_POLKIT, + NM_AUTH_POLKIT_MODE_USE_POLKIT, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + signals[CHANGED_SIGNAL] = g_signal_new(NM_AUTH_MANAGER_SIGNAL_CHANGED, + NM_TYPE_AUTH_MANAGER, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} |