mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 03:00:13 +01:00
The Settings.Connection interface is now only provided by NetworkManager itself since there is only one settings service. NM can validate requests for secrets internally and thus there's no need to lock down GetSecrets using a separate D-Bus interface, since PolicyKit provides that functionality on systems where this is desirable (ie multi-user). Single-user systems that do not have PolicyKit will inherently trust the user already, or if not D-Bus auth is flexible enough to lock down the GetSecrets method individually even if it's not on a separate D-Bus interface. Second, since only clients like connection editors or applets will be calling the GetSecrets method, there's no need for 'hints' or 'request_new' arguments here since this method should never trigger an interactive secrets request. Only NM should send those requests when it knows it needs to ask the user, either during connection or after validating the incoming GetSecrets request. A connection editor type application should never be able to trigger the normal "What's your passphrase" dialog thats provided by the secret agent for that user's session.
477 lines
15 KiB
C
477 lines
15 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/*
|
|
* libnm_glib -- Access network status & information from glib applications
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2007 - 2008 Novell, Inc.
|
|
* Copyright (C) 2007 - 2011 Red Hat, Inc.
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <NetworkManager.h>
|
|
#include <nm-utils.h>
|
|
#include <nm-setting-connection.h>
|
|
#include "nm-remote-connection.h"
|
|
#include "nm-remote-connection-private.h"
|
|
#include "nm-dbus-glib-types.h"
|
|
#include "nm-sysconfig-connection-bindings.h"
|
|
|
|
#define NM_REMOTE_CONNECTION_BUS "bus"
|
|
|
|
G_DEFINE_TYPE (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNECTION)
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_BUS,
|
|
PROP_INIT_RESULT,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
enum {
|
|
UPDATED,
|
|
REMOVED,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
typedef struct {
|
|
NMRemoteConnection *self;
|
|
DBusGProxyCall *call;
|
|
GFunc callback;
|
|
gpointer user_data;
|
|
} RemoteCall;
|
|
|
|
typedef struct {
|
|
DBusGConnection *bus;
|
|
DBusGProxy *proxy;
|
|
GSList *calls;
|
|
|
|
NMRemoteConnectionInitResult init_result;
|
|
gboolean disposed;
|
|
} NMRemoteConnectionPrivate;
|
|
|
|
#define NM_REMOTE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionPrivate))
|
|
|
|
/****************************************************************/
|
|
|
|
static void
|
|
remote_call_complete (NMRemoteConnection *self, RemoteCall *call)
|
|
{
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
priv->calls = g_slist_remove (priv->calls, call);
|
|
/* Don't need to cancel it since this function should only be called from
|
|
* the dispose handler (where the proxy will be destroyed immediately after)
|
|
* or from the call's completion callback.
|
|
*/
|
|
memset (call, 0, sizeof (RemoteCall));
|
|
g_free (call);
|
|
}
|
|
|
|
static void
|
|
update_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
|
|
{
|
|
RemoteCall *call = user_data;
|
|
NMRemoteConnectionCommitFunc func = (NMRemoteConnectionCommitFunc) call->callback;
|
|
|
|
(*func)(call->self, error, call->user_data);
|
|
remote_call_complete (call->self, call);
|
|
}
|
|
|
|
/**
|
|
* nm_remote_connection_commit_changes:
|
|
* @connection: the #NMRemoteConnection
|
|
* @callback: (scope async): a function to be called when the commit completes
|
|
* @user_data: caller-specific data to be passed to @callback
|
|
*
|
|
* Save any local changes to the settings and properties of this connection and
|
|
* save them in the settings service.
|
|
**/
|
|
void
|
|
nm_remote_connection_commit_changes (NMRemoteConnection *self,
|
|
NMRemoteConnectionCommitFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
NMRemoteConnectionPrivate *priv;
|
|
GHashTable *settings = NULL;
|
|
RemoteCall *call;
|
|
|
|
g_return_if_fail (self != NULL);
|
|
g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
call = g_malloc0 (sizeof (RemoteCall));
|
|
call->self = self;
|
|
call->callback = (GFunc) callback;
|
|
call->user_data = user_data;
|
|
|
|
settings = nm_connection_to_hash (NM_CONNECTION (self));
|
|
|
|
call->call = org_freedesktop_NetworkManager_Settings_Connection_update_async (priv->proxy,
|
|
settings,
|
|
update_cb,
|
|
call);
|
|
g_assert (call->call);
|
|
priv->calls = g_slist_append (priv->calls, call);
|
|
|
|
g_hash_table_destroy (settings);
|
|
}
|
|
|
|
static void
|
|
delete_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
|
|
{
|
|
RemoteCall *call = user_data;
|
|
NMRemoteConnectionDeleteFunc func = (NMRemoteConnectionDeleteFunc) call->callback;
|
|
|
|
(*func)(call->self, error, call->user_data);
|
|
remote_call_complete (call->self, call);
|
|
}
|
|
|
|
/**
|
|
* nm_remote_connection_delete:
|
|
* @connection: the #NMRemoteConnection
|
|
* @callback: (scope async): a function to be called when the delete completes
|
|
* @user_data: caller-specific data to be passed to @callback
|
|
*
|
|
* Delete the connection.
|
|
**/
|
|
void
|
|
nm_remote_connection_delete (NMRemoteConnection *self,
|
|
NMRemoteConnectionDeleteFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
NMRemoteConnectionPrivate *priv;
|
|
RemoteCall *call;
|
|
|
|
g_return_if_fail (self != NULL);
|
|
g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
call = g_malloc0 (sizeof (RemoteCall));
|
|
call->self = self;
|
|
call->callback = (GFunc) callback;
|
|
call->user_data = user_data;
|
|
|
|
call->call = org_freedesktop_NetworkManager_Settings_Connection_delete_async (priv->proxy,
|
|
delete_cb,
|
|
call);
|
|
g_assert (call->call);
|
|
priv->calls = g_slist_append (priv->calls, call);
|
|
}
|
|
|
|
static void
|
|
get_secrets_cb (DBusGProxy *proxy, GHashTable *secrets, GError *error, gpointer user_data)
|
|
{
|
|
RemoteCall *call = user_data;
|
|
NMRemoteConnectionGetSecretsFunc func = (NMRemoteConnectionGetSecretsFunc) call->callback;
|
|
|
|
(*func)(call->self, error ? NULL : secrets, error, call->user_data);
|
|
remote_call_complete (call->self, call);
|
|
}
|
|
|
|
/**
|
|
* nm_remote_connection_get_secrets:
|
|
* @connection: the #NMRemoteConnection
|
|
* @setting_name: the #NMSetting object name to get secrets for
|
|
* @callback: (scope async): a function to be called when the update completes
|
|
* @user_data: caller-specific data to be passed to @callback
|
|
*
|
|
* Request the connection's secrets.
|
|
**/
|
|
void
|
|
nm_remote_connection_get_secrets (NMRemoteConnection *self,
|
|
const char *setting_name,
|
|
NMRemoteConnectionGetSecretsFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
NMRemoteConnectionPrivate *priv;
|
|
RemoteCall *call;
|
|
|
|
g_return_if_fail (self != NULL);
|
|
g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
call = g_malloc0 (sizeof (RemoteCall));
|
|
call->self = self;
|
|
call->callback = (GFunc) callback;
|
|
call->user_data = user_data;
|
|
|
|
call->call = org_freedesktop_NetworkManager_Settings_Connection_get_secrets_async (priv->proxy,
|
|
setting_name,
|
|
get_secrets_cb,
|
|
call);
|
|
g_assert (call->call);
|
|
priv->calls = g_slist_append (priv->calls, call);
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
static void
|
|
replace_settings (NMRemoteConnection *self, GHashTable *new_settings)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error))
|
|
g_signal_emit (self, signals[UPDATED], 0, new_settings);
|
|
else {
|
|
g_warning ("%s: error updating connection %s settings: (%d) %s",
|
|
__func__,
|
|
nm_connection_get_path (NM_CONNECTION (self)),
|
|
error ? error->code : -1,
|
|
(error && error->message) ? error->message : "(unknown)");
|
|
g_clear_error (&error);
|
|
|
|
g_signal_emit (self, signals[REMOVED], 0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_get_settings_cb (DBusGProxy *proxy,
|
|
GHashTable *new_settings,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
NMRemoteConnection *self = user_data;
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
if (error) {
|
|
/* Connection doesn't exist, or isn't visible to this user */
|
|
priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR;
|
|
g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT);
|
|
} else {
|
|
replace_settings (self, new_settings);
|
|
g_hash_table_destroy (new_settings);
|
|
priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS;
|
|
g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT);
|
|
}
|
|
}
|
|
|
|
static void
|
|
updated_get_settings_cb (DBusGProxy *proxy,
|
|
GHashTable *new_settings,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
NMRemoteConnection *self = user_data;
|
|
|
|
if (error) {
|
|
/* The connection no longer exists, or is no longer visible to this
|
|
* user; we must remove it.
|
|
*/
|
|
g_signal_emit (self, signals[REMOVED], 0);
|
|
} else {
|
|
replace_settings (self, new_settings);
|
|
g_hash_table_destroy (new_settings);
|
|
}
|
|
}
|
|
|
|
static void
|
|
updated_cb (DBusGProxy *proxy, gpointer user_data)
|
|
{
|
|
NMRemoteConnection *self = NM_REMOTE_CONNECTION (user_data);
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
/* The connection got updated; request the replacement settings */
|
|
org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy,
|
|
updated_get_settings_cb,
|
|
self);
|
|
}
|
|
|
|
static void
|
|
removed_cb (DBusGProxy *proxy, gpointer user_data)
|
|
{
|
|
g_signal_emit (G_OBJECT (user_data), signals[REMOVED], 0);
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/**
|
|
* nm_remote_connection_new:
|
|
* @bus: a valid and connected D-Bus connection
|
|
* @path: the D-Bus path of the connection as exported by the settings service
|
|
*
|
|
* Creates a new object representing the remote connection.
|
|
*
|
|
* Returns: the new remote connection object on success, or %NULL on failure
|
|
**/
|
|
NMRemoteConnection *
|
|
nm_remote_connection_new (DBusGConnection *bus,
|
|
const char *path)
|
|
{
|
|
g_return_val_if_fail (bus != NULL, NULL);
|
|
g_return_val_if_fail (path != NULL, NULL);
|
|
|
|
return (NMRemoteConnection *) g_object_new (NM_TYPE_REMOTE_CONNECTION,
|
|
NM_REMOTE_CONNECTION_BUS, bus,
|
|
NM_CONNECTION_PATH, path,
|
|
NULL);
|
|
}
|
|
|
|
static GObject *
|
|
constructor (GType type,
|
|
guint n_construct_params,
|
|
GObjectConstructParam *construct_params)
|
|
{
|
|
GObject *object;
|
|
NMRemoteConnectionPrivate *priv;
|
|
|
|
object = G_OBJECT_CLASS (nm_remote_connection_parent_class)->constructor (type, n_construct_params, construct_params);
|
|
if (!object)
|
|
return NULL;
|
|
|
|
priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
|
|
g_assert (priv->bus);
|
|
g_assert (nm_connection_get_path (NM_CONNECTION (object)));
|
|
|
|
priv->proxy = dbus_g_proxy_new_for_name (priv->bus,
|
|
NM_DBUS_SERVICE,
|
|
nm_connection_get_path (NM_CONNECTION (object)),
|
|
NM_DBUS_IFACE_SETTINGS_CONNECTION);
|
|
g_assert (priv->proxy);
|
|
dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT);
|
|
|
|
dbus_g_proxy_add_signal (priv->proxy, "Updated", G_TYPE_INVALID);
|
|
dbus_g_proxy_connect_signal (priv->proxy, "Updated", G_CALLBACK (updated_cb), object, NULL);
|
|
|
|
dbus_g_proxy_add_signal (priv->proxy, "Removed", G_TYPE_INVALID);
|
|
dbus_g_proxy_connect_signal (priv->proxy, "Removed", G_CALLBACK (removed_cb), object, NULL);
|
|
|
|
org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy,
|
|
init_get_settings_cb,
|
|
object);
|
|
return object;
|
|
}
|
|
|
|
static void
|
|
nm_remote_connection_init (NMRemoteConnection *self)
|
|
{
|
|
}
|
|
|
|
static void
|
|
set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_BUS:
|
|
/* Construct only */
|
|
priv->bus = dbus_g_connection_ref ((DBusGConnection *) g_value_get_boxed (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
get_property (GObject *object, guint prop_id,
|
|
GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMRemoteConnection *self = NM_REMOTE_CONNECTION (object);
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
|
|
|
|
switch (prop_id) {
|
|
case PROP_INIT_RESULT:
|
|
g_value_set_uint (value, priv->init_result);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dispose (GObject *object)
|
|
{
|
|
NMRemoteConnection *self = NM_REMOTE_CONNECTION (object);
|
|
NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
|
|
|
|
if (!priv->disposed) {
|
|
priv->disposed = TRUE;
|
|
|
|
while (g_slist_length (priv->calls))
|
|
remote_call_complete (self, priv->calls->data);
|
|
|
|
g_object_unref (priv->proxy);
|
|
dbus_g_connection_unref (priv->bus);
|
|
}
|
|
|
|
G_OBJECT_CLASS (nm_remote_connection_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (remote_class);
|
|
|
|
g_type_class_add_private (object_class, sizeof (NMRemoteConnectionPrivate));
|
|
|
|
/* virtual methods */
|
|
object_class->set_property = set_property;
|
|
object_class->get_property = get_property;
|
|
object_class->dispose = dispose;
|
|
object_class->constructor = constructor;
|
|
|
|
/* Properties */
|
|
g_object_class_install_property
|
|
(object_class, PROP_BUS,
|
|
g_param_spec_boxed (NM_REMOTE_CONNECTION_BUS,
|
|
"DBusGConnection",
|
|
"DBusGConnection",
|
|
DBUS_TYPE_G_CONNECTION,
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
g_object_class_install_property
|
|
(object_class, PROP_INIT_RESULT,
|
|
g_param_spec_uint (NM_REMOTE_CONNECTION_INIT_RESULT,
|
|
"Initialization result (PRIVATE)",
|
|
"Initialization result (PRIVATE)",
|
|
NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN,
|
|
NM_REMOTE_CONNECTION_INIT_RESULT_ERROR,
|
|
NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN,
|
|
G_PARAM_READABLE));
|
|
|
|
/* Signals */
|
|
signals[UPDATED] =
|
|
g_signal_new (NM_REMOTE_CONNECTION_UPDATED,
|
|
G_TYPE_FROM_CLASS (remote_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMRemoteConnectionClass, updated),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[REMOVED] =
|
|
g_signal_new (NM_REMOTE_CONNECTION_REMOVED,
|
|
G_TYPE_FROM_CLASS (remote_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMRemoteConnectionClass, removed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
}
|