NetworkManager/src/settings/nm-secret-agent.c

827 lines
26 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2010 - 2011 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-secret-agent.h"
#include <sys/types.h>
#include <pwd.h>
#include "nm-glib-aux/nm-c-list.h"
#include "nm-glib-aux/nm-dbus-aux.h"
#include "nm-dbus-interface.h"
#include "nm-core-internal.h"
#include "nm-auth-subject.h"
#include "nm-simple-connection.h"
#include "NetworkManagerUtils.h"
#include "c-list/src/c-list.h"
/*****************************************************************************/
#define METHOD_GET_SECRETS "GetSecrets"
#define METHOD_CANCEL_GET_SECRETS "CancelGetSecrets"
#define METHOD_SAVE_SECRETS "SaveSecrets"
#define METHOD_DELETE_SECRETS "DeleteSecrets"
enum {
DISCONNECTED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
CList permissions;
char *description;
NMAuthSubject *subject;
char *identifier;
char *owner_username;
char *dbus_owner;
GDBusConnection *dbus_connection;
GCancellable *name_owner_cancellable;
CList requests;
NMSecretAgentCapabilities capabilities;
guint name_owner_changed_id;
bool shutdown_wait_obj_registered:1;
} NMSecretAgentPrivate;
struct _NMSecretAgent {
GObject parent;
NMSecretAgentPrivate _priv;
};
struct _NMSecretAgentClass {
GObjectClass parent;
};
G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
#define NM_SECRET_AGENT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSecretAgent, NM_IS_SECRET_AGENT)
/*****************************************************************************/
#define _NMLOG_PREFIX_NAME "secret-agent"
#define _NMLOG_DOMAIN LOGD_AGENTS
#define _NMLOG(level, ...) \
G_STMT_START { \
if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
char _prefix[64]; \
\
if ((self)) { \
g_snprintf (_prefix, \
sizeof (_prefix), \
_NMLOG_PREFIX_NAME"["NM_HASH_OBFUSCATE_PTR_FMT"]", \
NM_HASH_OBFUSCATE_PTR (self)); \
} else \
g_strlcpy (_prefix, _NMLOG_PREFIX_NAME, sizeof (_prefix)); \
\
_nm_log ((level), \
(_NMLOG_DOMAIN), \
0, \
NULL, \
NULL, \
"%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_prefix \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
} G_STMT_END
#define _NMLOG2(level, call_id, ...) \
G_STMT_START { \
NMSecretAgentCallId *const _call_id = (call_id); \
\
nm_assert (_call_id); \
\
nm_log ((level), \
(_NMLOG_DOMAIN), \
NULL, \
NULL, \
"%s["NM_HASH_OBFUSCATE_PTR_FMT"] request ["NM_HASH_OBFUSCATE_PTR_FMT",%s,%s%s%s%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME, \
NM_HASH_OBFUSCATE_PTR (_call_id->self), \
NM_HASH_OBFUSCATE_PTR (_call_id), \
_call_id->method_name, \
NM_PRINT_FMT_QUOTE_STRING (_call_id->path), \
(_call_id->cancellable ? "" : " (cancelled)") \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} G_STMT_END
/*****************************************************************************/
NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabilities,
NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE, "none"),
NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "vpn-hints"),
);
/*****************************************************************************/
struct _NMSecretAgentCallId {
CList lst;
NMSecretAgent *self;
GCancellable *cancellable;
char *path;
const char *method_name;
char *setting_name;
NMSecretAgentCallback callback;
gpointer callback_data;
};
static NMSecretAgentCallId *
_call_id_new (NMSecretAgent *self,
const char *method_name, /* this must be a static string. */
const char *path,
const char *setting_name,
NMSecretAgentCallback callback,
gpointer callback_data)
{
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
NMSecretAgentCallId *call_id;
call_id = g_slice_new (NMSecretAgentCallId);
*call_id = (NMSecretAgentCallId) {
.self = g_object_ref (self),
.path = g_strdup (path),
.setting_name = g_strdup (setting_name),
.method_name = method_name,
.callback = callback,
.callback_data = callback_data,
.cancellable = g_cancellable_new (),
};
c_list_link_tail (&priv->requests, &call_id->lst);
_LOG2T (call_id, "new request...");
if (!priv->shutdown_wait_obj_registered) {
/* self has async requests (that keep self alive). As long as
* we have pending requests, shutdown is blocked. */
priv->shutdown_wait_obj_registered = TRUE;
nm_shutdown_wait_obj_register_object (G_OBJECT (self), "secret-agent");
}
return call_id;
}
#define _call_id_new(self, method_name, path, setting_name, callback, callback_data) _call_id_new(self, ""method_name"", path, setting_name, callback, callback_data)
static void
_call_id_free (NMSecretAgentCallId *call_id)
{
c_list_unlink_stale (&call_id->lst);
g_free (call_id->path);
g_free (call_id->setting_name);
nm_g_object_unref (call_id->cancellable);
g_object_unref (call_id->self);
nm_g_slice_free (call_id);
}
static void
_call_id_invoke_callback (NMSecretAgentCallId *call_id,
GVariant *secrets,
GError *error,
gboolean cancelled,
gboolean free_call_id)
{
gs_free_error GError *error_cancelled = NULL;
nm_assert (call_id);
nm_assert (!c_list_is_empty (&call_id->lst));
c_list_unlink (&call_id->lst);
if (cancelled) {
nm_assert (!secrets);
nm_assert (!error);
if (call_id->callback) {
nm_utils_error_set_cancelled (&error_cancelled, FALSE, "NMSecretAgent");
error = error_cancelled;
}
_LOG2T (call_id, "cancelled");
} else if (error) {
nm_assert (!secrets);
_LOG2T (call_id, "completed with failure: %s", error->message);
} else {
nm_assert ( !secrets
|| g_variant_is_of_type (secrets, G_VARIANT_TYPE ("a{sa{sv}}")));
nm_assert ((!!secrets) == nm_streq0 (call_id->method_name, METHOD_GET_SECRETS));
_LOG2T (call_id, "completed successfully");
}
if (call_id->callback)
call_id->callback (call_id->self, call_id, secrets, error, call_id->callback_data);
if (free_call_id)
_call_id_free (call_id);
}
/*****************************************************************************/
static char *
_create_description (const char *dbus_owner, const char *identifier, gulong uid)
{
return g_strdup_printf ("%s/%s/%lu",
dbus_owner,
identifier,
uid);
}
const char *
nm_secret_agent_get_description (NMSecretAgent *agent)
{
NMSecretAgentPrivate *priv;
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
if (!priv->description) {
priv->description = _create_description (priv->dbus_owner,
priv->identifier,
nm_auth_subject_get_unix_process_uid (priv->subject));
}
return priv->description;
}
/*****************************************************************************/
const char *
nm_secret_agent_get_dbus_owner (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->dbus_owner;
}
const char *
nm_secret_agent_get_identifier (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier;
}
gulong
nm_secret_agent_get_owner_uid (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
return nm_auth_subject_get_unix_process_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
const char *
nm_secret_agent_get_owner_username (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_username;
}
gulong
nm_secret_agent_get_pid (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
return nm_auth_subject_get_unix_process_pid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
NMSecretAgentCapabilities
nm_secret_agent_get_capabilities (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NM_SECRET_AGENT_CAPABILITY_NONE);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->capabilities;
}
NMAuthSubject *
nm_secret_agent_get_subject (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->subject;
}
/*****************************************************************************/
/**
* nm_secret_agent_add_permission:
* @agent: A #NMSecretAgent.
* @permission: The name of the permission
*
* Records whether or not the agent has a given permission.
*/
void
nm_secret_agent_add_permission (NMSecretAgent *agent,
const char *permission,
gboolean allowed)
{
NMSecretAgentPrivate *priv;
NMCListElem *elem;
g_return_if_fail (agent != NULL);
g_return_if_fail (permission != NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
elem = nm_c_list_elem_find_first (&priv->permissions, p, nm_streq (p, permission));
if (elem) {
if (!allowed)
nm_c_list_elem_free_full (elem, g_free);
return;
}
if (allowed) {
c_list_link_tail (&priv->permissions,
&nm_c_list_elem_new_stale (g_strdup (permission))->lst);
}
}
/**
* nm_secret_agent_has_permission:
* @agent: A #NMSecretAgent.
* @permission: The name of the permission to check for
*
* Returns whether or not the agent has the given permission.
*
* Returns: %TRUE if the agent has the given permission, %FALSE if it does not
* or if the permission was not previous recorded with
* nm_secret_agent_add_permission().
*/
gboolean
nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission)
{
g_return_val_if_fail (agent != NULL, FALSE);
g_return_val_if_fail (permission != NULL, FALSE);
return !!nm_c_list_elem_find_first (&NM_SECRET_AGENT_GET_PRIVATE (agent)->permissions,
p, nm_streq (p, permission));
}
/*****************************************************************************/
static void
_dbus_call_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
NMSecretAgentCallId *call_id;
gs_unref_variant GVariant *ret = NULL;
gs_unref_variant GVariant *secrets = NULL;
gs_free_error GError *error = NULL;
ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if ( !ret
&& nm_utils_error_is_cancelled (error, FALSE))
return;
call_id = user_data;
if (!ret)
g_dbus_error_strip_remote_error (error);
else {
if (nm_streq (call_id->method_name, METHOD_GET_SECRETS)) {
g_variant_get (ret,
"(@a{sa{sv}})",
&secrets);
}
}
_call_id_invoke_callback (call_id, secrets, error, FALSE, TRUE);
}
/*****************************************************************************/
NMSecretAgentCallId *
nm_secret_agent_get_secrets (NMSecretAgent *self,
const char *path,
NMConnection *connection,
const char *setting_name,
const char **hints,
NMSecretAgentGetSecretsFlags flags,
NMSecretAgentCallback callback,
gpointer callback_data)
{
NMSecretAgentPrivate *priv;
GVariant *dict;
NMSecretAgentCallId *call_id;
g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (path && *path, NULL);
g_return_val_if_fail (setting_name, NULL);
g_return_val_if_fail (callback, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
/* Mask off the private flags if present */
flags &= ~( NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM
| NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS);
call_id = _call_id_new (self, METHOD_GET_SECRETS, path, setting_name, callback, callback_data);
g_dbus_connection_call (priv->dbus_connection,
priv->dbus_owner,
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT,
call_id->method_name,
g_variant_new ("(@a{sa{sv}}os^asu)",
dict,
path,
setting_name,
hints ?: NM_PTRARRAY_EMPTY (const char *),
(guint32) flags),
G_VARIANT_TYPE ("(a{sa{sv}})"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
120000,
call_id->cancellable,
_dbus_call_cb,
call_id);
return call_id;
}
/*****************************************************************************/
static void
_call_cancel_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
NMSecretAgentCallId *call_id = user_data;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *ret = NULL;
ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (ret)
_LOG2T (call_id, "success cancelling GetSecrets");
else if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
_LOG2T (call_id, "cancelling GetSecrets no longer works as service disconnected");
else {
_LOG2T (call_id, "failed to cancel GetSecrets: %s",
error->message);
}
_call_id_free (call_id);
}
/**
* nm_secret_agent_cancel_call:
* @self: the #NMSecretAgent instance for the @call_id.
* Maybe be %NULL if @call_id is %NULL.
* @call_id: (allow-none): the call id to cancel. May be %NULL for convenience,
* in which case it does nothing.
*
* It is an error to pass an invalid @call_id or a @call_id for an operation
* that already completed. It is also an error to cancel the call from inside
* the callback, at that point the call is already completed.
* In case of nm_secret_agent_cancel_call() this will synchronously invoke the
* callback before nm_secret_agent_cancel_call() returns.
*/
void
nm_secret_agent_cancel_call (NMSecretAgent *self,
NMSecretAgentCallId *call_id)
{
NMSecretAgentPrivate *priv;
gboolean free_call_id = TRUE;
if (!call_id) {
/* for convenience, %NULL is accepted fine. */
nm_assert (!self || NM_IS_SECRET_AGENT (self));
return;
}
g_return_if_fail (NM_IS_SECRET_AGENT (call_id->self));
g_return_if_fail (!c_list_is_empty (&call_id->lst));
/* Theoretically, call-id already has a self pointer. But nm_secret_agent_cancel_call() has only
* one user: NMAgentManager. And that one has the self-pointer at hand, so the only purpose of
* the @self argument is to assert that we are cancelling the expected call.
*
* We could drop the @self argument, but that just remove an additional assert-check from
* our code, without making a simplification for the only caller of this function. */
g_return_if_fail (self == call_id->self);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
nm_assert (c_list_contains (&priv->requests,
&call_id->lst));
nm_clear_g_cancellable (&call_id->cancellable);
if (nm_streq (call_id->method_name, METHOD_GET_SECRETS)) {
g_dbus_connection_call (priv->dbus_connection,
priv->dbus_owner,
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT,
METHOD_CANCEL_GET_SECRETS,
g_variant_new ("(os)",
call_id->path,
call_id->setting_name),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
NM_SHUTDOWN_TIMEOUT_MS,
NULL, /* this operation is not cancellable. We rely on the timeout. */
_call_cancel_cb,
call_id);
/* we keep call-id alive, but it will be unlinked from priv->requests.
* _call_cancel_cb() will finally free it later. */
free_call_id = FALSE;
}
_call_id_invoke_callback (call_id, NULL, NULL, TRUE, free_call_id);
}
/*****************************************************************************/
NMSecretAgentCallId *
nm_secret_agent_save_secrets (NMSecretAgent *self,
const char *path,
NMConnection *connection,
NMSecretAgentCallback callback,
gpointer callback_data)
{
NMSecretAgentPrivate *priv;
GVariant *dict;
NMSecretAgentCallId *call_id;
g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (path && *path, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
/* Caller should have ensured that only agent-owned secrets exist in 'connection' */
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
call_id = _call_id_new (self, METHOD_SAVE_SECRETS, path, NULL, callback, callback_data);
g_dbus_connection_call (priv->dbus_connection,
priv->dbus_owner,
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT,
call_id->method_name,
g_variant_new ("(@a{sa{sv}}o)",
dict,
path),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
60000,
call_id->cancellable,
_dbus_call_cb,
call_id);
return call_id;
}
/*****************************************************************************/
NMSecretAgentCallId *
nm_secret_agent_delete_secrets (NMSecretAgent *self,
const char *path,
NMConnection *connection,
NMSecretAgentCallback callback,
gpointer callback_data)
{
NMSecretAgentPrivate *priv;
GVariant *dict;
NMSecretAgentCallId *call_id;
g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (path && *path, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
/* No secrets sent; agents must be smart enough to track secrets using the UUID or something */
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS);
call_id = _call_id_new (self, METHOD_DELETE_SECRETS, path, NULL, callback, callback_data);
g_dbus_connection_call (priv->dbus_connection,
priv->dbus_owner,
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT,
call_id->method_name,
g_variant_new ("(@a{sa{sv}}o)",
dict,
path),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
60000,
call_id->cancellable,
_dbus_call_cb,
call_id);
return call_id;
}
/*****************************************************************************/
static void
name_owner_changed (NMSecretAgent *self,
const char *owner)
{
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
nm_assert (!priv->name_owner_cancellable);
owner = nm_str_not_empty (owner);
_LOGT ("name-owner-changed: %s%s%s",
NM_PRINT_FMT_QUOTED (owner, "has ", owner, "", "disconnected"));
if (owner)
return;
nm_clear_g_dbus_connection_signal (priv->dbus_connection,
&priv->name_owner_changed_id);
g_signal_emit (self, signals[DISCONNECTED], 0);
}
static void
name_owner_changed_cb (GDBusConnection *dbus_connection,
const char *sender_name,
const char *object_path,
const char *interface_name,
const char *signal_name,
GVariant *parameters,
gpointer user_data)
{
NMSecretAgent *self = NM_SECRET_AGENT (user_data);
const char *new_owner = NULL;
if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) {
g_variant_get (parameters,
"(&s&s&s)",
NULL,
NULL,
&new_owner);
}
nm_clear_g_cancellable (&NM_SECRET_AGENT_GET_PRIVATE (self)->name_owner_cancellable);
name_owner_changed (self, new_owner);
}
static void
get_name_owner_cb (const char *name_owner,
GError *error,
gpointer user_data)
{
NMSecretAgent *self;
if ( !name_owner
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
g_clear_object (&NM_SECRET_AGENT_GET_PRIVATE (self)->name_owner_cancellable);
name_owner_changed (self, name_owner);
}
/*****************************************************************************/
NMSecretAgent *
nm_secret_agent_new (GDBusMethodInvocation *context,
NMAuthSubject *subject,
const char *identifier,
NMSecretAgentCapabilities capabilities)
{
NMSecretAgent *self;
NMSecretAgentPrivate *priv;
const char *dbus_owner;
struct passwd *pw;
char *owner_username = NULL;
char *description = NULL;
char buf_subject[64];
char buf_caps[150];
gulong uid;
GDBusConnection *dbus_connection;
g_return_val_if_fail (context != NULL, NULL);
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL);
g_return_val_if_fail (identifier != NULL, NULL);
dbus_connection = g_dbus_method_invocation_get_connection (context);
g_return_val_if_fail (G_IS_DBUS_CONNECTION (dbus_connection), NULL);
uid = nm_auth_subject_get_unix_process_uid (subject);
pw = getpwuid (uid);
if (pw && pw->pw_name && pw->pw_name[0])
owner_username = g_strdup (pw->pw_name);
dbus_owner = nm_auth_subject_get_unix_process_dbus_sender (subject);
self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
priv->dbus_connection = g_object_ref (dbus_connection);
_LOGT ("constructed: %s, owner=%s%s%s (%s), unique-name=%s%s%s, capabilities=%s",
(description = _create_description (dbus_owner, identifier, uid)),
NM_PRINT_FMT_QUOTE_STRING (owner_username),
nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)),
NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->dbus_connection)),
_capabilities_to_string (capabilities, buf_caps, sizeof (buf_caps)));
priv->identifier = g_strdup (identifier);
priv->owner_username = owner_username;
priv->dbus_owner = g_strdup (dbus_owner);
priv->description = description;
priv->capabilities = capabilities;
priv->subject = g_object_ref (subject);
priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection,
priv->dbus_owner,
name_owner_changed_cb,
self,
NULL);
priv->name_owner_cancellable = g_cancellable_new ();
nm_dbus_connection_call_get_name_owner (priv->dbus_connection,
priv->dbus_owner,
-1,
priv->name_owner_cancellable,
get_name_owner_cb,
self);
return self;
}
static void
nm_secret_agent_init (NMSecretAgent *self)
{
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
c_list_init (&priv->permissions);
c_list_init (&priv->requests);
}
static void
dispose (GObject *object)
{
NMSecretAgent *self = NM_SECRET_AGENT (object);
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
nm_assert (c_list_is_empty (&priv->requests));
nm_clear_g_dbus_connection_signal (priv->dbus_connection,
&priv->name_owner_changed_id);
nm_clear_g_cancellable (&priv->name_owner_cancellable);
G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMSecretAgent *self = NM_SECRET_AGENT (object);
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
g_free (priv->description);
g_free (priv->identifier);
g_free (priv->owner_username);
g_free (priv->dbus_owner);
nm_c_list_elem_free_all (&priv->permissions, g_free);
g_clear_object (&priv->subject);
g_clear_object (&priv->dbus_connection);
G_OBJECT_CLASS (nm_secret_agent_parent_class)->finalize (object);
_LOGT ("finalized");
}
static void
nm_secret_agent_class_init (NMSecretAgentClass *config_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (config_class);
object_class->dispose = dispose;
object_class->finalize = finalize;
signals[DISCONNECTED] =
g_signal_new (NM_SECRET_AGENT_DISCONNECTED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}