diff options
Diffstat (limited to 'libnm/nm-secret-agent-old.c')
| -rw-r--r-- | libnm/nm-secret-agent-old.c | 1995 |
1 files changed, 0 insertions, 1995 deletions
diff --git a/libnm/nm-secret-agent-old.c b/libnm/nm-secret-agent-old.c deleted file mode 100644 index 8f826ed8..00000000 --- a/libnm/nm-secret-agent-old.c +++ /dev/null @@ -1,1995 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2010 - 2011 Red Hat, Inc. - */ - -#include "libnm/nm-default-libnm.h" - -#include "nm-secret-agent-old.h" - -#include "c-list/src/c-list.h" -#include "nm-core-internal.h" -#include "nm-dbus-helpers.h" -#include "nm-dbus-interface.h" -#include "nm-enum-types.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-glib-aux/nm-time-utils.h" -#include "nm-simple-connection.h" - -#define REGISTER_RETRY_TIMEOUT_MSEC 3000 -#define _CALL_REGISTER_TIMEOUT_MSEC 15000 - -/*****************************************************************************/ - -typedef struct { - char * connection_path; - char * setting_name; - GDBusMethodInvocation *context; - CList gsi_lst; - bool is_cancelling : 1; -} GetSecretsInfo; - -NM_GOBJECT_PROPERTIES_DEFINE(NMSecretAgentOld, - PROP_IDENTIFIER, - PROP_AUTO_REGISTER, - PROP_REGISTERED, - PROP_CAPABILITIES, - PROP_DBUS_CONNECTION, ); - -typedef struct { - GDBusConnection *dbus_connection; - GMainContext * main_context; - GMainContext * dbus_context; - GObject * context_busy_watcher; - GCancellable * name_owner_cancellable; - GCancellable * registering_cancellable; - GSource * registering_retry_source; - - NMLInitData *init_data; - - CList gsi_lst_head; - - CList pending_tasks_register_lst_head; - - char *identifier; - - NMRefString *name_owner_curr; - NMRefString *name_owner_next; - - gint64 registering_timeout_msec; - - guint name_owner_changed_id; - - guint exported_id; - - guint capabilities; - - guint8 registering_try_count; - - guint8 register_state_change_reenter : 2; - - bool session_bus : 1; - - bool auto_register : 1; - - bool is_registered : 1; - - bool is_enabled : 1; - - bool registration_force_unregister : 1; - - /* This is true, if we either are in the process of RegisterWithCapabilities() or - * are already successfully registered. - * - * This is only TRUE, if the name owner was authenticated to run as root user. - * - * It also means, we should follow up with an Unregister() call during shutdown. */ - bool registered_against_server : 1; - - bool is_initialized : 1; - bool is_destroyed : 1; -} NMSecretAgentOldPrivate; - -static void nm_secret_agent_old_initable_iface_init(GInitableIface *iface); -static void nm_secret_agent_old_async_initable_iface_init(GAsyncInitableIface *iface); - -G_DEFINE_ABSTRACT_TYPE_WITH_CODE( - NMSecretAgentOld, - nm_secret_agent_old, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, nm_secret_agent_old_initable_iface_init); - G_IMPLEMENT_INTERFACE(G_TYPE_ASYNC_INITABLE, nm_secret_agent_old_async_initable_iface_init);) - -#define NM_SECRET_AGENT_OLD_GET_PRIVATE(self) \ - (G_TYPE_INSTANCE_GET_PRIVATE((self), NM_TYPE_SECRET_AGENT_OLD, NMSecretAgentOldPrivate)) - -/*****************************************************************************/ - -#define _NMLOG(level, ...) \ - NML_DBUS_LOG((level), \ - "secret-agent[" NM_HASH_OBFUSCATE_PTR_FMT \ - "]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_HASH_OBFUSCATE_PTR(self) _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -static const GDBusInterfaceInfo interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_SECRET_AGENT, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_GDBUS_METHOD_INFO("GetSecrets", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("connection_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO("setting_name", "s"), - NM_DEFINE_GDBUS_ARG_INFO("hints", "as"), - NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("secrets", "a{sa{sv}}"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO("CancelGetSecrets", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO("setting_name", "s"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO("SaveSecrets", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("connection_path", "o"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO( - "DeleteSecrets", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("connection_path", "o"), ), ), ), ); - -/*****************************************************************************/ - -static void _register_state_change(NMSecretAgentOld *self); - -static void _register_dbus_call(NMSecretAgentOld *self); - -static void _init_complete(NMSecretAgentOld *self, GError *error_take); - -static void _register_state_complete(NMSecretAgentOld *self); - -/*****************************************************************************/ - -/** - * nm_secret_agent_old_get_dbus_connection: - * @self: the #NMSecretAgentOld instance - * - * Returns: (transfer none): the #GDBusConnection used by the secret agent. - * You may either set this as construct property %NM_SECRET_AGENT_OLD_DBUS_CONNECTION, - * or it will automatically set during initialization. - * - * Since: 1.24 - */ -GDBusConnection * -nm_secret_agent_old_get_dbus_connection(NMSecretAgentOld *self) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), NULL); - - return NM_SECRET_AGENT_OLD_GET_PRIVATE(self)->dbus_connection; -} - -/** - * nm_secret_agent_old_get_main_context: - * @self: the #NMSecretAgentOld instance - * - * Returns: (transfer none): the #GMainContext instance associate with the - * instance. This is the g_main_context_get_thread_default() at the time - * when creating the instance. - * - * Since: 1.24 - */ -GMainContext * -nm_secret_agent_old_get_main_context(NMSecretAgentOld *self) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), NULL); - - return NM_SECRET_AGENT_OLD_GET_PRIVATE(self)->main_context; -} - -/** - * nm_secret_agent_old_get_context_busy_watcher: - * @self: the #NMSecretAgentOld instance - * - * Returns a #GObject that stays alive as long as there are pending - * requests in the #GDBusConnection. Such requests keep the #GMainContext - * alive, and thus you may want to keep iterating the context as long - * until a weak reference indicates that this object is gone. This is - * useful because even when you destroy the instance right away (and all - * the internally pending requests get cancelled), any pending g_dbus_connection_call() - * requests will still invoke the result on the #GMainContext. Hence, this - * allows you to know how long you must iterate the context to know - * that all remains are cleaned up. - * - * Returns: (transfer none): a #GObject that you may register a weak pointer - * to know that the #GMainContext is still kept busy by @self. - * - * Since: 1.24 - */ -GObject * -nm_secret_agent_old_get_context_busy_watcher(NMSecretAgentOld *self) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), NULL); - - return NM_SECRET_AGENT_OLD_GET_PRIVATE(self)->context_busy_watcher; -} - -/** - * nm_secret_agent_old_get_dbus_name_owner: - * @self: the #NMSecretAgentOld instance - * - * Returns: the current D-Bus name owner. While this property - * is set while registering, it really only makes sense when - * the nm_secret_agent_old_get_registered() indicates that - * registration is successful. - * - * Since: 1.24 - */ -const char * -nm_secret_agent_old_get_dbus_name_owner(NMSecretAgentOld *self) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), NULL); - - return nm_ref_string_get_str(NM_SECRET_AGENT_OLD_GET_PRIVATE(self)->name_owner_curr); -} - -/** - * nm_secret_agent_old_get_registered: - * @self: a #NMSecretAgentOld - * - * Note that the secret agent transparently registers and re-registers - * as the D-Bus name owner appears. Hence, this property is not really - * useful. Also, to be graceful against races during registration, the - * instance will already accept requests while being in the process of - * registering. - * If you need to avoid races and want to wait until @self is registered, - * call nm_secret_agent_old_register_async(). If that function completes - * with success, you know the instance is registered. - * - * Returns: a %TRUE if the agent is registered, %FALSE if it is not. - **/ -gboolean -nm_secret_agent_old_get_registered(NMSecretAgentOld *self) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), FALSE); - - return NM_SECRET_AGENT_OLD_GET_PRIVATE(self)->is_registered; -} - -/*****************************************************************************/ - -static void -get_secret_info_free(GetSecretsInfo *info) -{ - nm_assert(info); - nm_assert(!info->context); - - c_list_unlink_stale(&info->gsi_lst); - g_free(info->connection_path); - g_free(info->setting_name); - nm_g_slice_free(info); -} - -static void -get_secret_info_complete_and_free(GetSecretsInfo *info, GVariant *secrets, GError *error) -{ - if (error) { - if (secrets) - nm_g_variant_unref_floating(secrets); - g_dbus_method_invocation_return_gerror(g_steal_pointer(&info->context), error); - } else { - g_dbus_method_invocation_return_value(g_steal_pointer(&info->context), - g_variant_new("(@a{sa{sv}})", secrets)); - } - get_secret_info_free(info); -} - -static void -get_secret_info_complete_and_free_error(GetSecretsInfo *info, - GQuark error_domain, - int error_code, - const char * error_message) -{ - g_dbus_method_invocation_return_error_literal(g_steal_pointer(&info->context), - error_domain, - error_code, - error_message); - get_secret_info_free(info); -} - -/*****************************************************************************/ - -static void -_dbus_connection_call_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - gs_unref_object GObject *context_busy_watcher = NULL; - GAsyncReadyCallback callback; - gpointer callback_user_data; - - nm_utils_user_data_unpack(user_data, &context_busy_watcher, &callback, &callback_user_data); - callback(source, result, callback_user_data); -} - -static void -_dbus_connection_call(NMSecretAgentOld * self, - const char * bus_name, - const char * object_path, - const char * interface_name, - const char * method_name, - GVariant * parameters, - const GVariantType *reply_type, - GDBusCallFlags flags, - int timeout_msec, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - nm_assert(nm_g_main_context_is_thread_default(priv->dbus_context)); - - g_dbus_connection_call( - priv->dbus_connection, - bus_name, - object_path, - interface_name, - method_name, - parameters, - reply_type, - flags, - timeout_msec, - cancellable, - callback ? _dbus_connection_call_cb : NULL, - callback - ? nm_utils_user_data_pack(g_object_ref(priv->context_busy_watcher), callback, user_data) - : NULL); -} - -/*****************************************************************************/ - -static GetSecretsInfo * -find_get_secrets_info(NMSecretAgentOldPrivate *priv, - const char * connection_path, - const char * setting_name) -{ - GetSecretsInfo *info; - - c_list_for_each_entry (info, &priv->gsi_lst_head, gsi_lst) { - if (nm_streq(connection_path, info->connection_path) - && nm_streq(setting_name, info->setting_name)) - return info; - } - return NULL; -} - -static void -_cancel_get_secret_request(NMSecretAgentOld *self, GetSecretsInfo *info, const char *message) -{ - c_list_unlink(&info->gsi_lst); - info->is_cancelling = TRUE; - - _LOGT("cancel get-secrets request \"%s\", \"%s\": %s", - info->connection_path, - info->setting_name, - message); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->cancel_get_secrets(self, - info->connection_path, - info->setting_name); - - get_secret_info_complete_and_free_error(info, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_AGENT_CANCELED, - message); -} - -static gboolean -verify_request(NMSecretAgentOld * self, - GDBusMethodInvocation *context, - GVariant * connection_dict, - const char * connection_path, - NMConnection ** out_connection, - GError ** error) -{ - gs_unref_object NMConnection *connection = NULL; - gs_free_error GError *local = NULL; - - if (!nm_dbus_path_not_empty(connection_path)) { - g_set_error_literal(error, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, - "Invalid connection: no connection path given."); - return FALSE; - } - - connection = _nm_simple_connection_new_from_dbus(connection_dict, - NM_SETTING_PARSE_FLAGS_BEST_EFFORT, - &local); - if (!connection) { - g_set_error(error, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, - "Invalid connection: %s", - local->message); - return FALSE; - } - - nm_connection_set_path(connection, connection_path); - NM_SET_OUT(out_connection, g_steal_pointer(&connection)); - return TRUE; -} - -static void -get_secrets_cb(NMSecretAgentOld *self, - NMConnection * connection, - GVariant * secrets, - GError * error, - gpointer user_data) -{ - GetSecretsInfo *info = user_data; - - if (info->is_cancelling) { - if (secrets) - nm_g_variant_unref_floating(secrets); - return; - } - - _LOGT("request: get-secrets request \"%s\", \"%s\" complete with %s%s%s", - info->connection_path, - info->setting_name, - NM_PRINT_FMT_QUOTED(error, "error: ", error->message, "", "success")); - - get_secret_info_complete_and_free(info, secrets, error); -} - -static void -impl_get_secrets(NMSecretAgentOld *self, GVariant *parameters, GDBusMethodInvocation *context) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - GError * error = NULL; - gs_unref_object NMConnection *connection = NULL; - GetSecretsInfo * info; - gs_unref_variant GVariant *arg_connection = NULL; - const char * arg_connection_path; - const char * arg_setting_name; - gs_free const char ** arg_hints = NULL; - guint32 arg_flags; - - g_variant_get(parameters, - "(@a{sa{sv}}&o&s^a&su)", - &arg_connection, - &arg_connection_path, - &arg_setting_name, - &arg_hints, - &arg_flags); - - if (!verify_request(self, context, arg_connection, arg_connection_path, &connection, &error)) { - g_dbus_method_invocation_take_error(context, error); - return; - } - - _LOGT("request: get-secrets(\"%s\", \"%s\")", arg_connection_path, arg_setting_name); - - info = find_get_secrets_info(priv, arg_connection_path, arg_setting_name); - if (info) - _cancel_get_secret_request(self, info, "Request aborted due to new request"); - - info = g_slice_new(GetSecretsInfo); - *info = (GetSecretsInfo){ - .context = context, - .connection_path = g_strdup(arg_connection_path), - .setting_name = g_strdup(arg_setting_name), - }; - c_list_link_tail(&priv->gsi_lst_head, &info->gsi_lst); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->get_secrets(self, - connection, - info->connection_path, - info->setting_name, - arg_hints, - arg_flags, - get_secrets_cb, - info); -} - -static void -impl_cancel_get_secrets(NMSecretAgentOld * self, - GVariant * parameters, - GDBusMethodInvocation *context) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - GetSecretsInfo * info; - const char * arg_connection_path; - const char * arg_setting_name; - - g_variant_get(parameters, "(&o&s)", &arg_connection_path, &arg_setting_name); - - info = find_get_secrets_info(priv, arg_connection_path, arg_setting_name); - if (!info) { - g_dbus_method_invocation_return_error_literal( - context, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_FAILED, - "No secrets request in progress for this connection."); - return; - } - - _cancel_get_secret_request(self, info, "Request cancelled by NetworkManager"); - - g_dbus_method_invocation_return_value(context, NULL); -} - -static void -save_secrets_cb(NMSecretAgentOld *self, NMConnection *connection, GError *error, gpointer user_data) -{ - GDBusMethodInvocation *context = user_data; - - if (error) - g_dbus_method_invocation_return_gerror(context, error); - else - g_dbus_method_invocation_return_value(context, NULL); -} - -static void -impl_save_secrets(NMSecretAgentOld *self, GVariant *parameters, GDBusMethodInvocation *context) -{ - gs_unref_object NMConnection *connection = NULL; - gs_unref_variant GVariant *arg_connection = NULL; - const char * arg_connection_path; - GError * error = NULL; - - g_variant_get(parameters, "(@a{sa{sv}}&o)", &arg_connection, &arg_connection_path); - - if (!verify_request(self, context, arg_connection, arg_connection_path, &connection, &error)) { - g_dbus_method_invocation_take_error(context, error); - return; - } - - _LOGT("request: save-secrets(\"%s\")", arg_connection_path); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->save_secrets(self, - connection, - arg_connection_path, - save_secrets_cb, - context); -} - -static void -delete_secrets_cb(NMSecretAgentOld *self, - NMConnection * connection, - GError * error, - gpointer user_data) -{ - GDBusMethodInvocation *context = user_data; - - if (error) - g_dbus_method_invocation_return_gerror(context, error); - else - g_dbus_method_invocation_return_value(context, NULL); -} - -static void -impl_delete_secrets(NMSecretAgentOld *self, GVariant *parameters, GDBusMethodInvocation *context) -{ - gs_unref_object NMConnection *connection = NULL; - gs_unref_variant GVariant *arg_connection = NULL; - const char * arg_connection_path; - GError * error = NULL; - - g_variant_get(parameters, "(@a{sa{sv}}&o)", &arg_connection, &arg_connection_path); - - if (!verify_request(self, context, arg_connection, arg_connection_path, &connection, &error)) { - g_dbus_method_invocation_take_error(context, error); - return; - } - - _LOGT("request: delete-secrets(\"%s\")", arg_connection_path); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->delete_secrets(self, - connection, - arg_connection_path, - delete_secrets_cb, - context); -} - -/*****************************************************************************/ - -/** - * nm_secret_agent_old_enable: - * @self: the #NMSecretAgentOld instance - * @enable: whether to enable or disable the listener. - * - * This has the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER - * property. - * - * Unlike most other functions, you may already call this function before - * initialization completes. - * - * Since: 1.24 - */ -void -nm_secret_agent_old_enable(NMSecretAgentOld *self, gboolean enable) -{ - NMSecretAgentOldPrivate *priv; - - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - enable = (!!enable); - - if (priv->auto_register != enable) { - priv->auto_register = enable; - priv->is_enabled = enable; - _notify(self, PROP_AUTO_REGISTER); - } - _register_state_change(self); -} - -static void -_secret_agent_old_destroy(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - priv->is_destroyed = TRUE; - - if (priv->exported_id != 0) { - g_dbus_connection_unregister_object(priv->dbus_connection, - nm_steal_int(&priv->exported_id)); - } - - _register_state_change(self); - - nm_assert(!priv->name_owner_changed_id); - nm_assert(!priv->name_owner_curr); - nm_assert(!priv->name_owner_next); - nm_assert(!priv->name_owner_cancellable); - nm_assert(!priv->registering_retry_source); - nm_assert(!priv->registering_cancellable); - nm_assert(!priv->init_data); - nm_assert(c_list_is_empty(&priv->gsi_lst_head)); - nm_assert(c_list_is_empty(&priv->pending_tasks_register_lst_head)); -} - -/** - * nm_secret_agent_old_destroy: - * @self: the #NMSecretAgentOld instance. - * - * Since 1.24, the instance will already register a D-Bus object on the - * D-Bus connection during initialization. That object will stay registered - * until @self gets unrefed (destroyed) or this function is called. This - * function performs the necessary cleanup to tear down the instance. Afterwards, - * the function can not longer be used. This is optional, but necessary to - * ensure unregistering the D-Bus object at a define point, when other users - * might still have a reference on @self. - * - * You may call this function any time and repeatedly. However, after destroying - * the instance, it is a bug to still use the instance for other purposes. The - * instance becomes defunct and cannot re-register. - * - * Since: 1.24 - */ -void -nm_secret_agent_old_destroy(NMSecretAgentOld *self) -{ - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - - _LOGT("destroying"); - - _secret_agent_old_destroy(self); -} - -/*****************************************************************************/ - -/** - * nm_secret_agent_old_register: - * @self: a #NMSecretAgentOld - * @cancellable: a #GCancellable, or %NULL - * @error: return location for a #GError, or %NULL - * - * Registers the #NMSecretAgentOld with the NetworkManager secret manager, - * indicating to NetworkManager that the agent is able to provide and save - * secrets for connections on behalf of its user. - * - * Returns: %TRUE if registration was successful, %FALSE on error. - * - * Since 1.24, this can no longer fail unless the @cancellable gets - * cancelled. Contrary to nm_secret_agent_old_register_async(), this also - * does not wait for the registration to succeed. You cannot synchronously - * (without iterating the caller's GMainContext) wait for registration. - * - * Since 1.24, registration is idempotent. It has the same effect as setting - * %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %TRUE or nm_secret_agent_old_enable(). - * - * Deprecated: 1.24: Use nm_secret_agent_old_enable() or nm_secret_agent_old_register_async(). - **/ -gboolean -nm_secret_agent_old_register(NMSecretAgentOld *self, GCancellable *cancellable, GError **error) -{ - NMSecretAgentOldPrivate *priv; - - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_val_if_fail(priv->is_initialized && !priv->is_destroyed, FALSE); - - priv->is_enabled = TRUE; - _register_state_change(self); - - if (g_cancellable_set_error_if_cancelled(cancellable, error)) - return FALSE; - - /* This is a synchronous function, meaning: we are not allowed to iterate - * the caller's GMainContext. This is a catch 22, because we don't want - * to perform synchronous calls that bypasses the ordering of our otherwise - * asynchronous mode of operation. Hence, we always signal success. - * That's why this function is deprecated. - * - * So despite claiming success, we might still be in the process of registering - * or NetworkManager might not be available. - * - * This is a change in behavior with respect to libnm before 1.24. - */ - return TRUE; -} - -static void -_register_cancelled_cb(GObject *object, gpointer user_data) -{ - GTask * task0 = user_data; - gs_unref_object GTask * task = NULL; - NMSecretAgentOld * self = g_task_get_source_object(task0); - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - gulong * p_cancelled_id; - NMCListElem * elem; - gs_free_error GError *error = NULL; - - elem = nm_c_list_elem_find_first(&priv->pending_tasks_register_lst_head, x, x == task0); - - g_return_if_fail(elem); - - task = nm_c_list_elem_free_steal(elem); - - p_cancelled_id = g_task_get_task_data(task); - if (p_cancelled_id) { - g_signal_handler_disconnect(g_task_get_cancellable(task), *p_cancelled_id); - g_task_set_task_data(task, NULL, NULL); - } - - nm_utils_error_set_cancelled(&error, FALSE, NULL); - g_task_return_error(task, error); -} - -/** - * nm_secret_agent_old_register_async: - * @self: a #NMSecretAgentOld - * @cancellable: a #GCancellable, or %NULL - * @callback: callback to call when the agent is registered - * @user_data: data for @callback - * - * Asynchronously registers the #NMSecretAgentOld with the NetworkManager secret - * manager, indicating to NetworkManager that the agent is able to provide and - * save secrets for connections on behalf of its user. - * - * Since 1.24, registration cannot fail and is idempotent. It has - * the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %TRUE - * or nm_secret_agent_old_enable(). - * - * Since 1.24, the asynchronous result indicates whether the instance is successfully - * registered. In any case, this call enables the agent and it will automatically - * try to register and handle secret requests. A failure of this function only indicates - * that currently the instance might not be ready (but since it will automatically - * try to recover, it might be ready in a moment afterwards). Use this function if - * you want to check and ensure that the agent is registered. - **/ -void -nm_secret_agent_old_register_async(NMSecretAgentOld * self, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMSecretAgentOldPrivate *priv; - - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_if_fail(priv->is_initialized && !priv->is_destroyed); - - if (callback) { - GTask *task; - - task = nm_g_task_new(self, - cancellable, - nm_secret_agent_old_register_async, - callback, - user_data); - - c_list_link_tail(&priv->pending_tasks_register_lst_head, - &nm_c_list_elem_new_stale(task)->lst); - - if (cancellable) { - gulong cancelled_id; - - cancelled_id = - g_cancellable_connect(cancellable, G_CALLBACK(_register_cancelled_cb), task, NULL); - if (cancelled_id != 0) { - g_task_set_task_data(task, g_memdup(&cancelled_id, sizeof(cancelled_id)), g_free); - } - } - } - - priv->is_enabled = TRUE; - _register_state_change(self); -} - -/** - * nm_secret_agent_old_register_finish: - * @self: a #NMSecretAgentOld - * @result: the result passed to the #GAsyncReadyCallback - * @error: return location for a #GError, or %NULL - * - * Gets the result of a call to nm_secret_agent_old_register_async(). - * - * Returns: %TRUE if registration was successful, %FALSE on error. - * - * Since 1.24, registration cannot fail and is idempotent. It has - * the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %TRUE - * or nm_secret_agent_old_enable(). - **/ -gboolean -nm_secret_agent_old_register_finish(NMSecretAgentOld *self, GAsyncResult *result, GError **error) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_secret_agent_old_register_async), - FALSE); - - return g_task_propagate_boolean(G_TASK(result), error); -} - -/** - * nm_secret_agent_old_unregister: - * @self: a #NMSecretAgentOld - * @cancellable: a #GCancellable, or %NULL - * @error: return location for a #GError, or %NULL - * - * Unregisters the #NMSecretAgentOld with the NetworkManager secret manager, - * indicating to NetworkManager that the agent will no longer provide or - * store secrets on behalf of this user. - * - * Returns: %TRUE if unregistration was successful, %FALSE on error - * - * Since 1.24, registration cannot fail and is idempotent. It has - * the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %FALSE - * or nm_secret_agent_old_enable(). - * - * Deprecated: 1.24: Use nm_secret_agent_old_enable(). - **/ -gboolean -nm_secret_agent_old_unregister(NMSecretAgentOld *self, GCancellable *cancellable, GError **error) -{ - NMSecretAgentOldPrivate *priv; - - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), FALSE); - g_return_val_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_val_if_fail(priv->is_initialized && !priv->is_destroyed, FALSE); - - priv->is_enabled = FALSE; - _register_state_change(self); - - return !g_cancellable_set_error_if_cancelled(cancellable, error); -} - -/** - * nm_secret_agent_old_unregister_async: - * @self: a #NMSecretAgentOld - * @cancellable: a #GCancellable, or %NULL - * @callback: callback to call when the agent is unregistered - * @user_data: data for @callback - * - * Asynchronously unregisters the #NMSecretAgentOld with the NetworkManager secret - * manager, indicating to NetworkManager that the agent will no longer provide - * or store secrets on behalf of this user. - * - * Since 1.24, registration cannot fail and is idempotent. It has - * the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %FALSE - * or nm_secret_agent_old_enable(). - * - * Deprecated: 1.24: Use nm_secret_agent_old_enable(). - **/ -void -nm_secret_agent_old_unregister_async(NMSecretAgentOld * self, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMSecretAgentOldPrivate *priv; - - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_if_fail(priv->is_initialized && !priv->is_destroyed); - - if (callback) { - gs_unref_object GTask *task = NULL; - - task = nm_g_task_new(self, - cancellable, - nm_secret_agent_old_unregister_async, - callback, - user_data); - g_task_return_boolean(task, TRUE); - } - - priv->is_enabled = FALSE; - _register_state_change(self); -} - -/** - * nm_secret_agent_old_unregister_finish: - * @self: a #NMSecretAgentOld - * @result: the result passed to the #GAsyncReadyCallback - * @error: return location for a #GError, or %NULL - * - * Gets the result of a call to nm_secret_agent_old_unregister_async(). - * - * Returns: %TRUE if unregistration was successful, %FALSE on error. - * - * Since 1.24, registration cannot fail and is idempotent. It has - * the same effect as setting %NM_SECRET_AGENT_OLD_AUTO_REGISTER to %FALSE - * or nm_secret_agent_old_enable(). - * - * Deprecated: 1.24: Use nm_secret_agent_old_enable(). - **/ -gboolean -nm_secret_agent_old_unregister_finish(NMSecretAgentOld *self, GAsyncResult *result, GError **error) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_secret_agent_old_unregister_async), - FALSE); - - return g_task_propagate_boolean(G_TASK(result), error); -} - -/*****************************************************************************/ - -/** - * nm_secret_agent_old_get_secrets: (virtual get_secrets): - * @self: a #NMSecretAgentOld - * @connection: the #NMConnection for which we're asked secrets - * @setting_name: the name of the secret setting - * @hints: (array zero-terminated=1): hints to the agent - * @flags: flags that modify the behavior of the request - * @callback: (scope async): a callback, to be invoked when the operation is done - * @user_data: (closure): caller-specific data to be passed to @callback - * - * Asynchronously retrieves secrets belonging to @connection for the - * setting @setting_name. @flags indicate specific behavior that the secret - * agent should use when performing the request, for example returning only - * existing secrets without user interaction, or requesting entirely new - * secrets from the user. - */ -void -nm_secret_agent_old_get_secrets(NMSecretAgentOld * self, - NMConnection * connection, - const char * setting_name, - const char ** hints, - NMSecretAgentGetSecretsFlags flags, - NMSecretAgentOldGetSecretsFunc callback, - gpointer user_data) -{ - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - g_return_if_fail(NM_IS_CONNECTION(connection)); - g_return_if_fail(nm_connection_get_path(connection)); - g_return_if_fail(setting_name && setting_name[0]); - g_return_if_fail(!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)); - g_return_if_fail(!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS)); - g_return_if_fail(callback != NULL); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->get_secrets(self, - connection, - nm_connection_get_path(connection), - setting_name, - hints, - flags, - callback, - user_data); -} - -/** - * nm_secret_agent_old_save_secrets: (virtual save_secrets): - * @self: a #NMSecretAgentOld - * @connection: a #NMConnection - * @callback: (scope async): a callback, to be invoked when the operation is done - * @user_data: (closure): caller-specific data to be passed to @callback - * - * Asynchronously ensures that all secrets inside @connection are stored to - * disk. - */ -void -nm_secret_agent_old_save_secrets(NMSecretAgentOld * self, - NMConnection * connection, - NMSecretAgentOldSaveSecretsFunc callback, - gpointer user_data) -{ - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - g_return_if_fail(NM_IS_CONNECTION(connection)); - g_return_if_fail(nm_connection_get_path(connection)); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->save_secrets(self, - connection, - nm_connection_get_path(connection), - callback, - user_data); -} - -/** - * nm_secret_agent_old_delete_secrets: (virtual delete_secrets): - * @self: a #NMSecretAgentOld - * @connection: a #NMConnection - * @callback: (scope async): a callback, to be invoked when the operation is done - * @user_data: (closure): caller-specific data to be passed to @callback - * - * Asynchronously asks the agent to delete all saved secrets belonging to - * @connection. - */ -void -nm_secret_agent_old_delete_secrets(NMSecretAgentOld * self, - NMConnection * connection, - NMSecretAgentOldDeleteSecretsFunc callback, - gpointer user_data) -{ - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(self)); - g_return_if_fail(NM_IS_CONNECTION(connection)); - g_return_if_fail(nm_connection_get_path(connection)); - - NM_SECRET_AGENT_OLD_GET_CLASS(self)->delete_secrets(self, - connection, - nm_connection_get_path(connection), - callback, - user_data); -} - -/*****************************************************************************/ - -static gboolean -validate_identifier(const char *identifier) -{ - const char *p = identifier; - size_t id_len; - - /* Length between 3 and 255 characters inclusive */ - id_len = strlen(identifier); - if (id_len < 3 || id_len > 255) - return FALSE; - - if ((identifier[0] == '.') || (identifier[id_len - 1] == '.')) - return FALSE; - - /* FIXME: do complete validation here */ - while (p && *p) { - if (!g_ascii_isalnum(*p) && (*p != '_') && (*p != '-') && (*p != '.')) - return FALSE; - if ((*p == '.') && (*(p + 1) == '.')) - return FALSE; - p++; - } - - return TRUE; -} - -/*****************************************************************************/ - -static gboolean -_register_retry_cb(gpointer user_data) -{ - NMSecretAgentOld * self = user_data; - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - nm_auto_pop_gmaincontext GMainContext *dbus_context = NULL; - - dbus_context = nm_g_main_context_push_thread_default_if_necessary(priv->dbus_context); - - nm_clear_g_source_inst(&priv->registering_retry_source); - _register_dbus_call(self); - return G_SOURCE_CONTINUE; -} - -static void -_register_call_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMSecretAgentOld * self = user_data; - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); - - if (nm_utils_error_is_cancelled(error)) - return; - - nm_assert(!priv->registering_retry_source); - nm_assert(!priv->is_registered); - nm_assert(priv->registering_cancellable); - - if (nm_dbus_error_is(error, NM_DBUS_ERROR_NAME_UNKNOWN_METHOD) - && nm_utils_get_monotonic_timestamp_msec() < priv->registering_timeout_msec) { - guint timeout_msec; - - timeout_msec = (2u << NM_MIN(6u, ++priv->registering_try_count)); - - _LOGT("register: registration failed with error \"%s\". Retry in %u msec...", - error->message, - timeout_msec); - - priv->registering_retry_source = - nm_g_source_attach(nm_g_timeout_source_new(timeout_msec, - G_PRIORITY_DEFAULT, - _register_retry_cb, - self, - NULL), - priv->dbus_context); - return; - } - - g_clear_object(&priv->registering_cancellable); - - if (error) { - /* registration apparently failed. However we still keep priv->registered_against_server TRUE, because - * - * - eventually we want to still make an Unregister() call. Even if it probably has no effect, - * better be sure. - * - * - we actually accept secret request (from the right name owner). We register so that - * NetworkManager knows that we are here. We don't require the registration to succeed - * for our purpose. If NetworkManager makes requests for us, despite the registration - * failing, that is fine. */ - _LOGT("register: registration failed with error \"%s\"", error->message); - goto out; - } - - _LOGT("register: registration succeeded"); - priv->is_registered = TRUE; - _notify(self, PROP_REGISTERED); - -out: - _register_state_complete(self); -} - -static void -_register_dbus_call(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - _dbus_connection_call(self, - nm_ref_string_get_str(priv->name_owner_curr), - NM_DBUS_PATH_AGENT_MANAGER, - NM_DBUS_INTERFACE_AGENT_MANAGER, - "RegisterWithCapabilities", - g_variant_new("(su)", priv->identifier, (guint32) priv->capabilities), - G_VARIANT_TYPE("()"), - G_DBUS_CALL_FLAGS_NONE, - _CALL_REGISTER_TIMEOUT_MSEC, - priv->registering_cancellable, - _register_call_cb, - self); -} - -static void -_get_connection_unix_user_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMSecretAgentOld * self; - NMSecretAgentOldPrivate *priv; - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - guint32 sender_uid = 0; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - nm_assert(priv->registering_cancellable); - nm_assert(!priv->registered_against_server); - - if (ret) - g_variant_get(ret, "(u)", &sender_uid); - - if (ret && sender_uid == 0) - _LOGT("register: peer %s is owned by root. Validated to accept requests.", - priv->name_owner_curr->str); - else if (ret && priv->session_bus) { - _LOGT( - "register: peer %s is owned by user %d for session bus. Validated to accept requests.", - priv->name_owner_curr->str, - sender_uid); - } else { - /* the peer is not validated. We don't actually register. */ - if (ret) - _LOGT("register: peer %s is owned by user %u. Not validated as NetworkManager service.", - priv->name_owner_curr->str, - sender_uid); - else - _LOGT("register: failed to get user id for peer %s: %s. Not validated as " - "NetworkManager service.", - priv->name_owner_curr->str, - error->message); - - /* we actually don't do anything and keep the agent unregistered. - * - * We keep priv->registering_cancellable set to not retry this again, until we loose the - * name owner. But the state of the agent is lingering and won't accept any requests. */ - return; - } - - priv->registering_timeout_msec = - nm_utils_get_monotonic_timestamp_msec() + REGISTER_RETRY_TIMEOUT_MSEC; - priv->registering_try_count = 0; - priv->registered_against_server = TRUE; - _register_dbus_call(self); -} - -/*****************************************************************************/ - -static void -_name_owner_changed(NMSecretAgentOld *self, const char *name_owner, gboolean is_event) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - if (is_event) { - if (priv->name_owner_cancellable) { - /* we are still fetching the name-owner. Ignore this event. */ - return; - } - } else - g_clear_object(&priv->name_owner_cancellable); - - nm_ref_string_unref(priv->name_owner_next); - priv->name_owner_next = nm_ref_string_new(nm_str_not_empty(name_owner)); - - _LOGT("name-owner changed: %s%s%s -> %s%s%s", - NM_PRINT_FMT_QUOTED(priv->name_owner_curr, - "\"", - priv->name_owner_curr->str, - "\"", - "(null)"), - NM_PRINT_FMT_QUOTED(priv->name_owner_next, - "\"", - priv->name_owner_next->str, - "\"", - "(null)")); - - _register_state_change(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) -{ - NMSecretAgentOld *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, TRUE); -} - -static void -_name_owner_get_cb(const char *name_owner, GError *error, gpointer user_data) -{ - if (name_owner || !nm_utils_error_is_cancelled(error)) - _name_owner_changed(user_data, name_owner, FALSE); -} - -/*****************************************************************************/ - -static void -_method_call(GDBusConnection * connection, - const char * sender, - const char * object_path, - const char * interface_name, - const char * method_name, - GVariant * parameters, - GDBusMethodInvocation *context, - gpointer user_data) -{ - NMSecretAgentOld * self = user_data; - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - nm_assert(nm_streq0(object_path, NM_DBUS_PATH_SECRET_AGENT)); - nm_assert(nm_streq0(interface_name, NM_DBUS_INTERFACE_SECRET_AGENT)); - nm_assert(sender); - nm_assert(nm_streq0(sender, g_dbus_method_invocation_get_sender(context))); - - if (!priv->name_owner_curr || !priv->registered_against_server) { - /* priv->registered_against_server means that we started to register, but not necessarily - * that the registration fully succeeded. However, we already authenticated the request - * and so we accept it, even if the registration is not yet complete. */ - g_dbus_method_invocation_return_error_literal(context, - NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_PERMISSION_DENIED, - "Request by non authenticated peer rejected"); - return; - } - - if (nm_streq(method_name, "GetSecrets")) - impl_get_secrets(self, parameters, context); - else if (nm_streq(method_name, "CancelGetSecrets")) - impl_cancel_get_secrets(self, parameters, context); - else if (nm_streq(method_name, "SaveSecrets")) - impl_save_secrets(self, parameters, context); - else if (nm_streq(method_name, "DeleteSecrets")) - impl_delete_secrets(self, parameters, context); - else - nm_assert_not_reached(); -} - -/*****************************************************************************/ - -static void -_register_state_complete(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - NMCListElem * elem; - gboolean any_tasks_to_complete = FALSE; - - if (!c_list_is_empty(&priv->pending_tasks_register_lst_head)) { - /* add a dummy sentinel. We want to complete all the task we started - * so far, but as we invoke user callbacks, the user might register - * new tasks. Those we don't complete in this run. */ - g_object_ref(self); - any_tasks_to_complete = TRUE; - c_list_link_tail(&priv->pending_tasks_register_lst_head, - &nm_c_list_elem_new_stale(&any_tasks_to_complete)->lst); - } - - _init_complete(self, NULL); - - if (any_tasks_to_complete) { - while ( - (elem = c_list_first_entry(&priv->pending_tasks_register_lst_head, NMCListElem, lst))) { - gpointer data = nm_c_list_elem_free_steal(elem); - gs_unref_object GTask *task = NULL; - - if (data == &any_tasks_to_complete) { - any_tasks_to_complete = FALSE; - break; - } - - task = data; - - if (!priv->is_registered) { - g_task_return_error(task, - g_error_new_literal(NM_SECRET_AGENT_ERROR, - NM_SECRET_AGENT_ERROR_FAILED, - _("registration failed"))); - continue; - } - g_task_return_boolean(task, TRUE); - } - nm_assert(!any_tasks_to_complete); - g_object_unref(self); - } -} - -static void -_register_state_change_do(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - if (priv->is_destroyed) - priv->is_enabled = FALSE; - - if (!priv->is_enabled || priv->registration_force_unregister - || priv->name_owner_curr != priv->name_owner_next) { - GetSecretsInfo *info; - - while ((info = c_list_first_entry(&priv->gsi_lst_head, GetSecretsInfo, gsi_lst))) { - _cancel_get_secret_request(self, info, "The secret agent is going away"); - _register_state_change(self); - return; - } - - priv->registration_force_unregister = FALSE; - - nm_clear_g_cancellable(&priv->registering_cancellable); - nm_clear_g_source_inst(&priv->registering_retry_source); - - if (priv->registered_against_server) { - priv->registered_against_server = FALSE; - if (priv->name_owner_curr) { - _LOGT("register: unregister from %s", priv->name_owner_curr->str); - _dbus_connection_call(self, - priv->name_owner_curr->str, - NM_DBUS_PATH_AGENT_MANAGER, - NM_DBUS_INTERFACE_AGENT_MANAGER, - "Unregister", - g_variant_new("()"), - G_VARIANT_TYPE("()"), - G_DBUS_CALL_FLAGS_NONE, - _CALL_REGISTER_TIMEOUT_MSEC, - NULL, - NULL, - NULL); - } - } - - if (!priv->is_enabled) { - nm_clear_g_cancellable(&priv->name_owner_cancellable); - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); - nm_clear_pointer(&priv->name_owner_curr, nm_ref_string_unref); - nm_clear_pointer(&priv->name_owner_next, nm_ref_string_unref); - } - - if (priv->is_registered) { - priv->is_registered = FALSE; - if (!priv->is_destroyed) { - _LOGT("register: now unregistered"); - _notify(self, PROP_REGISTERED); - _register_state_change(self); - return; - } - } - - if (!priv->is_enabled) { - _register_state_complete(self); - return; - } - - if (priv->name_owner_curr != priv->name_owner_next) { - nm_ref_string_unref(priv->name_owner_curr); - priv->name_owner_curr = nm_ref_string_ref(priv->name_owner_next); - } - } - - if (priv->name_owner_changed_id == 0) { - nm_assert(!priv->name_owner_cancellable); - nm_assert(!priv->name_owner_curr); - nm_assert(!priv->name_owner_next); - priv->name_owner_cancellable = g_cancellable_new(); - priv->name_owner_changed_id = - nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, - NM_DBUS_SERVICE, - _name_owner_changed_cb, - self, - NULL); - nm_dbus_connection_call_get_name_owner(priv->dbus_connection, - NM_DBUS_SERVICE, - -1, - priv->name_owner_cancellable, - _name_owner_get_cb, - self); - return; - } - - if (priv->name_owner_cancellable) { - /* we still wait for the name owner. Nothing to do for now. */ - return; - } - - if (!priv->name_owner_curr) { - /* we don't have a name owner. We are done and wait. */ - _register_state_complete(self); - return; - } - - if (priv->registering_cancellable) { - /* we are already registering... wait longer. */ - return; - } - - nm_assert(!priv->registering_retry_source); - - if (!priv->is_registered) { - /* start registering... */ - priv->registering_cancellable = g_cancellable_new(); - _dbus_connection_call(self, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixUser", - g_variant_new("(s)", priv->name_owner_curr->str), - G_VARIANT_TYPE("(u)"), - G_DBUS_CALL_FLAGS_NONE, - _CALL_REGISTER_TIMEOUT_MSEC, - priv->registering_cancellable, - _get_connection_unix_user_cb, - self); - return; - } - - /* we are fully registered and done. */ - _register_state_complete(self); -} - -static void -_register_state_change(NMSecretAgentOld *self) -{ - _nm_unused gs_unref_object NMSecretAgentOld *self_keep_alive = g_object_ref(self); - NMSecretAgentOldPrivate * priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - nm_auto_pop_gmaincontext GMainContext *dbus_context = NULL; - - if (priv->register_state_change_reenter == 0) { - /* We are not yet initialized. Do nothing. */ - return; - } - - if (priv->register_state_change_reenter != 1) { - /* Recursive calls are prevented. Do nothing for now, but repeat - * the state change afterwards. */ - priv->register_state_change_reenter = 3; - return; - } - - dbus_context = nm_g_main_context_push_thread_default_if_necessary(priv->dbus_context); - -again: - priv->register_state_change_reenter = 2; - - _register_state_change_do(self); - - if (priv->register_state_change_reenter != 2) - goto again; - - priv->register_state_change_reenter = 1; -} - -/*****************************************************************************/ - -static void -_init_complete(NMSecretAgentOld *self, GError *error_take) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - gs_free_error GError *error = g_steal_pointer(&error_take); - GError * error_cancelled = NULL; - - if (!priv->init_data) - return; - - if (g_cancellable_set_error_if_cancelled(priv->init_data->cancellable, &error_cancelled)) { - g_clear_error(&error); - g_propagate_error(&error, error_cancelled); - } - - priv->is_initialized = (!error); - - _LOGT("%s init complete with %s%s%s", - priv->init_data->is_sync ? "sync" : "async", - NM_PRINT_FMT_QUOTED(error_take, "error: ", error_take->message, "", "success")); - - nml_init_data_return(g_steal_pointer(&priv->init_data), g_steal_pointer(&error)); -} - -static void -_init_register_object(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - GDBusInterfaceVTable interface_vtable = { - .method_call = _method_call, - }; - - if (g_cancellable_set_error_if_cancelled(priv->init_data->cancellable, &error)) { - _init_complete(self, g_steal_pointer(&error)); - return; - } - - priv->exported_id = g_dbus_connection_register_object(priv->dbus_connection, - NM_DBUS_PATH_SECRET_AGENT, - (GDBusInterfaceInfo *) &interface_info, - &interface_vtable, - self, - NULL, - &error); - if (priv->exported_id == 0) { - _init_complete(self, g_steal_pointer(&error)); - return; - } - - priv->register_state_change_reenter = 1; - - _register_state_change(self); -} - -static void -_init_got_bus(GObject *initable, GAsyncResult *result, gpointer user_data) -{ - NMSecretAgentOld * self = user_data; - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - - priv->dbus_connection = g_bus_get_finish(result, &error); - if (!priv->dbus_connection) { - _init_complete(self, g_steal_pointer(&error)); - return; - } - - _LOGT("init: got GDBusConnection"); - - _notify(self, PROP_DBUS_CONNECTION); - - _init_register_object(self); -} - -static void -_init_start(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - if (!priv->dbus_connection) { - GBusType bus_type; - - bus_type = _nm_dbus_bus_type(); - - priv->session_bus = (bus_type == G_BUS_TYPE_SESSION); - - g_bus_get(bus_type, priv->init_data->cancellable, _init_got_bus, self); - return; - } - - _init_register_object(self); -} - -static void -init_async(GAsyncInitable * initable, - int io_priority, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMSecretAgentOld * self; - NMSecretAgentOldClass * klass; - NMSecretAgentOldPrivate *priv; - nm_auto_pop_gmaincontext GMainContext *dbus_context = NULL; - gs_unref_object GTask *task = NULL; - - g_return_if_fail(NM_IS_SECRET_AGENT_OLD(initable)); - - self = NM_SECRET_AGENT_OLD(initable); - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_if_fail(!priv->dbus_context); - g_return_if_fail(!priv->is_destroyed); - - klass = NM_SECRET_AGENT_OLD_GET_CLASS(self); - g_return_if_fail(klass->get_secrets); - g_return_if_fail(klass->cancel_get_secrets); - g_return_if_fail(klass->save_secrets); - g_return_if_fail(klass->delete_secrets); - - _LOGT("init-async starting..."); - - priv->dbus_context = g_main_context_ref(priv->main_context); - - dbus_context = nm_g_main_context_push_thread_default_if_necessary(priv->dbus_context); - - task = nm_g_task_new(self, cancellable, init_async, callback, user_data); - g_task_set_priority(task, io_priority); - - priv->init_data = nml_init_data_new_async(cancellable, g_steal_pointer(&task)); - - _init_start(self); -} - -static gboolean -init_finish(GAsyncInitable *initable, GAsyncResult *result, GError **error) -{ - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(initable), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, initable, init_async), FALSE); - - return g_task_propagate_boolean(G_TASK(result), error); -} - -/*****************************************************************************/ - -static gboolean -init_sync(GInitable *initable, GCancellable *cancellable, GError **error) -{ - gs_unref_object NMSecretAgentOld *self = NULL; - NMSecretAgentOldPrivate * priv; - NMSecretAgentOldClass * klass; - GMainLoop * main_loop; - GError * local_error = NULL; - - g_return_val_if_fail(NM_IS_SECRET_AGENT_OLD(initable), FALSE); - - self = g_object_ref(NM_SECRET_AGENT_OLD(initable)); - priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - g_return_val_if_fail(!priv->dbus_context, FALSE); - g_return_val_if_fail(!priv->is_destroyed, FALSE); - - klass = NM_SECRET_AGENT_OLD_GET_CLASS(self); - g_return_val_if_fail(klass->get_secrets, FALSE); - g_return_val_if_fail(klass->cancel_get_secrets, FALSE); - g_return_val_if_fail(klass->save_secrets, FALSE); - g_return_val_if_fail(klass->delete_secrets, FALSE); - - _LOGT("init-sync"); - - /* See NMClient's sync-init method for explanation about why we create - * an internal GMainContext priv->dbus_context. */ - - priv->dbus_context = g_main_context_new(); - - g_main_context_push_thread_default(priv->dbus_context); - - main_loop = g_main_loop_new(priv->dbus_context, FALSE); - - priv->init_data = nml_init_data_new_sync(cancellable, main_loop, &local_error); - - _init_start(self); - - g_main_loop_run(main_loop); - - g_main_loop_unref(main_loop); - - g_main_context_pop_thread_default(priv->dbus_context); - - nm_context_busy_watcher_integrate_source(priv->main_context, - priv->dbus_context, - priv->context_busy_watcher); - - if (local_error) { - g_propagate_error(error, local_error); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_DBUS_CONNECTION: - g_value_set_object(value, priv->dbus_connection); - break; - case PROP_IDENTIFIER: - g_value_set_string(value, priv->identifier); - break; - case PROP_AUTO_REGISTER: - g_value_set_boolean(value, priv->auto_register); - break; - case PROP_REGISTERED: - g_value_set_boolean(value, priv->is_registered); - break; - case PROP_CAPABILITIES: - g_value_set_flags(value, priv->capabilities); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMSecretAgentOld * self = NM_SECRET_AGENT_OLD(object); - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - guint u; - - switch (prop_id) { - case PROP_DBUS_CONNECTION: - /* construct-only */ - priv->dbus_connection = g_value_dup_object(value); - break; - case PROP_IDENTIFIER: - /* construct-only */ - priv->identifier = g_value_dup_string(value); - g_return_if_fail(validate_identifier(priv->identifier)); - break; - case PROP_AUTO_REGISTER: - /* construct */ - priv->auto_register = g_value_get_boolean(value); - priv->is_enabled = priv->auto_register; - _register_state_change(self); - break; - case PROP_CAPABILITIES: - /* construct */ - u = g_value_get_flags(value); - if (u != priv->capabilities) { - priv->capabilities = u; - priv->registration_force_unregister = TRUE; - _register_state_change(self); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_secret_agent_old_init(NMSecretAgentOld *self) -{ - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - _LOGT("create new instance"); - - c_list_init(&priv->gsi_lst_head); - c_list_init(&priv->pending_tasks_register_lst_head); - - priv->main_context = g_main_context_ref_thread_default(); - priv->context_busy_watcher = g_object_new(G_TYPE_OBJECT, NULL); -} - -static void -dispose(GObject *object) -{ - NMSecretAgentOld *self = NM_SECRET_AGENT_OLD(object); - - _LOGT("disposing"); - - _secret_agent_old_destroy(self); - - G_OBJECT_CLASS(nm_secret_agent_old_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMSecretAgentOld * self = NM_SECRET_AGENT_OLD(object); - NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE(self); - - _LOGT("finalizing"); - - if (priv->dbus_context) { - nml_cleanup_context_busy_watcher_on_idle(g_steal_pointer(&priv->context_busy_watcher), - priv->dbus_context); - } - - g_clear_object(&priv->dbus_connection); - nm_clear_pointer(&priv->dbus_context, g_main_context_unref); - nm_clear_pointer(&priv->main_context, g_main_context_unref); - - g_clear_object(&priv->context_busy_watcher); - - g_free(priv->identifier); - - G_OBJECT_CLASS(nm_secret_agent_old_parent_class)->finalize(object); -} - -static void -nm_secret_agent_old_class_init(NMSecretAgentOldClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(class); - - g_type_class_add_private(class, sizeof(NMSecretAgentOldPrivate)); - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - /** - * NMSecretAgentOld:dbus-connection: - * - * The #GDBusConnection used by the instance. You may either set this - * as construct-only property, or otherwise #NMSecretAgentOld will choose - * a connection via g_bus_get() during initialization. - * - * Since: 1.24 - **/ - obj_properties[PROP_DBUS_CONNECTION] = - g_param_spec_object(NM_SECRET_AGENT_OLD_DBUS_CONNECTION, - "", - "", - G_TYPE_DBUS_CONNECTION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - /** - * NMSecretAgentOld:identifier: - * - * Identifies this agent; only one agent in each user session may use the - * same identifier. Identifier formatting follows the same rules as - * D-Bus bus names with the exception that the ':' character is not - * allowed. The valid set of characters is "[A-Z][a-z][0-9]_-." and the - * identifier is limited in length to 255 characters with a minimum - * of 3 characters. An example valid identifier is 'org.gnome.nm-applet' - * (without quotes). - **/ - obj_properties[PROP_IDENTIFIER] = - g_param_spec_string(NM_SECRET_AGENT_OLD_IDENTIFIER, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - /** - * NMSecretAgentOld:auto-register: - * - * If %TRUE (the default), the agent will always be registered when - * NetworkManager is running; if NetworkManager exits and restarts, the - * agent will re-register itself automatically. - * - * In particular, if this property is %TRUE at construct time, then the - * agent will register itself with NetworkManager during - * construction/initialization and initialization will only complete - * after registration is completed (either successfully or unsuccessfully). - * Since 1.24, a failure to register will no longer cause initialization - * of #NMSecretAgentOld to fail. - * - * If the property is %FALSE, the agent will not automatically register with - * NetworkManager, and nm_secret_agent_old_enable() or - * nm_secret_agent_old_register_async() must be called to register it. - * - * Calling nm_secret_agent_old_enable() has the same effect as setting this - * property. - **/ - obj_properties[PROP_AUTO_REGISTER] = - g_param_spec_boolean(NM_SECRET_AGENT_OLD_AUTO_REGISTER, - "", - "", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - /** - * NMSecretAgentOld:registered: - * - * %TRUE if the agent is registered with NetworkManager, %FALSE if not. - **/ - obj_properties[PROP_REGISTERED] = - g_param_spec_boolean(NM_SECRET_AGENT_OLD_REGISTERED, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - /** - * NMSecretAgentOld:capabilities: - * - * A bitfield of %NMSecretAgentCapabilities. - * - * Changing this property is possible at any time. In case the secret - * agent is currently registered, this will cause a re-registration. - **/ - obj_properties[PROP_CAPABILITIES] = - g_param_spec_flags(NM_SECRET_AGENT_OLD_CAPABILITIES, - "", - "", - NM_TYPE_SECRET_AGENT_CAPABILITIES, - NM_SECRET_AGENT_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -static void -nm_secret_agent_old_initable_iface_init(GInitableIface *iface) -{ - iface->init = init_sync; -} - -static void -nm_secret_agent_old_async_initable_iface_init(GAsyncInitableIface *iface) -{ - iface->init_async = init_async; - iface->init_finish = init_finish; -} |