NetworkManager/src/settings/nm-sysconfig-connection.c
Dan Williams 9d077444a9 settings: remove settings dict from connection 'updated' signal
New connections should not be pushed out in the Updated signal
because signals cannot be restricted to particular clients, and
some clients may not have permission to view the connection.

Upon receiving the Updated signal, clients should re-read the
connection using GetSettings to ensure that the client still
has permissions to view the connection, and to get the updated
settings.
2010-12-02 14:34:38 -06:00

953 lines
29 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Novell, Inc.
* (C) Copyright 2008 - 2010 Red Hat, Inc.
*/
#include <string.h>
#include <NetworkManager.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <nm-setting-connection.h>
#include <nm-utils.h>
#include "nm-sysconfig-connection.h"
#include "nm-session-monitor.h"
#include "nm-dbus-manager.h"
#include "nm-settings-error.h"
#include "nm-dbus-glib-types.h"
#include "nm-polkit-helpers.h"
#include "nm-logging.h"
#include "nm-manager-auth.h"
static void impl_sysconfig_connection_get_settings (NMSysconfigConnection *connection,
DBusGMethodInvocation *context);
static void impl_sysconfig_connection_update (NMSysconfigConnection *connection,
GHashTable *new_settings,
DBusGMethodInvocation *context);
static void impl_sysconfig_connection_delete (NMSysconfigConnection *connection,
DBusGMethodInvocation *context);
static void impl_sysconfig_connection_get_secrets (NMSysconfigConnection *connection,
const gchar *setting_name,
const gchar **hints,
gboolean request_new,
DBusGMethodInvocation *context);
#include "nm-sysconfig-connection-glue.h"
G_DEFINE_TYPE (NMSysconfigConnection, nm_sysconfig_connection, NM_TYPE_CONNECTION)
#define NM_SYSCONFIG_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_SYSCONFIG_CONNECTION, \
NMSysconfigConnectionPrivate))
enum {
PROP_0 = 0,
PROP_VISIBLE,
};
enum {
UPDATED,
REMOVED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
PolkitAuthority *authority;
GSList *pending_auths; /* List of pending authentication requests */
NMConnection *secrets;
gboolean visible; /* Is this connection is visible by some session? */
NMSessionMonitor *session_monitor;
guint session_changed_id;
} NMSysconfigConnectionPrivate;
/**************************************************************/
#define USER_TAG "user:"
/* Extract the username from the permission string and dump to a buffer */
static gboolean
perm_to_user (const char *perm, char *out_user, gsize out_user_size)
{
const char *end;
gsize userlen;
g_return_val_if_fail (perm != NULL, FALSE);
g_return_val_if_fail (out_user != NULL, FALSE);
if (!g_str_has_prefix (perm, USER_TAG))
return FALSE;
perm += strlen (USER_TAG);
/* Look for trailing ':' */
end = strchr (perm, ':');
if (!end)
end = perm + strlen (perm);
userlen = end - perm;
if (userlen > (out_user_size + 1))
return FALSE;
memcpy (out_user, perm, userlen);
out_user[userlen] = '\0';
return TRUE;
}
/**************************************************************/
static void
set_visible (NMSysconfigConnection *self, gboolean new_visible)
{
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
if (new_visible == priv->visible)
return;
priv->visible = new_visible;
g_object_notify (G_OBJECT (self), NM_SYSCONFIG_CONNECTION_VISIBLE);
}
gboolean
nm_sysconfig_connection_is_visible (NMSysconfigConnection *self)
{
g_return_val_if_fail (NM_SYSCONFIG_CONNECTION (self), FALSE);
return NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self)->visible;
}
void
nm_sysconfig_connection_recheck_visibility (NMSysconfigConnection *self)
{
NMSysconfigConnectionPrivate *priv;
NMSettingConnection *s_con;
guint32 num, i;
g_return_if_fail (NM_SYSCONFIG_CONNECTION (self));
priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (self),
NM_TYPE_SETTING_CONNECTION));
g_assert (s_con);
/* Check every user in the ACL for a session */
num = nm_setting_connection_get_num_permissions (s_con);
if (num == 0) {
/* Visible to all */
set_visible (self, TRUE);
return;
}
for (i = 0; i < num; i++) {
const char *perm;
char buf[75];
perm = nm_setting_connection_get_permission (s_con, i);
g_assert (perm);
if (perm_to_user (perm, buf, sizeof (buf))) {
if (nm_session_monitor_user_has_session (priv->session_monitor, buf, NULL, NULL)) {
set_visible (self, TRUE);
return;
}
}
}
set_visible (self, FALSE);
}
static void
session_changed_cb (NMSessionMonitor *self, gpointer user_data)
{
nm_sysconfig_connection_recheck_visibility (NM_SYSCONFIG_CONNECTION (user_data));
}
/**************************************************************/
/* Update the settings of this connection to match that of 'new', taking care to
* make a private copy of secrets. */
gboolean
nm_sysconfig_connection_replace_settings (NMSysconfigConnection *self,
NMConnection *new,
GError **error)
{
NMSysconfigConnectionPrivate *priv;
GHashTable *new_settings;
gboolean success = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_SYSCONFIG_CONNECTION (self), FALSE);
g_return_val_if_fail (new != NULL, FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (new), FALSE);
priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
new_settings = nm_connection_to_hash (new);
g_assert (new_settings);
if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) {
/* Copy the connection to keep its secrets around even if NM
* calls nm_connection_clear_secrets().
*/
if (priv->secrets)
g_object_unref (priv->secrets);
priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
nm_sysconfig_connection_recheck_visibility (self);
success = TRUE;
}
g_hash_table_destroy (new_settings);
return success;
}
static void
ignore_cb (NMSysconfigConnection *connection,
GError *error,
gpointer user_data)
{
}
/* Replaces the settings in this connection with those in 'new'. If any changes
* are made, commits them to permanent storage and to any other subsystems
* watching this connection. Before returning, 'callback' is run with the given
* 'user_data' along with any errors encountered.
*/
void
nm_sysconfig_connection_replace_and_commit (NMSysconfigConnection *self,
NMConnection *new,
NMSysconfigConnectionCommitFunc callback,
gpointer user_data)
{
GError *error = NULL;
g_return_if_fail (self != NULL);
g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION (self));
g_return_if_fail (new != NULL);
g_return_if_fail (NM_IS_CONNECTION (new));
if (!callback)
callback = ignore_cb;
/* Do nothing if there's nothing to update */
if (nm_connection_compare (NM_CONNECTION (self),
NM_CONNECTION (new),
NM_SETTING_COMPARE_FLAG_EXACT)) {
callback (self, NULL, user_data);
return;
}
if (nm_sysconfig_connection_replace_settings (self, new, &error)) {
nm_sysconfig_connection_commit_changes (self, callback, user_data);
} else {
callback (self, error, user_data);
g_clear_error (&error);
}
}
void
nm_sysconfig_connection_commit_changes (NMSysconfigConnection *connection,
NMSysconfigConnectionCommitFunc callback,
gpointer user_data)
{
g_return_if_fail (connection != NULL);
g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION (connection));
g_return_if_fail (callback != NULL);
if (NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->commit_changes) {
NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->commit_changes (connection,
callback,
user_data);
} else {
GError *error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INTERNAL_ERROR,
"%s: %s:%d commit_changes() unimplemented", __func__, __FILE__, __LINE__);
callback (connection, error, user_data);
g_error_free (error);
}
}
void
nm_sysconfig_connection_delete (NMSysconfigConnection *connection,
NMSysconfigConnectionDeleteFunc callback,
gpointer user_data)
{
g_return_if_fail (connection != NULL);
g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION (connection));
g_return_if_fail (callback != NULL);
if (NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->delete) {
NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->delete (connection,
callback,
user_data);
} else {
GError *error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INTERNAL_ERROR,
"%s: %s:%d delete() unimplemented", __func__, __FILE__, __LINE__);
callback (connection, error, user_data);
g_error_free (error);
}
}
void
nm_sysconfig_connection_get_secrets (NMSysconfigConnection *connection,
const char *setting_name,
const char **hints,
gboolean request_new,
NMSysconfigConnectionGetSecretsFunc callback,
gpointer user_data)
{
g_return_if_fail (connection != NULL);
g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION (connection));
g_return_if_fail (callback != NULL);
if (NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->get_secrets) {
NM_SYSCONFIG_CONNECTION_GET_CLASS (connection)->get_secrets (connection,
setting_name,
hints,
request_new,
callback,
user_data);
} else {
GError *error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INTERNAL_ERROR,
"%s: %s:%d get_secrets() unimplemented", __func__, __FILE__, __LINE__);
callback (connection, NULL, error, user_data);
g_error_free (error);
}
}
/**************************************************************/
static void
commit_changes (NMSysconfigConnection *connection,
NMSysconfigConnectionCommitFunc callback,
gpointer user_data)
{
g_object_ref (connection);
g_signal_emit (connection, signals[UPDATED], 0);
callback (connection, NULL, user_data);
g_object_unref (connection);
}
static void
do_delete (NMSysconfigConnection *connection,
NMSysconfigConnectionDeleteFunc callback,
gpointer user_data)
{
g_object_ref (connection);
set_visible (connection, FALSE);
g_signal_emit (connection, signals[REMOVED], 0);
callback (connection, NULL, user_data);
g_object_unref (connection);
}
static GValue *
string_to_gvalue (const char *str)
{
GValue *val = g_slice_new0 (GValue);
g_value_init (val, G_TYPE_STRING);
g_value_set_string (val, str);
return val;
}
static GValue *
byte_array_to_gvalue (const GByteArray *array)
{
GValue *val;
val = g_slice_new0 (GValue);
g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
g_value_set_boxed (val, array);
return val;
}
static void
copy_one_secret (gpointer key, gpointer value, gpointer user_data)
{
const char *value_str = (const char *) value;
if (value_str) {
g_hash_table_insert ((GHashTable *) user_data,
g_strdup ((char *) key),
string_to_gvalue (value_str));
}
}
static void
add_secrets (NMSetting *setting,
const char *key,
const GValue *value,
GParamFlags flags,
gpointer user_data)
{
GHashTable *secrets = user_data;
if (!(flags & NM_SETTING_PARAM_SECRET))
return;
/* Copy secrets into the returned hash table */
if (G_VALUE_HOLDS_STRING (value)) {
const char *tmp;
tmp = g_value_get_string (value);
if (tmp)
g_hash_table_insert (secrets, g_strdup (key), string_to_gvalue (tmp));
} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
/* Flatten the string hash by pulling its keys/values out */
g_hash_table_foreach (g_value_get_boxed (value), copy_one_secret, secrets);
} else if (G_VALUE_TYPE (value) == DBUS_TYPE_G_UCHAR_ARRAY) {
GByteArray *array;
array = g_value_get_boxed (value);
if (array)
g_hash_table_insert (secrets, g_strdup (key), byte_array_to_gvalue (array));
}
}
static void
destroy_gvalue (gpointer data)
{
GValue *value = (GValue *) data;
g_value_unset (value);
g_slice_free (GValue, value);
}
static void
get_secrets (NMSysconfigConnection *connection,
const char *setting_name,
const char **hints,
gboolean request_new,
NMSysconfigConnectionGetSecretsFunc callback,
gpointer user_data)
{
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (connection);
GHashTable *settings = NULL;
GHashTable *secrets = NULL;
NMSetting *setting;
GError *error = NULL;
/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
* will clear secrets on this object's settings. priv->secrets should be
* a complete copy of this object and kept in sync by
* nm_sysconfig_connection_replace_settings().
*/
if (!priv->secrets) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"%s.%d - Internal error; secrets cache invalid.",
__FILE__, __LINE__);
(*callback) (connection, NULL, error, user_data);
g_error_free (error);
return;
}
setting = nm_connection_get_setting_by_name (priv->secrets, setting_name);
if (!setting) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_SETTING,
"%s.%d - Connection didn't have requested setting '%s'.",
__FILE__, __LINE__, setting_name);
(*callback) (connection, NULL, error, user_data);
g_error_free (error);
return;
}
/* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
* will contain all the individual settings hashes.
*/
settings = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_hash_table_destroy);
/* Add the secrets from this setting to the inner secrets hash for this setting */
secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
nm_setting_enumerate_values (setting, add_secrets, secrets);
g_hash_table_insert (settings, g_strdup (setting_name), secrets);
callback (connection, settings, NULL, user_data);
g_hash_table_destroy (settings);
}
/**** User authorization **************************************/
typedef void (*AuthCallback) (NMSysconfigConnection *connection,
DBusGMethodInvocation *context,
GError *error,
gpointer data);
static void
pk_auth_cb (NMAuthChain *chain,
GError *chain_error,
DBusGMethodInvocation *context,
gpointer user_data)
{
NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (user_data);
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
GError *error = NULL;
NMAuthCallResult result;
AuthCallback callback;
gpointer callback_data;
priv->pending_auths = g_slist_remove (priv->pending_auths, chain);
/* If our NMSysconfigConnection is already gone, do nothing */
if (chain_error) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_GENERAL,
"Error checking authorization: %s",
chain_error->message ? chain_error->message : "(unknown)");
} else {
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY);
/* Caller didn't successfully authenticate */
if (result != NM_AUTH_CALL_RESULT_YES) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_NOT_PRIVILEGED,
"Insufficient privileges.");
}
}
callback = nm_auth_chain_get_data (chain, "callback");
callback_data = nm_auth_chain_get_data (chain, "callback-data");
callback (self, context, error, callback_data);
g_clear_error (&error);
nm_auth_chain_unref (chain);
}
static void
auth_start (NMSysconfigConnection *self,
DBusGMethodInvocation *context,
gboolean check_modify,
AuthCallback callback,
gpointer callback_data)
{
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
NMAuthChain *chain;
gulong sender_uid = G_MAXULONG;
GError *error = NULL;
char *error_desc = NULL;
/* Get the caller's UID */
if (!nm_auth_get_caller_uid (context, NULL, &sender_uid, &error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error);
goto error;
}
/* Make sure the UID can view this connection */
if (0 != sender_uid) {
if (!nm_auth_uid_in_acl (NM_CONNECTION (self),
priv->session_monitor,
sender_uid,
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
goto error;
}
}
if (check_modify) {
chain = nm_auth_chain_new (priv->authority, context, NULL, pk_auth_cb, self);
g_assert (chain);
priv->pending_auths = g_slist_append (priv->pending_auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY, TRUE);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
} else {
/* Don't need polkit auth, automatic success */
callback (self, context, NULL, callback_data);
}
return;
error:
callback (self, context, error, callback_data);
g_error_free (error);
}
/**** DBus method handlers ************************************/
static gboolean
check_writable (NMConnection *connection, GError **error)
{
NMSettingConnection *s_con;
g_return_val_if_fail (connection != NULL, FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
s_con = (NMSettingConnection *) nm_connection_get_setting (connection,
NM_TYPE_SETTING_CONNECTION);
if (!s_con) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Connection did not have required 'connection' setting");
return FALSE;
}
/* If the connection is read-only, that has to be changed at the source of
* the problem (ex a system settings plugin that can't write connections out)
* instead of over D-Bus.
*/
if (nm_setting_connection_get_read_only (s_con)) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_READ_ONLY_CONNECTION,
"Connection is read-only");
return FALSE;
}
return TRUE;
}
static void
get_settings_auth_cb (NMSysconfigConnection *self,
DBusGMethodInvocation *context,
GError *error,
gpointer data)
{
NMConnection *no_secrets;
GHashTable *settings;
if (error) {
dbus_g_method_return_error (context, error);
return;
}
/* Secrets should *never* be returned by the GetSettings method, they
* get returned by the GetSecrets method which can be better
* protected against leakage of secrets to unprivileged callers.
*/
no_secrets = nm_connection_duplicate (NM_CONNECTION (self));
g_assert (no_secrets);
nm_connection_clear_secrets (no_secrets);
settings = nm_connection_to_hash (no_secrets);
g_assert (settings);
dbus_g_method_return (context, settings);
g_object_unref (no_secrets);
g_hash_table_destroy (settings);
}
static void
impl_sysconfig_connection_get_settings (NMSysconfigConnection *self,
DBusGMethodInvocation *context)
{
auth_start (self, context, FALSE, get_settings_auth_cb, NULL);
}
static void
con_update_cb (NMSysconfigConnection *connection,
GError *error,
gpointer user_data)
{
DBusGMethodInvocation *context = user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context);
}
static void
update_auth_cb (NMSysconfigConnection *self,
DBusGMethodInvocation *context,
GError *error,
gpointer data)
{
NMConnection *new_settings = data;
if (error) {
dbus_g_method_return_error (context, error);
goto out;
}
/* Update and commit our settings. */
nm_sysconfig_connection_replace_and_commit (self,
new_settings,
con_update_cb,
context);
out:
g_object_unref (new_settings);
}
static void
impl_sysconfig_connection_update (NMSysconfigConnection *self,
GHashTable *new_settings,
DBusGMethodInvocation *context)
{
NMConnection *tmp;
GError *error = NULL;
/* If the connection is read-only, that has to be changed at the source of
* the problem (ex a system settings plugin that can't write connections out)
* instead of over D-Bus.
*/
if (!check_writable (NM_CONNECTION (self), &error)) {
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
/* Check if the settings are valid first */
tmp = nm_connection_new_from_hash (new_settings, &error);
if (!tmp) {
g_assert (error);
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
auth_start (self, context, TRUE, update_auth_cb, tmp);
}
static void
con_delete_cb (NMSysconfigConnection *connection,
GError *error,
gpointer user_data)
{
DBusGMethodInvocation *context = user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context);
}
static void
delete_auth_cb (NMSysconfigConnection *self,
DBusGMethodInvocation *context,
GError *error,
gpointer data)
{
if (error) {
dbus_g_method_return_error (context, error);
return;
}
nm_sysconfig_connection_delete (self, con_delete_cb, context);
}
static void
impl_sysconfig_connection_delete (NMSysconfigConnection *self,
DBusGMethodInvocation *context)
{
GError *error = NULL;
if (!check_writable (NM_CONNECTION (self), &error)) {
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
auth_start (self, context, TRUE, delete_auth_cb, NULL);
}
typedef struct {
char *setting_name;
char **hints;
gboolean request_new;
} GetSecretsInfo;
static void
con_secrets_cb (NMSysconfigConnection *connection,
GHashTable *secrets,
GError *error,
gpointer user_data)
{
DBusGMethodInvocation *context = user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context, secrets);
}
static void
secrets_auth_cb (NMSysconfigConnection *self,
DBusGMethodInvocation *context,
GError *error,
gpointer data)
{
GetSecretsInfo *info = data;
if (error) {
dbus_g_method_return_error (context, error);
goto out;
}
nm_sysconfig_connection_get_secrets (self,
info->setting_name,
(const char **) info->hints,
info->request_new,
con_secrets_cb,
context);
out:
g_free (info->setting_name);
g_strfreev (info->hints);
g_slice_free (GetSecretsInfo, info);
}
static void
impl_sysconfig_connection_get_secrets (NMSysconfigConnection *self,
const gchar *setting_name,
const gchar **hints,
gboolean request_new,
DBusGMethodInvocation *context)
{
GetSecretsInfo *info = g_slice_new (GetSecretsInfo);
info->setting_name = g_strdup (setting_name);
info->hints = g_strdupv ((char **) hints);
info->request_new = request_new;
auth_start (self, context, TRUE, secrets_auth_cb, info);
}
/**************************************************************/
static void
nm_sysconfig_connection_init (NMSysconfigConnection *self)
{
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
static guint32 dbus_counter = 0;
char *dbus_path;
GError *error = NULL;
priv->authority = polkit_authority_get_sync (NULL, NULL);
if (!priv->authority) {
nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
dbus_path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, dbus_counter++);
nm_connection_set_path (NM_CONNECTION (self), dbus_path);
g_free (dbus_path);
priv->visible = FALSE;
priv->session_monitor = nm_session_monitor_get ();
priv->session_changed_id = g_signal_connect (priv->session_monitor,
NM_SESSION_MONITOR_CHANGED,
G_CALLBACK (session_changed_cb),
self);
}
static void
dispose (GObject *object)
{
NMSysconfigConnection *self = NM_SYSCONFIG_CONNECTION (object);
NMSysconfigConnectionPrivate *priv = NM_SYSCONFIG_CONNECTION_GET_PRIVATE (self);
GSList *iter;
if (priv->secrets)
g_object_unref (priv->secrets);
/* Cancel PolicyKit requests */
for (iter = priv->pending_auths; iter; iter = g_slist_next (iter))
nm_auth_chain_unref ((NMAuthChain *) iter->data);
g_slist_free (priv->pending_auths);
priv->pending_auths = NULL;
set_visible (self, FALSE);
g_object_unref (priv->session_monitor);
G_OBJECT_CLASS (nm_sysconfig_connection_parent_class)->dispose (object);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case PROP_VISIBLE:
g_value_set_boolean (value, NM_SYSCONFIG_CONNECTION_GET_PRIVATE (object)->visible);
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)
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
static void
nm_sysconfig_connection_class_init (NMSysconfigConnectionClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_class_add_private (class, sizeof (NMSysconfigConnectionPrivate));
/* Virtual methods */
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
class->commit_changes = commit_changes;
class->delete = do_delete;
class->get_secrets = get_secrets;
/* Properties */
g_object_class_install_property
(object_class, PROP_VISIBLE,
g_param_spec_boolean (NM_SYSCONFIG_CONNECTION_VISIBLE,
"Visible",
"Visible",
FALSE,
G_PARAM_READABLE));
/* Signals */
signals[UPDATED] =
g_signal_new (NM_SYSCONFIG_CONNECTION_UPDATED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[REMOVED] =
g_signal_new (NM_SYSCONFIG_CONNECTION_REMOVED,
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class),
&dbus_glib_nm_sysconfig_connection_object_info);
}