core: PolicyKit protect Deactivate and Disconnect

This commit is contained in:
Dan Williams 2010-06-04 00:42:10 -07:00
parent 25e758c770
commit ae4b47ca99
8 changed files with 437 additions and 34 deletions

View file

@ -65,10 +65,11 @@
</property>
<method name="Disconnect">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<tp:docstring>
Disconnects a device and prevents the device from automatically activating further connections without user intervention.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/>
</method>
<signal name="StateChanged">

View file

@ -31,16 +31,19 @@ object. dbus-glib generates the same bound function names for D-Bus the methods
<method name="DeactivateConnection">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_deactivate_connection"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="active_connection" type="o" direction="in"/>
</method>
<method name="Sleep">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_sleep"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="sleep" type="b" direction="in"/>
</method>
<method name="Enable">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enable"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="enable" type="b" direction="in"/>
</method>

View file

@ -77,6 +77,7 @@
Deactivate an active connection.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_deactivate_connection"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="active_connection" type="o" direction="in">
<tp:docstring>
The currently active connection to deactivate.

View file

@ -19,6 +19,8 @@
* Copyright (C) 2007 - 2010 Red Hat, Inc.
*/
#include <dbus/dbus-glib.h>
#include "nm-marshal.h"
#include "nm-setting-connection.h"
#include "nm-device-interface.h"
@ -26,8 +28,8 @@
#include "nm-properties-changed-signal.h"
#include "nm-rfkill.h"
static gboolean impl_device_disconnect (NMDeviceInterface *device,
GError **error);
static void impl_device_disconnect (NMDeviceInterface *device,
DBusGMethodInvocation *context);
#include "nm-device-interface-glue.h"
@ -211,6 +213,13 @@ nm_device_interface_init (gpointer g_iface)
G_TYPE_NONE, 3,
G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
g_signal_new (NM_DEVICE_INTERFACE_DISCONNECT_REQUEST,
iface_type,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
dbus_g_object_type_install_info (iface_type,
&dbus_glib_nm_device_interface_object_info);
@ -334,11 +343,11 @@ nm_device_interface_disconnect (NMDeviceInterface *device,
return success;
}
static gboolean
static void
impl_device_disconnect (NMDeviceInterface *device,
GError **error)
DBusGMethodInvocation *context)
{
return nm_device_interface_disconnect (device, error);
g_signal_emit_by_name (device, NM_DEVICE_INTERFACE_DISCONNECT_REQUEST, context);
}
void

View file

@ -45,6 +45,8 @@ typedef enum
#define NM_DEVICE_INTERFACE_ERROR (nm_device_interface_error_quark ())
#define NM_TYPE_DEVICE_INTERFACE_ERROR (nm_device_interface_error_get_type ())
#define NM_DEVICE_INTERFACE_DISCONNECT_REQUEST "disconnect-request"
#define NM_DEVICE_INTERFACE_UDI "udi"
#define NM_DEVICE_INTERFACE_IFACE "interface"
#define NM_DEVICE_INTERFACE_DRIVER "driver"

View file

@ -67,9 +67,9 @@ static void impl_manager_activate_connection (NMManager *manager,
const char *specific_object_path,
DBusGMethodInvocation *context);
static gboolean impl_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
GError **error);
static void impl_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
DBusGMethodInvocation *context);
static void impl_manager_sleep (NMManager *manager,
gboolean do_sleep,
@ -714,6 +714,41 @@ out:
nm_auth_chain_unref (chain);
}
static gboolean
check_user_authorized (NMDBusManager *dbus_mgr,
DBusGProxy *user_proxy,
DBusGMethodInvocation *context,
NMConnectionScope scope,
gulong *out_sender_uid,
const char **out_error_desc)
{
g_return_val_if_fail (dbus_mgr != NULL, FALSE);
g_return_val_if_fail (user_proxy != NULL, FALSE);
g_return_val_if_fail (context != NULL, FALSE);
g_return_val_if_fail (out_sender_uid != NULL, FALSE);
g_return_val_if_fail (out_error_desc != NULL, FALSE);
*out_sender_uid = G_MAXULONG;
/* Get the UID */
if (!nm_auth_get_caller_uid (context, dbus_mgr, out_sender_uid, out_error_desc))
return FALSE;
/* root gets to do anything */
if (0 == *out_sender_uid)
return TRUE;
/* Check whether the UID is authorized for user connections */
if ( scope == NM_CONNECTION_SCOPE_USER
&& !nm_auth_uid_authorized (*out_sender_uid,
dbus_mgr,
user_proxy,
out_error_desc))
return FALSE;
return TRUE;
}
static void
pending_activation_check_authorized (PendingActivation *pending,
NMDBusManager *dbus_mgr,
@ -727,8 +762,12 @@ pending_activation_check_authorized (PendingActivation *pending,
g_return_if_fail (dbus_mgr != NULL);
g_return_if_fail (user_proxy != NULL);
/* Get the UID */
if (!nm_auth_get_caller_uid (pending->context, dbus_mgr, &sender_uid, &error_desc)) {
if (!check_user_authorized (dbus_mgr,
user_proxy,
pending->context,
pending->scope,
&sender_uid,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
@ -737,26 +776,12 @@ pending_activation_check_authorized (PendingActivation *pending,
return;
}
/* root gets to do anything */
/* Yay for root */
if (0 == sender_uid) {
pending->callback (pending, NULL);
return;
}
/* Check whether the UID is authorized for user connections */
if ( pending->scope == NM_CONNECTION_SCOPE_USER
&& !nm_auth_uid_authorized (sender_uid,
dbus_mgr,
user_proxy,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
pending->callback (pending, error);
g_error_free (error);
return;
}
/* First check if the user is allowed to use networking at all, giving
* the user a chance to authenticate to gain the permission.
*/
@ -765,6 +790,7 @@ pending_activation_check_authorized (PendingActivation *pending,
NULL,
pending_auth_net_done,
pending);
g_assert (pending->chain);
nm_auth_chain_add_call (pending->chain,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE);
@ -1805,6 +1831,175 @@ manager_modem_enabled_changed (NMModem *device, gpointer user_data)
nm_manager_rfkill_update (NM_MANAGER (user_data), RFKILL_TYPE_WWAN);
}
static GError *
deactivate_disconnect_check_error (GError *auth_error,
NMAuthCallResult result,
const char *detail)
{
if (auth_error) {
nm_log_dbg (LOGD_CORE, "%s request failed: %s", detail, auth_error->message);
return g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"%s request failed: %s",
detail, auth_error->message);
} else if (result != NM_AUTH_CALL_RESULT_YES) {
return g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Not authorized to %s user connections",
detail);
}
return NULL;
}
static void
disconnect_user_auth_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *ret_error = NULL;
NMAuthCallResult result;
NMDevice *device;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
ret_error = deactivate_disconnect_check_error (error, result, "Disconnect");
g_message ("%s: here! ret error %p", __func__, ret_error);
if (!ret_error) {
/* Everything authorized, deactivate the connection */
device = nm_auth_chain_get_data (chain, "device");
g_message ("%s: here! device %p", __func__, device);
if (nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error))
dbus_g_method_return (context);
}
if (ret_error)
dbus_g_method_return_error (context, ret_error);
g_clear_error (&ret_error);
nm_auth_chain_unref (chain);
}
static void
disconnect_net_auth_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *ret_error = NULL;
NMAuthCallResult result;
NMConnectionScope scope;
NMDevice *device;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
ret_error = deactivate_disconnect_check_error (error, result, "Disconnect");
g_message ("%s: here! ret error %p", __func__, ret_error);
if (ret_error) {
dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error);
goto done;
}
/* If it's a system connection, we're done */
device = nm_auth_chain_get_data (chain, "device");
scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope"));
if (scope == NM_CONNECTION_SCOPE_USER) {
NMAuthChain *user_chain;
/* It's a user connection, so we need to ensure the caller is
* authorized to manipulate user connections.
*/
user_chain = nm_auth_chain_new (priv->authority, context, NULL, disconnect_user_auth_done_cb, self);
g_assert (user_chain);
priv->auth_chains = g_slist_append (priv->auth_chains, user_chain);
nm_auth_chain_set_data (user_chain, "device", g_object_ref (device), g_object_unref);
nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL);
nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE);
} else {
if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error)) {
dbus_g_method_return_error (context, ret_error);
g_clear_error (&ret_error);
} else
dbus_g_method_return (context);
}
done:
nm_auth_chain_unref (chain);
}
static void
manager_device_disconnect_request (NMDevice *device,
DBusGMethodInvocation *context,
NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMActRequest *req;
NMConnection *connection;
GError *error = NULL;
NMConnectionScope scope;
gulong sender_uid = G_MAXULONG;
const char *error_desc = NULL;
req = nm_device_get_act_request (device);
if (!req) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
"This device is not active");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
connection = nm_act_request_get_connection (req);
g_assert (connection);
/* Need to check the caller's permissions and stuff before we can
* deactivate the connection.
*/
scope = nm_connection_get_scope (connection);
if (!check_user_authorized (priv->dbus_mgr,
priv->user_proxy,
context,
scope,
&sender_uid,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
/* Yay for root */
if (0 == sender_uid) {
if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &error)) {
dbus_g_method_return_error (context, error);
g_clear_error (&error);
} else
dbus_g_method_return (context);
} else {
NMAuthChain *chain;
/* Otherwise validate the user request */
chain = nm_auth_chain_new (priv->authority, context, NULL, disconnect_net_auth_done_cb, self);
g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
}
}
static void
add_device (NMManager *self, NMDevice *device)
{
@ -1832,6 +2027,10 @@ add_device (NMManager *self, NMDevice *device)
G_CALLBACK (manager_device_state_changed),
self);
g_signal_connect (device, NM_DEVICE_INTERFACE_DISCONNECT_REQUEST,
G_CALLBACK (manager_device_disconnect_request),
self);
if (NM_IS_DEVICE_WIFI (device)) {
/* Attach to the access-point-added signal so that the manager can fill
* non-SSID-broadcasting APs with an SSID.
@ -2895,15 +3094,173 @@ done:
return success;
}
static gboolean
impl_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
GError **error)
static void
deactivate_user_auth_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
return nm_manager_deactivate_connection (manager,
connection_path,
NM_DEVICE_STATE_REASON_USER_REQUESTED,
error);
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *ret_error = NULL;
NMAuthCallResult result;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
ret_error = deactivate_disconnect_check_error (error, result, "Deactivate");
if (!ret_error) {
/* Everything authorized, deactivate the connection */
if (nm_manager_deactivate_connection (self,
nm_auth_chain_get_data (chain, "path"),
NM_DEVICE_STATE_REASON_USER_REQUESTED,
&ret_error))
dbus_g_method_return (context);
}
if (ret_error)
dbus_g_method_return_error (context, ret_error);
g_clear_error (&ret_error);
nm_auth_chain_unref (chain);
}
static void
deactivate_net_auth_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *ret_error = NULL;
NMAuthCallResult result;
const char *active_path;
NMConnectionScope scope;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
ret_error = deactivate_disconnect_check_error (error, result, "Deactivate");
if (ret_error) {
dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error);
goto done;
}
/* If it's a system connection, we're done */
active_path = nm_auth_chain_get_data (chain, "path");
scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope"));
if (scope == NM_CONNECTION_SCOPE_USER) {
NMAuthChain *user_chain;
/* It's a user connection, so we need to ensure the caller is
* authorized to manipulate user connections.
*/
user_chain = nm_auth_chain_new (priv->authority, context, NULL, deactivate_user_auth_done_cb, self);
g_assert (user_chain);
priv->auth_chains = g_slist_append (priv->auth_chains, user_chain);
nm_auth_chain_set_data (user_chain, "path", g_strdup (active_path), g_free);
nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL);
nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE);
} else {
if (!nm_manager_deactivate_connection (self,
active_path,
NM_DEVICE_STATE_REASON_USER_REQUESTED,
&ret_error)) {
dbus_g_method_return_error (context, ret_error);
g_clear_error (&ret_error);
} else
dbus_g_method_return (context);
}
done:
nm_auth_chain_unref (chain);
}
static void
impl_manager_deactivate_connection (NMManager *self,
const char *active_path,
DBusGMethodInvocation *context)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMConnection *connection = NULL;
GError *error = NULL;
GSList *iter;
NMAuthChain *chain;
gulong sender_uid = G_MAXULONG;
NMConnectionScope scope;
const char *error_desc = NULL;
/* Check for device connections first */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMActRequest *req;
const char *req_path = NULL;
req = nm_device_get_act_request (NM_DEVICE (iter->data));
if (req)
req_path = nm_act_request_get_active_connection_path (req);
if (req_path && !strcmp (active_path, req_path)) {
connection = nm_act_request_get_connection (req);
break;
}
}
/* Maybe it's a VPN */
if (!connection)
connection = nm_vpn_manager_get_connection_for_active (priv->vpn_manager, active_path);
if (!connection) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
"The connection was not active.");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
/* Need to check the caller's permissions and stuff before we can
* deactivate the connection.
*/
scope = nm_connection_get_scope (connection);
if (!check_user_authorized (priv->dbus_mgr,
priv->user_proxy,
context,
scope,
&sender_uid,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
/* Yay for root */
if (0 == sender_uid) {
if (!nm_manager_deactivate_connection (self,
active_path,
NM_DEVICE_STATE_REASON_USER_REQUESTED,
&error)) {
dbus_g_method_return_error (context, error);
g_clear_error (&error);
} else
dbus_g_method_return (context);
return;
}
/* Otherwise validate the user request */
chain = nm_auth_chain_new (priv->authority, context, NULL, deactivate_net_auth_done_cb, self);
g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free);
nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
}
static void

View file

@ -304,6 +304,33 @@ nm_vpn_manager_get_active_connections (NMVPNManager *manager)
return list;
}
NMConnection *
nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
const char *active_path)
{
NMVPNManagerPrivate *priv;
GSList *iter;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *active, *elt;
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
for (elt = active; elt; elt = g_slist_next (elt)) {
NMVPNConnection *candidate = NM_VPN_CONNECTION (elt->data);
const char *ac_path;
ac_path = nm_vpn_connection_get_active_connection_path (candidate);
if (ac_path && !strcmp (ac_path, active_path))
return nm_vpn_connection_get_connection (candidate);
}
}
return NULL;
}
NMVPNManager *
nm_vpn_manager_get (void)
{

View file

@ -83,4 +83,7 @@ void nm_vpn_manager_add_active_connections (NMVPNManager *manager,
GSList *nm_vpn_manager_get_active_connections (NMVPNManager *manager);
NMConnection *nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
const char *active_path);
#endif /* NM_VPN_VPN_MANAGER_H */