core: removal of PendingActivation object from nm-manager.c (bgo #707335)

This branch decouples NMActiveConnection creation from device activation
so that the NMActiveConnection object tracks the entire activation request
(either internally-requested by the Policy or externally via D-Bus) from
start to finish, instead of the previous situation where the PendingActivation
handled D-Bus requests separately.  This also will allow implementation of
the DEACTIVATING state in the future.  The NMActiveConnection object tracking
the activation is not actually exported to D-Bus until the device or VPN
activation is completely authorized and actually begins.

It also encapsulates all the details needed to authorize a request into
a new NMAuthSubject class, replacing various "dbus_sender" and "user_requested"
arguments throughout the code.
This commit is contained in:
Dan Williams 2013-10-31 15:06:23 -05:00
commit 8a173e1d7a
31 changed files with 2127 additions and 1374 deletions

View file

@ -248,6 +248,8 @@ nm_sources = \
nm-ip6-config.h \
nm-manager-auth.c \
nm-manager-auth.h \
nm-auth-subject.c \
nm-auth-subject.h \
nm-manager.c \
nm-manager.h \
nm-netlink-monitor.c \

View file

@ -147,6 +147,7 @@ get_generic_capabilities (NMDevice *dev)
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMActStageReturn ret;
NMActRequest *req;
NMConnection *connection;
NMSettingInfiniband *s_infiniband;
@ -156,6 +157,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
req = nm_device_get_act_request (dev);
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -186,7 +191,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
return NM_ACT_STAGE_RETURN_FAILURE;
}
return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void

View file

@ -252,8 +252,13 @@ deactivate (NMDevice *device)
static NMActStageReturn
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{
NMActStageReturn ret;
NMActRequest *req;
ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
req = nm_device_get_act_request (device);
g_assert (req);

View file

@ -252,8 +252,13 @@ static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (dev);
NMActStageReturn ret;
gboolean scanning;
ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (dev, reason);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
/* disconnect companion device, if it is connected */
if (nm_device_get_act_request (NM_DEVICE (priv->companion))) {
nm_log_info (LOGD_OLPC_MESH, "(%s): disconnecting companion device %s",

View file

@ -2790,6 +2790,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMActStageReturn ret;
NMAccessPoint *ap = NULL;
NMActRequest *req;
NMConnection *connection;
@ -2798,6 +2799,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
GSList *iter;
const char *mode;
ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage1_prepare (dev, reason);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
req = nm_device_get_act_request (NM_DEVICE (self));
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);

View file

@ -288,6 +288,7 @@ typedef struct {
/* master interface for bridge/bond/team slave */
NMDevice * master;
gboolean enslaved;
guint master_ready_id;
/* slave management */
gboolean is_master;
@ -1935,10 +1936,61 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
return FALSE;
}
static void
master_ready_cb (NMActiveConnection *active,
GParamSpec *pspec,
NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActiveConnection *master;
g_assert (priv->state == NM_DEVICE_STATE_PREPARE);
/* Notify a master device that it has a new slave */
g_assert (nm_active_connection_get_master_ready (active));
master = nm_active_connection_get_master (active);
priv->master = g_object_ref (nm_active_connection_get_device (master));
nm_device_master_add_slave (priv->master, self);
nm_log_dbg (LOGD_DEVICE, "(%s): master connection ready; master device %s",
nm_device_get_iface (self),
nm_device_get_iface (priv->master));
if (priv->master_ready_id) {
g_signal_handler_disconnect (active, priv->master_ready_id);
priv->master_ready_id = 0;
}
nm_device_activate_schedule_stage2_device_config (self);
}
static NMActStageReturn
act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
{
return NM_ACT_STAGE_RETURN_SUCCESS;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
if (nm_active_connection_get_master (active)) {
/* If the master connection is ready for slaves, attach ourselves */
if (nm_active_connection_get_master_ready (active))
master_ready_cb (active, NULL, self);
else {
nm_log_dbg (LOGD_DEVICE, "(%s): waiting for master connection to become ready",
nm_device_get_iface (self));
/* Attach a signal handler and wait for the master connection to begin activating */
g_assert (priv->master_ready_id == 0);
priv->master_ready_id = g_signal_connect (active,
"notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY,
(GCallback) master_ready_cb,
self);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
}
}
return ret;
}
/*
@ -3445,7 +3497,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *iface;
int ifindex;
NMDevice *master;
NMActiveConnection *master;
NMDevice *master_device;
/* Clear the activation source ID now that this stage has run */
activation_source_clear (self, FALSE, 0);
@ -3471,11 +3524,12 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
*/
master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request));
if (master) {
if (priv->enslaved == FALSE) {
master_device = nm_active_connection_get_device (master);
if (master_device && priv->enslaved == FALSE) {
nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on master '%s'",
nm_device_get_iface (self),
nm_connection_get_id (nm_device_get_connection (self)),
nm_device_get_iface (master));
nm_device_get_iface (master_device));
}
goto out;
}
@ -4022,6 +4076,11 @@ clear_act_request (NMDevice *self)
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
if (priv->master_ready_id) {
g_signal_handler_disconnect (priv->act_request, priv->master_ready_id);
priv->master_ready_id = 0;
}
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
@ -4425,8 +4484,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
nm_device_activate_schedule_stage3_ip_config_start (self);
} else {
NMDevice *master;
/* HACK: update the state a bit early to avoid a race between the
* scheduled stage1 handler and nm_policy_device_change_check() thinking
* that the activation request isn't deferred because the deferred bit
@ -4434,17 +4491,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
*/
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
/* Handle any dependencies this connection might have */
master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (req));
if (master) {
/* Master should at least already be activating */
g_assert (nm_device_get_state (master) > NM_DEVICE_STATE_DISCONNECTED);
g_assert (priv->master == NULL);
priv->master = g_object_ref (master);
nm_device_master_add_slave (master, self);
}
nm_device_activate_schedule_stage1_device_prepare (self);
}
}
@ -5027,6 +5073,7 @@ dispose (GObject *object)
dnsmasq_cleanup (self);
g_warn_if_fail (priv->slaves == NULL);
g_assert (priv->master_ready_id == 0);
/* Take the device itself down and clear its IPv4 configuration */
if (nm_device_get_managed (self) && deconfigure) {

View file

@ -9,6 +9,7 @@ AM_CPPFLAGS = \
-I${top_builddir}/libnm-util \
-I${top_srcdir}/libnm-util \
$(DBUS_CFLAGS) \
$(POLKIT_CFLAGS) \
$(IWMX_SDK_CFLAGS) \
$(LIBNL_CFLAGS) \
$(GUDEV_CFLAGS)

View file

@ -51,10 +51,6 @@ typedef struct {
} ShareRule;
typedef struct {
NMConnection *connection;
NMDevice *device;
guint device_state_id;
char *dbus_sender;
GSList *secrets_calls;
gboolean shared;
GSList *share_rules;
@ -70,14 +66,6 @@ nm_act_request_get_connection (NMActRequest *req)
return nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
}
const char *
nm_act_request_get_dbus_sender (NMActRequest *req)
{
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
return NM_ACT_REQUEST_GET_PRIVATE (req)->dbus_sender;
}
/*******************************************************************/
typedef struct {
@ -157,6 +145,7 @@ void
nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
{
NMActRequestPrivate *priv;
NMConnection *connection;
GSList *iter;
g_return_if_fail (self);
@ -165,6 +154,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
priv = NM_ACT_REQUEST_GET_PRIVATE (self);
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (self));
for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
GetSecretsInfo *info = iter->data;
@ -173,7 +163,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
priv->secrets_calls = g_slist_remove_link (priv->secrets_calls, iter);
g_slist_free (iter);
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), call_id);
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), call_id);
g_free (info);
break;
}
@ -295,13 +285,15 @@ nm_act_request_add_share_rule (NMActRequest *req,
/********************************************************************/
static void
device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
device_state_changed (NMActiveConnection *active,
NMDevice *device,
NMDeviceState new_state,
NMDeviceState old_state)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
/* Set NMActiveConnection state based on the device's state */
switch (nm_device_get_state (device)) {
switch (new_state) {
case NM_DEVICE_STATE_PREPARE:
case NM_DEVICE_STATE_CONFIG:
case NM_DEVICE_STATE_NEED_AUTH:
@ -321,13 +313,6 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
case NM_DEVICE_STATE_UNMANAGED:
case NM_DEVICE_STATE_UNAVAILABLE:
ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED;
/* No longer need to pay attention to device state */
if (priv->device && priv->device_state_id) {
g_signal_handler_disconnect (priv->device, priv->device_state_id);
priv->device_state_id = 0;
}
g_clear_object (&priv->device);
break;
default:
break;
@ -335,11 +320,33 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
|| ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (self), FALSE);
nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (self), FALSE);
nm_active_connection_set_default (active, FALSE);
nm_active_connection_set_default6 (active, FALSE);
}
nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), ac_state);
nm_active_connection_set_state (active, ac_state);
}
static void
master_failed (NMActiveConnection *self)
{
NMDevice *device;
NMDeviceState device_state;
/* If the connection has an active device, fail it */
device = nm_active_connection_get_device (self);
if (device) {
device_state = nm_device_get_state (device);
if (nm_device_is_activating (device) || (device_state == NM_DEVICE_STATE_ACTIVATED)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
return;
}
}
/* If no device, or the device wasn't active, just move to deactivated state */
nm_active_connection_set_state (self, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
}
/********************************************************************/
@ -350,48 +357,31 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
* @connection: the connection to activate @device with
* @specific_object: the object path of the specific object (ie, WiFi access point,
* etc) that will be used to activate @connection and @device
* @user_requested: pass %TRUE if the activation was requested via D-Bus,
* otherwise %FALSE if requested internally by NM (ie, autoconnect)
* @user_uid: if @user_requested is %TRUE, the Unix UID of the user that requested
* @dbus_sender: if @user_requested is %TRUE, the D-BUS sender that requested
* the activation
* @device: the device/interface to configure according to @connection
* @master: if the activation depends on another device (ie, bond or bridge
* or team master to which this device will be enslaved) pass the #NMDevice
* that this activation request be enslaved to
* @subject: the #NMAuthSubject representing the requestor of the activation
* @device: the device/interface to configure according to @connection; or %NULL
* if the connection describes a software device which will be created during
* connection activation
*
* Begins activation of @device using the given @connection and other details.
* Creates a new device-based activation request.
*
* Returns: the new activation request on success, %NULL on error.
*/
NMActRequest *
nm_act_request_new (NMConnection *connection,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
const char *dbus_sender,
NMDevice *device,
NMDevice *master)
NMAuthSubject *subject,
NMDevice *device)
{
GObject *object;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (NM_DEVICE (device), NULL);
g_return_val_if_fail (!device || NM_IS_DEVICE (device), NULL);
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
object = g_object_new (NM_TYPE_ACT_REQUEST,
NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
NM_ACTIVE_CONNECTION_INT_DEVICE, device,
NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested,
NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid,
NM_ACTIVE_CONNECTION_INT_MASTER, master,
NULL);
if (object) {
nm_active_connection_export (NM_ACTIVE_CONNECTION (object));
NM_ACT_REQUEST_GET_PRIVATE (object)->dbus_sender = g_strdup (dbus_sender);
}
return (NMActRequest *) object;
return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST,
NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
NM_ACTIVE_CONNECTION_INT_DEVICE, device,
NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NULL);
}
static void
@ -399,39 +389,13 @@ nm_act_request_init (NMActRequest *req)
{
}
static void
constructed (GObject *object)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
NMConnection *connection;
NMDevice *device;
G_OBJECT_CLASS (nm_act_request_parent_class)->constructed (object);
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
priv->connection = g_object_ref (connection);
device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
if (device) {
priv->device = g_object_ref (device);
priv->device_state_id = g_signal_connect (priv->device,
"notify::" NM_DEVICE_STATE,
G_CALLBACK (device_state_changed),
NM_ACT_REQUEST (object));
}
}
static void
dispose (GObject *object)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
NMConnection *connection;
GSList *iter;
if (priv->device && priv->device_state_id) {
g_signal_handler_disconnect (priv->device, priv->device_state_id);
priv->device_state_id = 0;
}
/* Clear any share rules */
if (priv->share_rules) {
nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE);
@ -439,22 +403,16 @@ dispose (GObject *object)
}
/* Kill any in-progress secrets requests */
for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
for (iter = priv->secrets_calls; connection && iter; iter = g_slist_next (iter)) {
GetSecretsInfo *info = iter->data;
g_assert (priv->connection);
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), info->call_id);
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), info->call_id);
g_free (info);
}
g_slist_free (priv->secrets_calls);
priv->secrets_calls = NULL;
g_free (priv->dbus_sender);
priv->dbus_sender = NULL;
g_clear_object (&priv->device);
g_clear_object (&priv->connection);
G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
}
@ -462,11 +420,13 @@ static void
nm_act_request_class_init (NMActRequestClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (req_class);
g_type_class_add_private (req_class, sizeof (NMActRequestPrivate));
/* virtual methods */
object_class->constructed = constructed;
object_class->dispose = dispose;
active_class->master_failed = master_failed;
active_class->device_state_changed = device_state_changed;
}

View file

@ -48,18 +48,11 @@ GType nm_act_request_get_type (void);
NMActRequest *nm_act_request_new (NMConnection *connection,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
const char *dbus_sender,
NMDevice *device,
NMDevice *master);
NMAuthSubject *subject,
NMDevice *device);
NMConnection *nm_act_request_get_connection (NMActRequest *req);
gulong nm_act_request_get_user_uid (NMActRequest *req);
const char *nm_act_request_get_dbus_sender (NMActRequest *req);
gboolean nm_act_request_get_shared (NMActRequest *req);
void nm_act_request_set_shared (NMActRequest *req, gboolean shared);

View file

@ -27,6 +27,8 @@
#include "nm-dbus-manager.h"
#include "nm-device.h"
#include "nm-settings-connection.h"
#include "nm-manager-auth.h"
#include "NetworkManagerUtils.h"
#include "nm-active-connection-glue.h"
@ -42,15 +44,22 @@ typedef struct {
char *path;
char *specific_object;
NMDevice *device;
guint32 device_state_id;
gboolean is_default;
gboolean is_default6;
NMActiveConnectionState state;
gboolean vpn;
gboolean user_requested;
gulong user_uid;
NMDevice *master;
NMAuthSubject *subject;
NMActiveConnection *master;
gboolean master_ready;
NMAuthChain *chain;
const char *wifi_shared_permission;
NMActiveConnectionAuthResultFunc result_func;
gpointer user_data1;
gpointer user_data2;
} NMActiveConnectionPrivate;
enum {
@ -67,15 +76,35 @@ enum {
PROP_INT_CONNECTION,
PROP_INT_DEVICE,
PROP_INT_USER_REQUESTED,
PROP_INT_USER_UID,
PROP_INT_SUBJECT,
PROP_INT_MASTER,
PROP_INT_MASTER_READY,
LAST_PROP
};
static void check_master_ready (NMActiveConnection *self);
/****************************************************************/
static const char *
state_to_string (NMActiveConnectionState state)
{
switch (state) {
case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
return "unknown";
case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
return "activating";
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
return "activated";
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
return "deactivating";
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
return "deactivated";
}
return "(none)";
}
NMActiveConnectionState
nm_active_connection_get_state (NMActiveConnection *self)
{
@ -100,6 +129,8 @@ nm_active_connection_set_state (NMActiveConnection *self,
priv->state = new_state;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
check_master_ready (self);
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|| old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection),
@ -107,8 +138,10 @@ nm_active_connection_set_state (NMActiveConnection *self,
}
if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
/* Device is no longer relevant when deactivated */
g_clear_object (&priv->device);
/* Device is no longer relevant when deactivated; emit property change
* notification so clients re-read the value, which will be NULL due to
* conditions in get_property().
*/
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
}
}
@ -127,6 +160,21 @@ nm_active_connection_get_connection (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection;
}
void
nm_active_connection_set_connection (NMActiveConnection *self,
NMConnection *connection)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
/* Can't change connection after the ActiveConnection is exported over D-Bus */
g_return_if_fail (priv->path == NULL);
g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection));
if (priv->connection)
g_object_unref (priv->connection);
priv->connection = g_object_ref (connection);
}
const char *
nm_active_connection_get_path (NMActiveConnection *self)
{
@ -145,6 +193,11 @@ nm_active_connection_set_specific_object (NMActiveConnection *self,
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
/* Nothing that calls this function should be using paths from D-Bus,
* where NM uses "/" to mean NULL.
*/
g_assert (g_strcmp0 (specific_object, "/") != 0);
if (g_strcmp0 (priv->specific_object, specific_object) == 0)
return;
@ -205,24 +258,37 @@ nm_active_connection_export (NMActiveConnection *self)
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
static guint32 counter = 0;
g_assert (priv->device || priv->vpn);
priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++);
nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self);
}
NMAuthSubject *
nm_active_connection_get_subject (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject;
}
gboolean
nm_active_connection_get_user_requested (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_requested;
return !nm_auth_subject_get_internal (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject);
}
gulong
nm_active_connection_get_user_uid (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG);
NMActiveConnectionPrivate *priv;
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_uid;
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG);
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
return nm_auth_subject_get_uid (priv->subject);
}
NMDevice *
@ -233,7 +299,73 @@ nm_active_connection_get_device (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device;
}
NMDevice *
static void
device_state_changed (NMDevice *device,
NMDeviceState new_state,
NMDeviceState old_state,
NMDeviceStateReason reason,
gpointer user_data)
{
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (old_state < NM_DEVICE_STATE_DISCONNECTED)
return;
if (old_state > NM_DEVICE_STATE_DISCONNECTED) {
/* Ignore disconnects if this ActiveConnection has not yet started
* activating. This is caused by activating a device when it's
* already activated, which causes a deactivating of the device before
* activating the new connection.
*/
if (new_state == NM_DEVICE_STATE_DISCONNECTED &&
old_state > NM_DEVICE_STATE_DISCONNECTED &&
priv->state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
return;
}
/* If the device used to be active, but now is disconnected/failed, we
* no longer care about its state.
*/
if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) {
g_signal_handler_disconnect (device, priv->device_state_id);
priv->device_state_id = 0;
}
}
/* Let subclasses handle the state change */
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state);
}
gboolean
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
{
NMActiveConnectionPrivate *priv;
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
if (device) {
g_return_val_if_fail (priv->device == NULL, FALSE);
/* Device obviously can't be its own master */
g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
priv->device = g_object_ref (device);
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
priv->device_state_id = g_signal_connect (device,
"state-changed",
G_CALLBACK (device_state_changed),
self);
}
return TRUE;
}
NMActiveConnection *
nm_active_connection_get_master (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
@ -241,6 +373,234 @@ nm_active_connection_get_master (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master;
}
/**
* nm_active_connection_get_master_ready:
* @self: the #NMActiveConnection
*
* Returns: %TRUE if the connection has a master connection, and that
* master connection is ready to accept slaves. Otherwise %FALSE.
*/
gboolean
nm_active_connection_get_master_ready (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master_ready;
}
static void
check_master_ready (NMActiveConnection *self)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) {
nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (not activating)", self);
return;
}
if (!priv->master) {
nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (no master)", self);
return;
}
if (priv->master_ready) {
nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (already signaled)", self);
return;
}
/* ActiveConnetions don't enter the ACTIVATING state until they have a
* NMDevice in PREPARE or higher states, so the master active connection's
* device will be ready to accept slaves when the master is in ACTIVATING
* or higher states.
*/
master_state = nm_active_connection_get_state (priv->master);
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)",
self, priv->master, state_to_string (master_state), master_state);
if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
|| master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
nm_log_dbg (LOGD_DEVICE, "(%p): signalling master-ready", self);
priv->master_ready = TRUE;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY);
/* Also notify clients to recheck the exported 'master' property to
* ensure that if the master connection was created without a device
* that we notify clients when the master device is known.
*/
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_MASTER);
}
}
static void
master_state_cb (NMActiveConnection *master,
GParamSpec *pspec,
gpointer user_data)
{
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionState self_state = nm_active_connection_get_state (self);
NMActiveConnectionState master_state = nm_active_connection_get_state (master);
check_master_ready (self);
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)",
self, master, state_to_string (master_state), master_state);
/* Master is deactivating, so this active connection must also deactivate */
if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING &&
master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] '%s' failed",
self, master, nm_active_connection_get_name (master));
g_signal_handlers_disconnect_by_func (master,
(GCallback) master_state_cb,
self);
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
}
}
/**
* nm_active_connection_set_master:
* @self: the #NMActiveConnection
* @master: if the activation depends on another device (ie, bond or bridge
* master to which this device will be enslaved) pass the #NMActiveConnection
* that this activation request is a child of
*
* Sets the master active connection of @self.
*/
void
nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master)
{
NMActiveConnectionPrivate *priv;
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master));
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
/* Master is write-once, and must be set before exporting the object */
g_return_if_fail (priv->master == NULL);
g_return_if_fail (priv->path == NULL);
if (priv->device) {
/* Note, the master ActiveConnection may not yet have a device */
g_return_if_fail (priv->device != nm_active_connection_get_device (master));
}
nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection is [%p] %s",
self, master, nm_active_connection_get_name (master));
priv->master = g_object_ref (master);
g_signal_connect (priv->master,
"notify::" NM_ACTIVE_CONNECTION_STATE,
(GCallback) master_state_cb,
self);
check_master_ready (self);
}
/****************************************************************/
static void
auth_done (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *unused,
gpointer user_data)
{
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
NMAuthCallResult result;
g_assert (priv->chain == chain);
g_assert (priv->result_func != NULL);
/* Must stay alive over the callback */
g_object_ref (self);
if (error) {
priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2);
goto done;
}
/* Caller has had a chance to obtain authorization, so we only need to
* check for 'yes' here.
*/
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
if (result != NM_AUTH_CALL_RESULT_YES) {
priv->result_func (self,
FALSE,
"Not authorized to control networking.",
priv->user_data1,
priv->user_data2);
goto done;
}
if (priv->wifi_shared_permission) {
result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission);
if (result != NM_AUTH_CALL_RESULT_YES) {
priv->result_func (self,
FALSE,
"Not authorized to share connections via wifi.",
priv->user_data1,
priv->user_data2);
goto done;
}
}
/* Otherwise authorized and available to activate */
priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2);
done:
nm_auth_chain_unref (chain);
priv->chain = NULL;
priv->result_func = NULL;
priv->user_data1 = NULL;
priv->user_data2 = NULL;
g_object_unref (self);
}
/**
* nm_active_connection_authorize:
* @self: the #NMActiveConnection
* @result_func: function to be called on success or error
* @user_data1: pointer passed to @result_func
* @user_data2: additional pointer passed to @result_func
*
* Checks whether the subject that initiated the active connection (read from
* the #NMActiveConnection::subject property) is authorized to complete this
* activation request.
*/
void
nm_active_connection_authorize (NMActiveConnection *self,
NMActiveConnectionAuthResultFunc result_func,
gpointer user_data1,
gpointer user_data2)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
const char *wifi_permission = NULL;
g_return_if_fail (result_func != NULL);
g_return_if_fail (priv->chain == NULL);
priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self);
g_assert (priv->chain);
/* Check that the subject is allowed to use networking at all */
nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
/* Shared wifi connections require special permissions too */
wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection);
if (wifi_permission) {
priv->wifi_shared_permission = wifi_permission;
nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE);
}
/* Wait for authorization */
priv->result_func = result_func;
priv->user_data1 = user_data1;
priv->user_data2 = user_data2;
}
/****************************************************************/
static void
@ -248,11 +608,19 @@ nm_active_connection_init (NMActiveConnection *self)
{
}
static void
constructed (GObject *object)
{
G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
const char *tmp;
switch (prop_id) {
case PROP_INT_CONNECTION:
@ -260,25 +628,19 @@ set_property (GObject *object, guint prop_id,
priv->connection = g_value_dup_object (value);
break;
case PROP_INT_DEVICE:
g_warn_if_fail (priv->device == NULL);
priv->device = g_value_dup_object (value);
if (priv->device)
g_warn_if_fail (priv->device != priv->master);
nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
break;
case PROP_INT_USER_REQUESTED:
priv->user_requested = g_value_get_boolean (value);
break;
case PROP_INT_USER_UID:
priv->user_uid = g_value_get_ulong (value);
case PROP_INT_SUBJECT:
priv->subject = g_value_dup_object (value);
break;
case PROP_INT_MASTER:
g_warn_if_fail (priv->master == NULL);
priv->master = g_value_dup_object (value);
if (priv->master)
g_warn_if_fail (priv->master != priv->device);
nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
break;
case PROP_SPECIFIC_OBJECT:
priv->specific_object = g_value_dup_boxed (value);
tmp = g_value_get_boxed (value);
/* NM uses "/" to mean NULL */
if (g_strcmp0 (tmp, "/") != 0)
priv->specific_object = g_value_dup_boxed (value);
break;
case PROP_DEFAULT:
priv->is_default = g_value_get_boolean (value);
@ -303,6 +665,7 @@ get_property (GObject *object, guint prop_id,
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
GPtrArray *devices;
NMDevice *master_device = NULL;
switch (prop_id) {
case PROP_CONNECTION:
@ -316,7 +679,7 @@ get_property (GObject *object, guint prop_id,
break;
case PROP_DEVICES:
devices = g_ptr_array_sized_new (1);
if (priv->device)
if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device)));
g_value_take_boxed (value, devices);
break;
@ -333,7 +696,15 @@ get_property (GObject *object, guint prop_id,
g_value_set_boolean (value, priv->vpn);
break;
case PROP_MASTER:
g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/");
if (priv->master)
master_device = nm_active_connection_get_device (priv->master);
g_value_set_boxed (value, master_device ? nm_device_get_path (master_device) : "/");
break;
case PROP_INT_SUBJECT:
g_value_set_object (value, priv->subject);
break;
case PROP_INT_MASTER_READY:
g_value_set_boolean (value, priv->master_ready);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -346,14 +717,32 @@ dispose (GObject *object)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
if (priv->chain) {
nm_auth_chain_unref (priv->chain);
priv->chain = NULL;
}
g_free (priv->path);
priv->path = NULL;
g_free (priv->specific_object);
priv->specific_object = NULL;
g_clear_object (&priv->connection);
if (priv->device_state_id) {
g_assert (priv->device);
g_signal_handler_disconnect (priv->device, priv->device_state_id);
priv->device_state_id = 0;
}
g_clear_object (&priv->device);
if (priv->master) {
g_signal_handlers_disconnect_by_func (priv->master,
(GCallback) master_state_cb,
NM_ACTIVE_CONNECTION (object));
}
g_clear_object (&priv->master);
g_clear_object (&priv->subject);
G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
}
@ -368,6 +757,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
/* virtual methods */
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->constructed = constructed;
object_class->dispose = dispose;
/* D-Bus exported properties */
@ -449,28 +839,27 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
"Internal device",
"Internal device",
NM_TYPE_DEVICE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_INT_SUBJECT,
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT,
"Subject",
"Subject",
NM_TYPE_AUTH_SUBJECT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_INT_USER_REQUESTED,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_USER_REQUESTED,
"User requested",
"User requested",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_INT_USER_UID,
g_param_spec_ulong (NM_ACTIVE_CONNECTION_INT_USER_UID,
"User UID",
"User UID (if user requested)",
0, G_MAXULONG, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_INT_MASTER,
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER,
"Internal master device",
"Internal device",
NM_TYPE_DEVICE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
"Internal master active connection",
"Internal active connection",
NM_TYPE_ACTIVE_CONNECTION,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_INT_MASTER_READY,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY,
"Internal master active connection ready for slaves",
"Internal active connection ready",
FALSE, G_PARAM_READABLE));
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (ac_class),

View file

@ -24,6 +24,7 @@
#include <glib-object.h>
#include "nm-types.h"
#include "nm-connection.h"
#include "nm-auth-subject.h"
#define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ())
#define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection))
@ -43,13 +44,12 @@
#define NM_ACTIVE_CONNECTION_VPN "vpn"
#define NM_ACTIVE_CONNECTION_MASTER "master"
/* Internal non-exported construct-time properties */
/* Internal non-exported properties */
#define NM_ACTIVE_CONNECTION_INT_CONNECTION "int-connection"
#define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device"
#define NM_ACTIVE_CONNECTION_INT_USER_REQUESTED "int-user-requested"
#define NM_ACTIVE_CONNECTION_INT_USER_UID "int-user-uid"
#define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject"
#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master"
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
typedef struct {
GObject parent;
@ -58,13 +58,36 @@ typedef struct {
typedef struct {
GObjectClass parent;
/* re-emits device state changes as a convenience for subclasses for
* device states >= DISCONNECTED.
*/
void (*device_state_changed) (NMActiveConnection *connection,
NMDevice *device,
NMDeviceState new_state,
NMDeviceState old_state);
void (*master_failed) (NMActiveConnection *connection);
} NMActiveConnectionClass;
GType nm_active_connection_get_type (void);
typedef void (*NMActiveConnectionAuthResultFunc) (NMActiveConnection *self,
gboolean success,
const char *error_desc,
gpointer user_data1,
gpointer user_data2);
void nm_active_connection_authorize (NMActiveConnection *self,
NMActiveConnectionAuthResultFunc result_func,
gpointer user_data1,
gpointer user_data2);
void nm_active_connection_export (NMActiveConnection *self);
NMConnection *nm_active_connection_get_connection (NMActiveConnection *self);
void nm_active_connection_set_connection (NMActiveConnection *self,
NMConnection *connection);
const char * nm_active_connection_get_name (NMActiveConnection *self);
const char * nm_active_connection_get_path (NMActiveConnection *self);
@ -91,10 +114,19 @@ void nm_active_connection_set_state (NMActiveConnection *self,
NMDevice * nm_active_connection_get_device (NMActiveConnection *self);
gboolean nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device);
NMAuthSubject *nm_active_connection_get_subject (NMActiveConnection *self);
gboolean nm_active_connection_get_user_requested (NMActiveConnection *self);
gulong nm_active_connection_get_user_uid (NMActiveConnection *self);
NMDevice * nm_active_connection_get_master (NMActiveConnection *self);
NMActiveConnection *nm_active_connection_get_master (NMActiveConnection *self);
gboolean nm_active_connection_get_master_ready (NMActiveConnection *self);
void nm_active_connection_set_master (NMActiveConnection *self,
NMActiveConnection *master);
#endif /* NM_ACTIVE_CONNECTION_H */

210
src/nm-auth-subject.c Normal file
View file

@ -0,0 +1,210 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* 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.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
/**
* SECTION:nm-auth-subject
* @short_description: Encapsulates authentication information about a requestor
*
* #NMAuthSubject encpasulates identifying information about an entity that
* makes requests, like process identifier and user UID.
*/
#include <config.h>
#include <glib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#if WITH_POLKIT
#include <polkit/polkit.h>
#endif
#include "nm-auth-subject.h"
#include "nm-dbus-manager.h"
G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
#define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate))
typedef struct {
gulong pid;
gulong uid;
char *dbus_sender;
#if WITH_POLKIT
PolkitSubject *pk_subject;
#endif
} NMAuthSubjectPrivate;
static NMAuthSubject *
_new_common (DBusGMethodInvocation *context,
DBusConnection *connection,
DBusMessage *message,
gboolean internal)
{
NMAuthSubject *subject;
NMAuthSubjectPrivate *priv;
NMDBusManager *dbus_mgr;
gboolean success = FALSE;
g_return_val_if_fail (context || (connection && message) || internal, NULL);
if (internal)
g_return_val_if_fail (context == NULL && connection == NULL && message == NULL, NULL);
subject = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, NULL));
priv = NM_AUTH_SUBJECT_GET_PRIVATE (subject);
dbus_mgr = nm_dbus_manager_get ();
if (internal) {
priv->uid = 0;
priv->pid = 0;
return subject;
}
if (context) {
success = nm_dbus_manager_get_caller_info (dbus_mgr,
context,
&priv->dbus_sender,
&priv->uid,
&priv->pid);
} else if (message) {
success = nm_dbus_manager_get_caller_info_from_message (dbus_mgr,
connection,
message,
&priv->dbus_sender,
&priv->uid,
&priv->pid);
} else
g_assert_not_reached ();
if (!success) {
g_object_unref (subject);
return NULL;
}
g_assert (priv->dbus_sender);
g_assert_cmpuint (priv->pid, !=, 0);
#if WITH_POLKIT
/* FIXME: should we use polkit_unix_session_new() to store the session ID
* of a short-lived process, so that the process can exit but we can still
* ask that user for authorization?
*/
priv->pk_subject = polkit_unix_process_new_for_owner (priv->pid, 0, priv->uid);
if (!priv->pk_subject)
return NULL;
#endif
return subject;
}
NMAuthSubject *
nm_auth_subject_new_from_context (DBusGMethodInvocation *context)
{
return _new_common (context, NULL, NULL, FALSE);
}
NMAuthSubject *
nm_auth_subject_new_from_message (DBusConnection *connection,
DBusMessage *message)
{
return _new_common (NULL, connection, message, FALSE);
}
/**
* nm_auth_subject_new_internal():
*
* Creates a new auth subject representing the NetworkManager process itself.
*
* Returns: the new #NMAuthSubject
*/
NMAuthSubject *
nm_auth_subject_new_internal (void)
{
return _new_common (NULL, NULL, NULL, TRUE);
}
/**************************************************************/
gulong
nm_auth_subject_get_uid (NMAuthSubject *subject)
{
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->uid;
}
const char *
nm_auth_subject_get_dbus_sender (NMAuthSubject *subject)
{
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender;
}
gboolean
nm_auth_subject_get_internal (NMAuthSubject *subject)
{
/* internal requests will have no dbus sender */
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender ? FALSE : TRUE;
}
#if WITH_POLKIT
PolkitSubject *
nm_auth_subject_get_polkit_subject (NMAuthSubject *subject)
{
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pk_subject;
}
#endif
/******************************************************************/
static void
nm_auth_subject_init (NMAuthSubject *self)
{
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
priv->pid = G_MAXULONG;
priv->uid = G_MAXULONG;
}
static void
finalize (GObject *object)
{
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
g_free (priv->dbus_sender);
#if WITH_POLKIT
if (priv->pk_subject)
g_object_unref (priv->pk_subject);
#endif
G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
}
static void
nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (config_class);
g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate));
/* virtual methods */
object_class->finalize = finalize;
}

68
src/nm-auth-subject.h Normal file
View file

@ -0,0 +1,68 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* 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.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
#ifndef NM_AUTH_SUBJECT_H
#define NM_AUTH_SUBJECT_H
#include <config.h>
#include <glib.h>
#include <glib-object.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#if WITH_POLKIT
#include <polkit/polkit.h>
#endif
#define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ())
#define NM_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject))
#define NM_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
#define NM_IS_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_SUBJECT))
#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT))
#define NM_AUTH_SUBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
typedef struct {
GObject parent;
} NMAuthSubject;
typedef struct {
GObjectClass parent;
} NMAuthSubjectClass;
GType nm_auth_subject_get_type (void);
NMAuthSubject *nm_auth_subject_new_from_context (DBusGMethodInvocation *context);
NMAuthSubject *nm_auth_subject_new_from_message (DBusConnection *connection, DBusMessage *message);
NMAuthSubject *nm_auth_subject_new_internal (void);
gulong nm_auth_subject_get_uid (NMAuthSubject *subject);
const char *nm_auth_subject_get_dbus_sender (NMAuthSubject *subject);
gboolean nm_auth_subject_get_internal (NMAuthSubject *subject);
#if WITH_POLKIT
PolkitSubject *nm_auth_subject_get_polkit_subject (NMAuthSubject *subject);
#endif
#endif /* NM_AUTH_SUBJECT_H */

View file

@ -267,6 +267,27 @@ private_server_get_connection_owner (PrivateServer *s, DBusGConnection *connecti
/**************************************************************/
static gboolean
_bus_get_unix_pid (NMDBusManager *self,
const char *sender,
gulong *out_pid,
GError **error)
{
guint32 unix_pid = G_MAXUINT32;
if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy,
"GetConnectionUnixProcessID", 2000, error,
G_TYPE_STRING, sender,
G_TYPE_INVALID,
G_TYPE_UINT, &unix_pid,
G_TYPE_INVALID)) {
return FALSE;
}
*out_pid = (gulong) unix_pid;
return TRUE;
}
/**
* _get_caller_info_from_context():
*
@ -279,7 +300,8 @@ _get_caller_info (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
gulong *out_uid)
gulong *out_uid,
gulong *out_pid)
{
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
DBusGConnection *gconn;
@ -312,6 +334,10 @@ _get_caller_info (NMDBusManager *self,
*out_uid = 0;
if (out_sender)
*out_sender = g_strdup (priv_sender);
if (out_pid) {
if (!dbus_connection_get_unix_process_id (connection, out_pid))
*out_pid = G_MAXULONG;
}
return TRUE;
}
}
@ -331,6 +357,14 @@ _get_caller_info (NMDBusManager *self,
}
}
if (out_pid) {
if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) {
*out_pid = G_MAXULONG;
g_free (sender);
return FALSE;
}
}
if (out_sender)
*out_sender = g_strdup (sender);
@ -342,9 +376,10 @@ gboolean
nm_dbus_manager_get_caller_info (NMDBusManager *self,
DBusGMethodInvocation *context,
char **out_sender,
gulong *out_uid)
gulong *out_uid,
gulong *out_pid)
{
return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid);
return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid);
}
gboolean
@ -352,9 +387,10 @@ nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
gulong *out_uid)
gulong *out_uid,
gulong *out_pid)
{
return _get_caller_info (self, NULL, connection, message, out_sender, out_uid);
return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid);
}
gboolean

View file

@ -87,7 +87,8 @@ DBusGConnection * nm_dbus_manager_get_connection (NMDBusManager *self);
gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self,
DBusGMethodInvocation *context,
char **out_sender,
gulong *out_uid);
gulong *out_uid,
gulong *out_pid);
gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self,
const char *sender,
@ -97,7 +98,8 @@ gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
gulong *out_uid);
gulong *out_uid,
gulong *out_pid);
void nm_dbus_manager_register_exported_type (NMDBusManager *self,
GType object_type,

View file

@ -31,6 +31,7 @@
#include "nm-manager-auth.h"
#include "nm-logging.h"
#include "nm-dbus-manager.h"
#include "nm-auth-subject.h"
struct NMAuthChain {
guint32 refcount;
@ -43,6 +44,7 @@ struct NMAuthChain {
DBusGMethodInvocation *context;
char *owner;
gulong user_uid;
NMAuthSubject *subject;
GError *error;
guint idle_id;
@ -105,16 +107,16 @@ pk_authority_get (GError **error)
#endif
static NMAuthChain *
_auth_chain_new (DBusGMethodInvocation *context,
DBusMessage *message,
_auth_chain_new (NMAuthSubject *subject,
const char *dbus_sender,
gulong user_uid,
DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
NMAuthChain *self;
g_return_val_if_fail (message || dbus_sender, NULL);
g_return_val_if_fail (subject || user_uid == 0 || dbus_sender, NULL);
self = g_malloc0 (sizeof (NMAuthChain));
self->refcount = 1;
@ -125,65 +127,73 @@ _auth_chain_new (DBusGMethodInvocation *context,
self->done_func = done_func;
self->user_data = user_data;
self->context = context;
self->user_uid = user_uid;
if (message)
self->owner = g_strdup (dbus_message_get_sender (message));
else if (dbus_sender)
if (subject) {
self->user_uid = nm_auth_subject_get_uid (subject);
self->subject = g_object_ref (subject);
} else {
self->user_uid = user_uid;
self->owner = g_strdup (dbus_sender);
if (user_uid > 0 && !self->owner) {
/* Need an owner */
g_warn_if_fail (self->owner);
nm_auth_chain_unref (self);
self = NULL;
if (user_uid > 0 && !self->owner) {
/* Need an owner */
g_warn_if_fail (self->owner);
nm_auth_chain_unref (self);
self = NULL;
}
}
return self;
}
NMAuthChain *
nm_auth_chain_new (DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data,
const char **out_error_desc)
{
gulong sender_uid = G_MAXULONG;
char *sender = NULL;
NMAuthChain *chain = NULL;
g_return_val_if_fail (context != NULL, NULL);
if (nm_dbus_manager_get_caller_info (nm_dbus_manager_get (),
context,
&sender,
&sender_uid)) {
chain = _auth_chain_new (context, NULL, sender, sender_uid, done_func, user_data);
}
if (!chain && out_error_desc)
*out_error_desc = "Unable to determine request UID and sender.";
g_free (sender);
return chain;
}
NMAuthChain *
nm_auth_chain_new_raw_message (DBusMessage *message,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (NULL, message, NULL, user_uid, done_func, user_data);
}
NMAuthChain *
nm_auth_chain_new_dbus_sender (const char *dbus_sender,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (NULL, NULL, dbus_sender, user_uid, done_func, user_data);
return _auth_chain_new (NULL, dbus_sender, user_uid, NULL, done_func, user_data);
}
/* Creates the NMAuthSubject automatically */
NMAuthChain *
nm_auth_chain_new_context (DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
NMAuthSubject *subject;
NMAuthChain *chain;
g_return_val_if_fail (context != NULL, NULL);
subject = nm_auth_subject_new_from_context (context);
if (!subject)
return NULL;
chain = nm_auth_chain_new_subject (subject,
context,
done_func,
user_data);
g_object_unref (subject);
return chain;
}
/* Requires an NMAuthSubject */
NMAuthChain *
nm_auth_chain_new_subject (NMAuthSubject *subject,
DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
NMAuthChain *chain;
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data);
/* Chains creation from a valid NMAuthSubject cannot fail since the
* subject already has all the necessary auth info.
*/
g_assert (chain);
return chain;
}
gpointer
@ -422,7 +432,7 @@ _add_call_polkit (NMAuthChain *self,
AuthCall *call;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (self->owner != NULL, FALSE);
g_return_val_if_fail (self->owner || self->subject, FALSE);
g_return_val_if_fail (permission != NULL, FALSE);
call = auth_call_new (self, permission);
@ -433,10 +443,16 @@ _add_call_polkit (NMAuthChain *self,
return FALSE;
}
subject = polkit_system_bus_name_new (self->owner);
if (!subject) {
auth_call_schedule_complete_with_error (call, "Failed to create polkit subject");
return FALSE;
if (self->subject) {
subject = g_object_ref (nm_auth_subject_get_polkit_subject (self->subject));
g_assert (subject);
} else {
g_assert (self->owner);
subject = polkit_system_bus_name_new (self->owner);
if (!subject) {
auth_call_schedule_complete_with_error (call, "Failed to create polkit subject");
return FALSE;
}
}
if (allow_interaction)
@ -496,6 +512,7 @@ nm_auth_chain_unref (NMAuthChain *self)
g_object_unref (self->authority);
#endif
g_free (self->owner);
g_object_unref (self->subject);
for (iter = self->calls; iter; iter = g_slist_next (iter))
auth_call_cancel ((AuthCall *) iter->data);

View file

@ -27,6 +27,7 @@
#include <nm-connection.h>
#include "nm-dbus-manager.h"
#include "nm-session-monitor.h"
#include "nm-auth-subject.h"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake"
@ -55,21 +56,20 @@ typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
DBusGMethodInvocation *context,
gpointer user_data);
NMAuthChain *nm_auth_chain_new (DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data,
const char **out_error_desc);
NMAuthChain *nm_auth_chain_new_raw_message (DBusMessage *message,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_context (DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject,
DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data);
gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag);
gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag);

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
#include <dbus/dbus-glib.h>
#include "nm-device.h"
#include "nm-settings.h"
#include "nm-auth-subject.h"
#define NM_TYPE_MANAGER (nm_manager_get_type ())
#define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager))
@ -116,8 +117,8 @@ NMDevice *nm_manager_get_device_by_ifindex (NMManager *manager,
NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
NMConnection *connection,
const char *specific_object,
const char *device_path,
const char *dbus_sender, /* NULL if automatic */
NMDevice *device,
NMAuthSubject *subject,
GError **error);
gboolean nm_manager_deactivate_connection (NMManager *manager,

View file

@ -669,7 +669,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
gw_addr = nm_ip4_config_get_gateway (ip4_config);
if (vpn) {
NMDevice *parent = nm_vpn_connection_get_parent_device (vpn);
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
int parent_ifindex = nm_device_get_ip_ifindex (parent);
NMIP4Config *parent_ip4 = nm_device_get_ip4_config (parent);
guint32 parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0;
@ -683,7 +683,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
}
}
default_device = nm_vpn_connection_get_parent_device (vpn);
default_device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
} else {
int mss = nm_ip4_config_get_mss (ip4_config);
@ -856,7 +856,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
gw_addr = &in6addr_any;
if (vpn) {
NMDevice *parent = nm_vpn_connection_get_parent_device (vpn);
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
int parent_ifindex = nm_device_get_ip_ifindex (parent);
NMIP6Config *parent_ip6 = nm_device_get_ip6_config (parent);
guint32 parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0;
@ -873,7 +873,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
}
}
default_device6 = nm_vpn_connection_get_parent_device (vpn);
default_device6 = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
} else {
int mss = nm_ip6_config_get_mss (ip6_config);
@ -1034,14 +1034,16 @@ auto_activate_device (gpointer user_data)
best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object);
if (best_connection) {
GError *error = NULL;
NMAuthSubject *subject;
nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.",
nm_connection_get_id (best_connection));
subject = nm_auth_subject_new_internal ();
if (!nm_manager_activate_connection (priv->manager,
best_connection,
specific_object,
nm_device_get_path (data->device),
NULL,
data->device,
subject,
&error)) {
nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s",
nm_connection_get_id (best_connection),
@ -1049,6 +1051,7 @@ auto_activate_device (gpointer user_data)
error ? error->message : "(none)");
g_error_free (error);
}
g_object_unref (subject);
}
g_slist_free (connections);
@ -1110,7 +1113,7 @@ static void
pending_secondary_data_free (PendingSecondaryData *data)
{
g_object_unref (data->device);
g_slist_free_full (data->secondaries, g_free);
g_slist_free_full (data->secondaries, g_object_unref);
memset (data, 0, sizeof (*data));
g_free (data);
}
@ -1121,51 +1124,47 @@ process_secondaries (NMPolicy *policy,
gboolean connected)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
NMDevice *device = NULL;
const char *ac_path;
GSList *iter, *iter2;
nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' %s; active path '%s'",
nm_active_connection_get_name (active),
connected ? "SUCCEEDED" : "FAILED",
nm_active_connection_get_path (active));
ac_path = nm_active_connection_get_path (active);
if (NM_IS_VPN_CONNECTION (active))
device = nm_vpn_connection_get_parent_device (NM_VPN_CONNECTION (active));
/* Loop through devices waiting for secondary connections to activate */
for (iter = priv->pending_secondaries; iter; iter = g_slist_next (iter)) {
PendingSecondaryData *secondary_data = (PendingSecondaryData *) iter->data;
NMDevice *item_device = secondary_data->device;
if (!device || item_device == device) {
for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) {
char *list_ac_path = (char *) iter2->data;
/* Look for 'active' in each device's secondary connections list */
for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) {
NMActiveConnection *secondary_active = NM_ACTIVE_CONNECTION (iter2->data);
if (g_strcmp0 (ac_path, list_ac_path) == 0) {
if (connected) {
/* Secondary connection activated */
secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, list_ac_path);
g_free (list_ac_path);
if (!secondary_data->secondaries) {
/* None secondary UUID remained -> remove the secondary data item */
priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
pending_secondary_data_free (secondary_data);
nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
return;
}
} else {
/* Secondary connection failed -> do not watch other connections */
priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
pending_secondary_data_free (secondary_data);
nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED);
return;
}
if (active != secondary_active)
continue;
if (connected) {
nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' SUCCEEDED; active path '%s'",
nm_active_connection_get_name (active),
nm_active_connection_get_path (active));
/* Secondary connection activated */
secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active);
g_object_unref (secondary_active);
if (!secondary_data->secondaries) {
/* No secondary UUID remained -> remove the secondary data item */
priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
pending_secondary_data_free (secondary_data);
nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
break;
}
} else {
nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' FAILED; active path '%s'",
nm_active_connection_get_name (active),
nm_active_connection_get_path (active));
/* Secondary connection failed -> do not watch other connections */
priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
pending_secondary_data_free (secondary_data);
nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED);
break;
}
return;
}
}
}
@ -1233,6 +1232,7 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
ActivateData *data;
const GSList *active_connections, *iter;
if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP)
return;
@ -1246,6 +1246,15 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds
if (!nm_device_autoconnect_allowed (device))
return;
/* If the device already has an activation in-progress or waiting for
* authentication, don't start an auto-activation for it.
*/
active_connections = nm_manager_get_active_connections (priv->manager);
for (iter = active_connections; iter; iter = iter->next) {
if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device)
return;
}
/* Schedule an auto-activation if there isn't one already for this device */
if (find_pending_activation (priv->pending_activation_checks, device) == NULL) {
data = activate_data_new (policy, device, delay_seconds);
@ -1357,13 +1366,12 @@ activate_secondary_connections (NMPolicy *policy,
ac = nm_manager_activate_connection (priv->manager,
NM_CONNECTION (settings_con),
nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)),
nm_device_get_path (device),
nm_act_request_get_dbus_sender (req),
device,
nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)),
&error);
if (ac) {
secondary_ac_list = g_slist_append (secondary_ac_list,
g_strdup (nm_active_connection_get_path (ac)));
} else {
if (ac)
secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac));
else {
nm_log_warn (LOGD_DEVICE, "Secondary connection '%s' auto-activation failed: (%d) %s",
sec_uuid,
error ? error->code : 0,
@ -1384,7 +1392,7 @@ activate_secondary_connections (NMPolicy *policy,
secondary_data = pending_secondary_data_new (device, secondary_ac_list);
priv->pending_secondaries = g_slist_append (priv->pending_secondaries, secondary_data);
} else
g_slist_free_full (secondary_ac_list, g_free);
g_slist_free_full (secondary_ac_list, g_object_unref);
return success;
}
@ -1720,8 +1728,6 @@ vpn_connection_activated (NMPolicy *policy, NMVPNConnection *vpn)
update_routing_and_dns (policy, TRUE);
nm_dns_manager_end_updates (mgr, __func__);
process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), TRUE);
}
static void
@ -1737,7 +1743,7 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
nm_dns_manager_begin_updates (mgr, __func__);
ip_iface = nm_vpn_connection_get_ip_iface (vpn);
parent = nm_vpn_connection_get_parent_device (vpn);
parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
ip4_config = nm_vpn_connection_get_ip4_config (vpn);
if (ip4_config) {
@ -1754,8 +1760,23 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
update_routing_and_dns (policy, TRUE);
nm_dns_manager_end_updates (mgr, __func__);
}
process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), FALSE);
static void
vpn_connection_state_changed (NMVPNConnection *vpn,
NMVPNConnectionState new_state,
NMVPNConnectionState old_state,
NMVPNConnectionStateReason reason,
NMPolicy *policy)
{
if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED)
vpn_connection_activated (policy, vpn);
else if (new_state >= NM_VPN_CONNECTION_STATE_FAILED) {
/* Only clean up IP/DNS if the connection ever got past IP_CONFIG */
if (old_state >= NM_VPN_CONNECTION_STATE_IP_CONFIG_GET &&
old_state <= NM_VPN_CONNECTION_STATE_ACTIVATED)
vpn_connection_deactivated (policy, vpn);
}
}
static void
@ -1763,18 +1784,12 @@ active_connection_state_changed (NMActiveConnection *active,
GParamSpec *pspec,
NMPolicy *policy)
{
switch (nm_active_connection_get_state (active)) {
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
if (NM_IS_VPN_CONNECTION (active))
vpn_connection_activated (policy, NM_VPN_CONNECTION (active));
break;
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
if (NM_IS_VPN_CONNECTION (active))
vpn_connection_deactivated (policy, NM_VPN_CONNECTION (active));
break;
default:
break;
}
NMActiveConnectionState state = nm_active_connection_get_state (active);
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
process_secondaries (policy, active, TRUE);
else if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
process_secondaries (policy, active, FALSE);
}
static void
@ -1782,7 +1797,13 @@ active_connection_added (NMManager *manager,
NMActiveConnection *active,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
NMPolicy *policy = NM_POLICY (user_data);
if (NM_IS_VPN_CONNECTION (active)) {
g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
G_CALLBACK (vpn_connection_state_changed),
policy);
}
g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
G_CALLBACK (active_connection_state_changed),
@ -1794,9 +1815,14 @@ active_connection_removed (NMManager *manager,
NMActiveConnection *active,
gpointer user_data)
{
NMPolicy *policy = NM_POLICY (user_data);
g_signal_handlers_disconnect_by_func (active,
vpn_connection_state_changed,
policy);
g_signal_handlers_disconnect_by_func (active,
active_connection_state_changed,
(NMPolicy *) user_data);
policy);
}
/**************************************************************************/

View file

@ -206,6 +206,8 @@ agent_register_permissions_done (NMAuthChain *chain,
GHashTableIter iter;
Request *req;
g_assert (context);
priv->chains = g_slist_remove (priv->chains, chain);
if (error) {
@ -270,22 +272,20 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
DBusGMethodInvocation *context)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
char *sender = NULL;
NMAuthSubject *subject;
gulong sender_uid = G_MAXULONG;
GError *error = NULL, *local = NULL;
NMSecretAgent *agent;
NMAuthChain *chain;
const char *error_desc = NULL;
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
context,
&sender,
&sender_uid)) {
subject = nm_auth_subject_new_from_context (context);
if (!subject) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
"Unable to determine request sender and UID.");
goto done;
}
sender_uid = nm_auth_subject_get_uid (subject);
if ( 0 != sender_uid
&& !nm_session_monitor_uid_has_session (priv->session_monitor,
@ -311,7 +311,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
}
/* Success, add the new agent */
agent = nm_secret_agent_new (context, sender, identifier, sender_uid, capabilities);
agent = nm_secret_agent_new (context, subject, identifier, capabilities);
if (!agent) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR,
@ -323,7 +323,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
nm_secret_agent_get_description (agent));
/* Kick off permissions requests for this agent */
chain = nm_auth_chain_new (context, agent_register_permissions_done, self, &error_desc);
chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self);
if (chain) {
nm_auth_chain_set_data (chain, "agent", agent, g_object_unref);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
@ -333,7 +333,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
} else {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
error_desc);
"Unable to start agent authentication.");
}
done:
@ -341,7 +341,7 @@ done:
dbus_g_method_return_error (context, error);
g_clear_error (&error);
g_clear_error (&local);
g_free (sender);
g_clear_object (&subject);
}
static void
@ -363,6 +363,7 @@ impl_agent_manager_unregister (NMAgentManager *self,
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
context,
&sender,
NULL,
NULL)) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
@ -1016,10 +1017,10 @@ get_next_cb (Request *parent)
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY",
req, parent->detail, req->setting_name, agent_dbus_owner);
req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner,
nm_secret_agent_get_owner_uid (parent->current),
get_agent_modify_auth_cb,
req);
req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current),
NULL,
get_agent_modify_auth_cb,
req);
g_assert (req->chain);
/* If the caller is the only user in the connection's permissions, then
@ -1502,10 +1503,10 @@ authority_changed_cb (gpointer user_data)
NMAuthChain *chain;
/* Kick off permissions requests for this agent */
chain = nm_auth_chain_new_dbus_sender (nm_secret_agent_get_dbus_owner (agent),
nm_secret_agent_get_owner_uid (agent),
agent_permissions_changed_done,
self);
chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent),
NULL,
agent_permissions_changed_done,
self);
g_assert (chain);
priv->chains = g_slist_append (priv->chains, chain);

View file

@ -31,6 +31,7 @@
#include "nm-secret-agent.h"
#include "nm-dbus-manager.h"
#include "nm-dbus-glib-types.h"
#include "nm-glib-compat.h"
#include "nm-logging.h"
G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
@ -40,12 +41,9 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
NMSecretAgentPrivate))
typedef struct {
gboolean disposed;
char *description;
char *owner;
NMAuthSubject *subject;
char *identifier;
uid_t owner_uid;
char *owner_username;
NMSecretAgentCapabilities capabilities;
guint32 hash;
@ -106,10 +104,10 @@ nm_secret_agent_get_description (NMSecretAgent *agent)
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
if (!priv->description) {
priv->description = g_strdup_printf ("%s/%s/%u",
priv->owner,
priv->description = g_strdup_printf ("%s/%s/%lu",
nm_auth_subject_get_dbus_sender (priv->subject),
priv->identifier,
priv->owner_uid);
nm_auth_subject_get_uid (priv->subject));
}
return priv->description;
@ -120,7 +118,7 @@ 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)->owner;
return nm_auth_subject_get_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
const char *
@ -131,16 +129,16 @@ nm_secret_agent_get_identifier (NMSecretAgent *agent)
return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier;
}
uid_t
gulong
nm_secret_agent_get_owner_uid (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXUINT);
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid;
return nm_auth_subject_get_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
const char *
nm_secret_agent_get_owner_username(NMSecretAgent *agent)
nm_secret_agent_get_owner_username (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
@ -156,13 +154,21 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent)
}
guint32
nm_secret_agent_get_hash (NMSecretAgent *agent)
nm_secret_agent_get_hash (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash;
}
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.
@ -443,9 +449,8 @@ proxy_cleanup (NMSecretAgent *self)
NMSecretAgent *
nm_secret_agent_new (DBusGMethodInvocation *context,
const char *owner,
NMAuthSubject *subject,
const char *identifier,
uid_t owner_uid,
NMSecretAgentCapabilities capabilities)
{
NMSecretAgent *self;
@ -453,10 +458,11 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
char *hash_str, *username;
struct passwd *pw;
g_return_val_if_fail (owner != NULL, NULL);
g_return_val_if_fail (context != NULL, NULL);
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
g_return_val_if_fail (identifier != NULL, NULL);
pw = getpwuid (owner_uid);
pw = getpwuid (nm_auth_subject_get_uid (subject));
g_return_val_if_fail (pw != NULL, NULL);
g_return_val_if_fail (pw->pw_name[0] != '\0', NULL);
username = g_strdup (pw->pw_name);
@ -464,19 +470,18 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
priv->owner = g_strdup (owner);
priv->identifier = g_strdup (identifier);
priv->owner_uid = owner_uid;
priv->owner_username = g_strdup (username);
priv->capabilities = capabilities;
priv->subject = g_object_ref (subject);
hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier);
hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_uid (subject), identifier);
priv->hash = g_str_hash (hash_str);
g_free (hash_str);
priv->proxy = nm_dbus_manager_new_proxy (nm_dbus_manager_get (),
context,
owner,
nm_auth_subject_get_dbus_sender (subject),
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT);
g_assert (priv->proxy);
@ -501,21 +506,21 @@ dispose (GObject *object)
{
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
if (!priv->disposed) {
priv->disposed = TRUE;
g_clear_pointer (&priv->description, g_free);
g_clear_pointer (&priv->identifier, g_free);
g_clear_pointer (&priv->owner_username, g_free);
g_free (priv->description);
g_free (priv->owner);
g_free (priv->identifier);
g_free (priv->owner_username);
g_slist_free_full (priv->permissions, g_free);
g_slist_free_full (priv->permissions, g_free);
priv->permissions = NULL;
if (priv->requests) {
g_hash_table_destroy (priv->requests);
proxy_cleanup (NM_SECRET_AGENT (object));
priv->requests = NULL;
}
proxy_cleanup (NM_SECRET_AGENT (object));
g_clear_object (&priv->subject);
G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
}

View file

@ -29,6 +29,7 @@
#include <nm-connection.h>
#include "nm-dbus-manager.h"
#include "nm-settings-flags.h"
#include "nm-auth-subject.h"
/* NOTE: ensure these capabilities match those in introspection/nm-secret-agent.xml and
* libnm-glib/nm-secret-agent.h.
@ -56,9 +57,8 @@ typedef struct {
GType nm_secret_agent_get_type (void);
NMSecretAgent *nm_secret_agent_new (DBusGMethodInvocation *context,
const char *owner,
NMAuthSubject *subject,
const char *identifier,
uid_t owner_uid,
NMSecretAgentCapabilities capabilities);
const char *nm_secret_agent_get_description (NMSecretAgent *agent);
@ -67,7 +67,7 @@ const char *nm_secret_agent_get_dbus_owner (NMSecretAgent *agent);
const char *nm_secret_agent_get_identifier (NMSecretAgent *agent);
uid_t nm_secret_agent_get_owner_uid (NMSecretAgent *agent);
gulong nm_secret_agent_get_owner_uid (NMSecretAgent *agent);
const char *nm_secret_agent_get_owner_username (NMSecretAgent *agent);
@ -75,6 +75,8 @@ NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent
guint32 nm_secret_agent_get_hash (NMSecretAgent *agent);
NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent);
void nm_secret_agent_add_permission (NMSecretAgent *agent,
const char *permission,
gboolean allowed);

View file

@ -994,47 +994,35 @@ pk_auth_cb (NMAuthChain *chain,
nm_auth_chain_unref (chain);
}
static gboolean
check_user_in_acl (NMConnection *connection,
DBusGMethodInvocation *context,
NMSessionMonitor *session_monitor,
gulong *out_sender_uid,
GError **error)
/**
* _new_auth_subject:
* @context: the D-Bus method invocation context
* @error: on failure, a #GError
*
* Creates an NMAuthSubject for the caller.
*
* Returns: the #NMAuthSubject on success, or %NULL on failure and sets @error
*/
static NMAuthSubject *
_new_auth_subject (DBusGMethodInvocation *context, GError **error)
{
gulong sender_uid = G_MAXULONG;
char *error_desc = NULL;
NMAuthSubject *subject;
g_return_val_if_fail (connection != NULL, FALSE);
g_return_val_if_fail (context != NULL, FALSE);
g_return_val_if_fail (session_monitor != NULL, FALSE);
/* Get the caller's UID */
if (!nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, NULL, &sender_uid)) {
subject = nm_auth_subject_new_from_context (context);
if (!subject) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine UID of request.");
return FALSE;
}
/* Make sure the UID can view this connection */
if (!nm_auth_uid_in_acl (connection, session_monitor, sender_uid, &error_desc)) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
return FALSE;
}
if (out_sender_uid)
*out_sender_uid = sender_uid;
return TRUE;
return subject;
}
static void
auth_start (NMSettingsConnection *self,
DBusGMethodInvocation *context,
NMAuthSubject *subject,
const char *check_permission,
AuthCallback callback,
gpointer callback_data)
@ -1043,41 +1031,49 @@ auth_start (NMSettingsConnection *self,
NMAuthChain *chain;
gulong sender_uid = G_MAXULONG;
GError *error = NULL;
const char *error_desc = NULL;
char *error_desc = NULL;
g_return_if_fail (context != NULL);
g_return_if_fail (NM_IS_AUTH_SUBJECT (subject));
/* Ensure the caller can view this connection */
if (!nm_auth_uid_in_acl (NM_CONNECTION (self),
priv->session_monitor,
nm_auth_subject_get_uid (subject),
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
if (!check_user_in_acl (NM_CONNECTION (self),
context,
priv->session_monitor,
&sender_uid,
&error)) {
callback (self, context, G_MAXULONG, error, callback_data);
g_clear_error (&error);
return;
}
if (check_permission) {
chain = nm_auth_chain_new (context, pk_auth_cb, self, &error_desc);
if (chain) {
priv->pending_auths = g_slist_append (priv->pending_auths, chain);
nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid);
nm_auth_chain_add_call (chain, check_permission, TRUE);
} else {
g_set_error_literal (&error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
callback (self, context, G_MAXULONG, error, callback_data);
g_clear_error (&error);
}
} else {
if (!check_permission) {
/* Don't need polkit auth, automatic success */
callback (self, context, sender_uid, NULL, callback_data);
callback (self, context, nm_auth_subject_get_uid (subject), NULL, callback_data);
return;
}
chain = nm_auth_chain_new_subject (subject, context, pk_auth_cb, self);
if (!chain) {
g_set_error_literal (&error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to authenticate the request.");
callback (self, context, G_MAXULONG, error, callback_data);
g_clear_error (&error);
return;
}
priv->pending_auths = g_slist_append (priv->pending_auths, chain);
nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid);
nm_auth_chain_add_call (chain, check_permission, TRUE);
}
/**** DBus method handlers ************************************/
@ -1184,7 +1180,17 @@ static void
impl_settings_connection_get_settings (NMSettingsConnection *self,
DBusGMethodInvocation *context)
{
auth_start (self, context, NULL, get_settings_auth_cb, NULL);
NMAuthSubject *subject;
GError *error = NULL;
subject = _new_auth_subject (context, &error);
if (subject) {
auth_start (self, context, subject, NULL, get_settings_auth_cb, NULL);
g_object_unref (subject);
} else {
dbus_g_method_return_error (context, error);
g_error_free (error);
}
}
typedef struct {
@ -1307,10 +1313,12 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
gboolean save_to_disk)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
NMAuthSubject *subject = NULL;
NMConnection *tmp = NULL;
GError *error = NULL;
UpdateInfo *info;
const char *permission;
char *error_desc = NULL;
g_assert (new_settings != NULL || save_to_disk == TRUE);
@ -1318,36 +1326,35 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
* 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;
}
if (!check_writable (NM_CONNECTION (self), &error))
goto error;
/* Check if the settings are valid first */
if (new_settings) {
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;
goto error;
}
}
subject = _new_auth_subject (context, &error);
if (!subject)
goto error;
/* And that the new connection settings will be visible to the user
* that's sending the update request. You can't make a connection
* invisible to yourself.
*/
if (!check_user_in_acl (tmp ? tmp : NM_CONNECTION (self),
context,
priv->session_monitor,
NULL,
&error)) {
dbus_g_method_return_error (context, error);
g_clear_error (&error);
g_object_unref (tmp);
return;
if (!nm_auth_uid_in_acl (tmp ? tmp : NM_CONNECTION (self),
priv->session_monitor,
nm_auth_subject_get_uid (subject),
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
goto error;
}
info = g_malloc0 (sizeof (*info));
@ -1359,7 +1366,16 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
permission = get_update_modify_permission (NM_CONNECTION (self),
tmp ? tmp : NM_CONNECTION (self));
auth_start (self, context, permission, update_auth_cb, info);
auth_start (self, context, subject, permission, update_auth_cb, info);
g_object_unref (subject);
return;
error:
g_clear_object (&tmp);
g_clear_object (&subject);
dbus_g_method_return_error (context, error);
g_clear_error (&error);
}
static void
@ -1440,6 +1456,7 @@ static void
impl_settings_connection_delete (NMSettingsConnection *self,
DBusGMethodInvocation *context)
{
NMAuthSubject *subject;
GError *error = NULL;
if (!check_writable (NM_CONNECTION (self), &error)) {
@ -1448,7 +1465,14 @@ impl_settings_connection_delete (NMSettingsConnection *self,
return;
}
auth_start (self, context, get_modify_permission_basic (self), delete_auth_cb, NULL);
subject = _new_auth_subject (context, &error);
if (subject) {
auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL);
g_object_unref (subject);
} else {
dbus_g_method_return_error (context, error);
g_error_free (error);
}
}
/**************************************************************/
@ -1524,11 +1548,22 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self,
const gchar *setting_name,
DBusGMethodInvocation *context)
{
auth_start (self,
context,
get_modify_permission_basic (self),
dbus_secrets_auth_cb,
g_strdup (setting_name));
NMAuthSubject *subject;
GError *error = NULL;
subject = _new_auth_subject (context, &error);
if (subject) {
auth_start (self,
context,
subject,
get_modify_permission_basic (self),
dbus_secrets_auth_cb,
g_strdup (setting_name));
g_object_unref (subject);
} else {
dbus_g_method_return_error (context, error);
g_error_free (error);
}
}
/**************************************************************/

View file

@ -1013,6 +1013,8 @@ pk_add_cb (NMAuthChain *chain,
const char *perm;
gboolean save_to_disk;
g_assert (context);
priv->auths = g_slist_remove (priv->auths, chain);
perm = nm_auth_chain_get_data (chain, "perm");
@ -1092,13 +1094,15 @@ nm_settings_add_connection_dbus (NMSettings *self,
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMSettingConnection *s_con;
NMAuthSubject *subject = NULL;
NMAuthChain *chain;
GError *error = NULL, *tmp_error = NULL;
gulong caller_uid = G_MAXULONG;
char *error_desc = NULL;
const char *auth_error_desc = NULL;
const char *perm;
g_return_if_fail (connection != NULL);
g_return_if_fail (context != NULL);
/* Connection must be valid, of course */
if (!nm_connection_verify (connection, &tmp_error)) {
error = g_error_new (NM_SETTINGS_ERROR,
@ -1106,9 +1110,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
"The connection was invalid: %s",
tmp_error ? tmp_error->message : "(unknown)");
g_error_free (tmp_error);
callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
goto done;
}
/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
@ -1119,9 +1121,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"WPA Ad-Hoc disabled due to kernel bugs");
callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
goto done;
}
/* Do any of the plugins support adding? */
@ -1129,32 +1129,29 @@ nm_settings_add_connection_dbus (NMSettings *self,
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED,
"None of the registered plugins support add.");
callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
goto done;
}
/* Get the caller's UID */
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) {
subject = nm_auth_subject_new_from_context (context);
if (!subject) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine request UID.");
callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
"Unable to determine UID of request.");
goto done;
}
/* Ensure the caller's username exists in the connection's permissions,
* or that the permissions is empty (ie, visible by everyone).
*/
if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) {
if (!nm_auth_uid_in_acl (connection,
priv->session_monitor,
nm_auth_subject_get_uid (subject),
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
callback (self, NULL, error, context, user_data);
g_error_free (error);
return;
goto done;
}
/* If the caller is the only user in the connection's permissions, then
@ -1169,23 +1166,29 @@ nm_settings_add_connection_dbus (NMSettings *self,
perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
/* Validate the user request */
chain = nm_auth_chain_new (context, pk_add_cb, self, &auth_error_desc);
if (chain) {
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, perm, TRUE);
nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL);
nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
nm_auth_chain_set_data_ulong (chain, "caller-uid", caller_uid);
nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL);
} else {
chain = nm_auth_chain_new_subject (subject, context, pk_add_cb, self);
if (!chain) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
auth_error_desc);
callback (self, NULL, error, context, user_data);
g_error_free (error);
"Unable to authenticate the request.");
goto done;
}
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, perm, TRUE);
nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL);
nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
nm_auth_chain_set_data_ulong (chain, "caller-uid", nm_auth_subject_get_uid (subject));
nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL);
done:
if (error)
callback (self, NULL, error, context, user_data);
g_clear_error (&error);
g_clear_object (&subject);
}
static void
@ -1251,7 +1254,7 @@ impl_settings_reload_connections (NMSettings *self,
gulong caller_uid;
GError *error = NULL;
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) {
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine request UID.");
@ -1294,6 +1297,8 @@ pk_hostname_cb (NMAuthChain *chain,
GSList *iter;
const char *hostname;
g_assert (context);
priv->auths = g_slist_remove (priv->auths, chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
@ -1344,30 +1349,31 @@ impl_settings_save_hostname (NMSettings *self,
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthChain *chain;
GError *error = NULL;
const char *error_desc = NULL;
/* Do any of the plugins support setting the hostname? */
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED,
"None of the registered plugins support setting the hostname.");
} else {
chain = nm_auth_chain_new (context, pk_hostname_cb, self, &error_desc);
if (chain) {
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
} else {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
}
goto done;
}
if (error) {
dbus_g_method_return_error (context, error);
g_error_free (error);
chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
if (!chain) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to authenticate the request.");
goto done;
}
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
done:
if (error)
dbus_g_method_return_error (context, error);
g_clear_error (&error);
}
static gboolean

View file

@ -71,9 +71,6 @@ typedef struct {
SecretsReq secrets_idx;
char *username;
NMDevice *parent_dev;
gulong device_monitor;
NMVPNConnectionState vpn_state;
NMVPNConnectionStateReason failure_reason;
DBusGProxy *proxy;
@ -163,7 +160,7 @@ call_plugin_disconnect (NMVPNConnection *self)
}
static void
vpn_cleanup (NMVPNConnection *connection)
vpn_cleanup (NMVPNConnection *connection, NMDevice *parent_dev)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
@ -173,8 +170,8 @@ vpn_cleanup (NMVPNConnection *connection)
nm_platform_address_flush (priv->ip_ifindex);
}
nm_device_set_vpn4_config (priv->parent_dev, NULL);
nm_device_set_vpn6_config (priv->parent_dev, NULL);
nm_device_set_vpn4_config (parent_dev, NULL);
nm_device_set_vpn6_config (parent_dev, NULL);
g_free (priv->banner);
priv->banner = NULL;
@ -197,6 +194,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
{
NMVPNConnectionPrivate *priv;
NMVPNConnectionState old_vpn_state;
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
@ -242,7 +240,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Let dispatcher scripts know we're up and running */
nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP,
priv->connection,
priv->parent_dev,
parent_dev,
priv->ip_iface,
priv->ip4_config,
priv->ip6_config,
@ -255,7 +253,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Let dispatcher scripts know we're about to go down */
nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN,
priv->connection,
priv->parent_dev,
parent_dev,
priv->ip_iface,
NULL,
NULL,
@ -265,7 +263,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Tear down and clean up the connection */
call_plugin_disconnect (connection);
vpn_cleanup (connection);
vpn_cleanup (connection, parent_dev);
/* Fall through */
default:
priv->secrets_idx = SECRETS_REQ_SYSTEM;
@ -276,25 +274,33 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
}
static void
device_state_changed (NMDevice *device,
device_state_changed (NMActiveConnection *active,
NMDevice *device,
NMDeviceState new_state,
NMDeviceState old_state,
NMDeviceStateReason reason,
gpointer user_data)
NMDeviceState old_state)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
nm_vpn_connection_set_vpn_state (connection,
nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active),
NM_VPN_CONNECTION_STATE_DISCONNECTED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
} else if (new_state == NM_DEVICE_STATE_FAILED) {
nm_vpn_connection_set_vpn_state (connection,
nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active),
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
}
}
static void
master_failed (NMActiveConnection *self)
{
NMVPNConnection *connection = NM_VPN_CONNECTION (self);
/* Master failure fails the VPN */
nm_vpn_connection_set_vpn_state (connection,
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
}
static void
add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw)
{
@ -400,26 +406,18 @@ NMVPNConnection *
nm_vpn_connection_new (NMConnection *connection,
NMDevice *parent_device,
const char *specific_object,
gboolean user_requested,
gulong user_uid)
NMAuthSubject *subject)
{
NMVPNConnection *self;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
return (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device,
NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested,
NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_VPN, TRUE,
NULL);
if (self)
nm_active_connection_export (NM_ACTIVE_CONNECTION (self));
return self;
}
static const char *
@ -652,6 +650,7 @@ static gboolean
nm_vpn_connection_apply_config (NMVPNConnection *connection)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
nm_platform_link_set_up (priv->ip_ifindex);
@ -668,9 +667,9 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection)
/* Add any explicit route to the VPN gateway through the parent device */
if (priv->ip4_external_gw)
add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_external_gw);
add_ip4_vpn_gateway_route (parent_dev, priv->ip4_external_gw);
if (priv->ip6_external_gw)
add_ip6_vpn_gateway_route (priv->parent_dev, priv->ip6_external_gw);
add_ip6_vpn_gateway_route (parent_dev, priv->ip6_external_gw);
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
nm_connection_get_id (priv->connection));
@ -1397,14 +1396,6 @@ nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection)
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex;
}
NMDevice *
nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
{
g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
}
guint32
nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
{
@ -1674,23 +1665,12 @@ nm_vpn_connection_init (NMVPNConnection *self)
static void
constructed (GObject *object)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
NMConnection *connection;
NMDevice *device;
G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object);
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
priv->connection = g_object_ref (connection);
device = (NMDevice *) nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
g_assert (device);
priv->parent_dev = g_object_ref (device);
priv->device_monitor = g_signal_connect (device, "state-changed",
G_CALLBACK (device_state_changed),
object);
NM_VPN_CONNECTION_GET_PRIVATE (object)->connection = g_object_ref (connection);
}
static void
@ -1712,11 +1692,6 @@ dispose (GObject *object)
if (priv->ip6_external_gw)
g_free (priv->ip6_external_gw);
if (priv->device_monitor)
g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor);
g_clear_object (&priv->parent_dev);
if (priv->ip4_config)
g_object_unref (priv->ip4_config);
if (priv->ip6_config)
@ -1755,6 +1730,7 @@ get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
NMDevice *parent_dev;
switch (prop_id) {
case PROP_VPN_STATE:
@ -1764,7 +1740,8 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, priv->banner ? priv->banner : "");
break;
case PROP_MASTER:
g_value_set_boxed (value, nm_device_get_path (priv->parent_dev));
parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
g_value_set_boxed (value, parent_dev ? nm_device_get_path (parent_dev) : "/");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -1776,6 +1753,7 @@ static void
nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (connection_class);
g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate));
@ -1784,6 +1762,8 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
active_class->master_failed = master_failed;
active_class->device_state_changed = device_state_changed;
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);

View file

@ -26,6 +26,7 @@
#include <glib-object.h>
#include "NetworkManagerVPN.h"
#include "nm-device.h"
#include "nm-auth-subject.h"
#define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ())
#define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnection))
@ -67,8 +68,7 @@ GType nm_vpn_connection_get_type (void);
NMVPNConnection * nm_vpn_connection_new (NMConnection *connection,
NMDevice *parent_device,
const char *specific_object,
gboolean user_requested,
gulong user_uid);
NMAuthSubject *subject);
void nm_vpn_connection_activate (NMVPNConnection *connection);
NMConnection * nm_vpn_connection_get_connection (NMVPNConnection *connection);
@ -82,7 +82,6 @@ NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connect
NMIP6Config * nm_vpn_connection_get_ip6_config (NMVPNConnection *connection);
const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection);
int nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection);
NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);
struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection);

View file

@ -78,7 +78,7 @@ get_service_by_namefile (NMVPNManager *self, const char *namefile)
}
static NMVPNConnection *
find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *connection)
find_active_vpn_connection (NMVPNManager *self, NMConnection *connection)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
@ -104,66 +104,53 @@ find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *conn
return found;
}
NMActiveConnection *
gboolean
nm_vpn_manager_activate_connection (NMVPNManager *manager,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
NMVPNConnection *vpn,
GError **error)
{
NMSettingVPN *vpn_setting;
NMVPNConnection *existing = NULL;
NMConnection *connection;
NMSettingVPN *s_vpn;
NMVPNService *service;
NMVPNConnection *vpn = NULL;
const char *service_name;
NMDevice *device;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
g_return_val_if_fail (error != NULL, NULL);
g_return_val_if_fail (*error == NULL, NULL);
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE);
g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, FALSE);
device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
g_assert (device);
if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state (device) != NM_DEVICE_STATE_SECONDARIES) {
g_set_error (error,
NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE,
"%s", "The base device for the VPN connection was not active.");
return NULL;
g_set_error_literal (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE,
"The base device for the VPN connection was not active.");
return FALSE;
}
vpn_setting = nm_connection_get_setting_vpn (connection);
if (!vpn_setting) {
g_set_error (error,
NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_CONNECTION_INVALID,
"%s", "The connection was not a VPN connection.");
return NULL;
}
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn));
g_assert (connection);
s_vpn = nm_connection_get_setting_vpn (connection);
g_assert (s_vpn);
vpn = find_active_vpn_connection_by_connection (manager, connection);
if (vpn) {
nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
vpn = NULL;
}
service_name = nm_setting_vpn_get_service_type (vpn_setting);
service_name = nm_setting_vpn_get_service_type (s_vpn);
g_assert (service_name);
service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name);
if (!service) {
g_set_error (error,
NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
g_set_error (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
"The VPN service '%s' was not installed.",
service_name);
return NULL;
return FALSE;
}
return (NMActiveConnection *) nm_vpn_service_activate (service,
connection,
device,
specific_object,
user_requested,
user_uid,
error);
existing = find_active_vpn_connection (manager,
nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn)));
if (existing)
nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
return nm_vpn_service_activate (service, vpn, error);
}
gboolean

View file

@ -59,13 +59,9 @@ GType nm_vpn_manager_get_type (void);
NMVPNManager *nm_vpn_manager_get (void);
NMActiveConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
GError **error);
gboolean nm_vpn_manager_activate_connection (NMVPNManager *manager,
NMVPNConnection *vpn,
GError **error);
gboolean nm_vpn_manager_deactivate_connection (NMVPNManager *manager,
NMVPNConnection *connection,

View file

@ -323,45 +323,37 @@ connection_vpn_state_changed (NMVPNConnection *connection,
}
}
NMVPNConnection *
gboolean
nm_vpn_service_activate (NMVPNService *service,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
NMVPNConnection *vpn,
GError **error)
{
NMVPNConnection *vpn;
NMVPNServicePrivate *priv;
g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
g_return_val_if_fail (error != NULL, NULL);
g_return_val_if_fail (*error == NULL, NULL);
g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE);
g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, FALSE);
priv = NM_VPN_SERVICE_GET_PRIVATE (service);
clear_quit_timeout (service);
vpn = nm_vpn_connection_new (connection, device, specific_object, user_requested, user_uid);
g_signal_connect (vpn, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
G_CALLBACK (connection_vpn_state_changed),
service);
priv->connections = g_slist_prepend (priv->connections, g_object_ref (vpn));
if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service)) {
// FIXME: fill in error when errors happen
if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service))
nm_vpn_connection_activate (vpn);
} else if (priv->start_timeout == 0) {
else if (priv->start_timeout == 0) {
nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name);
if (!nm_vpn_service_daemon_exec (service, error))
vpn = NULL;
return FALSE;
}
return vpn;
return TRUE;
}
const GSList *

View file

@ -54,13 +54,9 @@ const char *nm_vpn_service_get_dbus_service (NMVPNService *service);
/* Returns the path of the VPN service's .name file */
const char *nm_vpn_service_get_name_file (NMVPNService *service);
NMVPNConnection * nm_vpn_service_activate (NMVPNService *service,
NMConnection *connection,
NMDevice *device,
const char *specific_object,
gboolean user_requested,
gulong user_uid,
GError **error);
gboolean nm_vpn_service_activate (NMVPNService *service,
NMVPNConnection *vpn,
GError **error);
const GSList *nm_vpn_service_get_active_connections (NMVPNService *service);