mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 13:20:08 +01:00
Our coding style recommends C style comments (/* */) instead of C++ (//). Also, systemd (which we partly fork) uses C style comments for the SPDX-License-Identifier. Unify the style. $ sed -i '1 s#// SPDX-License-Identifier: \([^ ]\+\)$#/* SPDX-License-Identifier: \1 */#' -- $(git ls-files -- '*.[hc]' '*.[hc]pp')
1995 lines
71 KiB
C
1995 lines
71 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
/*
|
|
* Copyright (C) 2010 - 2011 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "nm-default.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;
|
|
}
|