core: PolicyKit-protect enable/disable networking method

This commit is contained in:
Dan Williams
2010-05-29 23:00:46 -07:00
parent 716a9c6c0d
commit c013490ba3
4 changed files with 218 additions and 65 deletions

View File

@@ -101,6 +101,7 @@
<method name="Enable"> <method name="Enable">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enable"/> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enable"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<tp:docstring> <tp:docstring>
Control whether overall networking is enabled or disabled. When Control whether overall networking is enabled or disabled. When
disabled, all interfaces that NM manages are deactivated. When enabled, disabled, all interfaces that NM manages are deactivated. When enabled,

View File

@@ -28,6 +28,7 @@ struct NMAuthChain {
guint32 refcount; guint32 refcount;
PolkitAuthority *authority; PolkitAuthority *authority;
GSList *calls; GSList *calls;
GHashTable *data;
DBusGMethodInvocation *context; DBusGMethodInvocation *context;
GError *error; GError *error;
@@ -35,7 +36,6 @@ struct NMAuthChain {
NMAuthChainResultFunc done_func; NMAuthChainResultFunc done_func;
NMAuthChainCallFunc call_func; NMAuthChainCallFunc call_func;
gpointer user_data; gpointer user_data;
gpointer user_data2;
}; };
typedef struct { typedef struct {
@@ -45,28 +45,76 @@ typedef struct {
gboolean disposed; gboolean disposed;
} PolkitCall; } PolkitCall;
typedef struct {
gpointer data;
GDestroyNotify destroy;
} ChainData;
static void
free_data (gpointer data)
{
ChainData *tmp = data;
if (tmp->destroy)
tmp->destroy (tmp->data);
memset (tmp, 0, sizeof (ChainData));
g_free (tmp);
}
NMAuthChain * NMAuthChain *
nm_auth_chain_new (PolkitAuthority *authority, nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context, DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func, NMAuthChainResultFunc done_func,
NMAuthChainCallFunc call_func, NMAuthChainCallFunc call_func,
gpointer user_data, gpointer user_data)
gpointer user_data2)
{ {
NMAuthChain *self; NMAuthChain *self;
self = g_malloc0 (sizeof (NMAuthChain)); self = g_malloc0 (sizeof (NMAuthChain));
self->refcount = 1; self->refcount = 1;
self->authority = g_object_ref (authority); self->authority = g_object_ref (authority);
self->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_data);
self->done_func = done_func; self->done_func = done_func;
self->call_func = call_func; self->call_func = call_func;
self->context = context; self->context = context;
self->user_data = user_data; self->user_data = user_data;
self->user_data2 = user_data2;
return self; return self;
} }
gpointer
nm_auth_chain_get_data (NMAuthChain *self, const char *tag)
{
ChainData *tmp;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (tag != NULL, NULL);
tmp = g_hash_table_lookup (self->data, tag);
return tmp ? tmp->data : NULL;
}
void
nm_auth_chain_set_data (NMAuthChain *self,
const char *tag,
gpointer data,
GDestroyNotify data_destroy)
{
ChainData *tmp;
g_return_if_fail (self != NULL);
g_return_if_fail (tag != NULL);
if (data == NULL)
g_hash_table_remove (self->data, tag);
else {
tmp = g_malloc0 (sizeof (ChainData));
tmp->data = data;
tmp->destroy = data_destroy;
g_hash_table_insert (self->data, g_strdup (tag), tmp);
}
}
static void static void
nm_auth_chain_check_done (NMAuthChain *self) nm_auth_chain_check_done (NMAuthChain *self)
{ {
@@ -75,7 +123,7 @@ nm_auth_chain_check_done (NMAuthChain *self)
if (g_slist_length (self->calls) == 0) { if (g_slist_length (self->calls) == 0) {
/* Ensure we say alive across the callback */ /* Ensure we say alive across the callback */
self->refcount++; self->refcount++;
self->done_func (self, self->error, self->context, self->user_data, self->user_data2); self->done_func (self, self->error, self->context, self->user_data);
nm_auth_chain_unref (self); nm_auth_chain_unref (self);
} }
} }
@@ -141,7 +189,7 @@ pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
call_result = NM_AUTH_CALL_RESULT_NO; call_result = NM_AUTH_CALL_RESULT_NO;
} }
chain->call_func (chain, call->permission, error, call_result, chain->user_data, chain->user_data2); chain->call_func (chain, call->permission, error, call_result, chain->user_data);
nm_auth_chain_check_done (chain); nm_auth_chain_check_done (chain);
g_clear_error (&error); g_clear_error (&error);
@@ -152,11 +200,13 @@ pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
gboolean gboolean
nm_auth_chain_add_call (NMAuthChain *self, nm_auth_chain_add_call (NMAuthChain *self,
const char *permission) const char *permission,
gboolean allow_interaction)
{ {
PolkitCall *call; PolkitCall *call;
char *sender; char *sender;
PolkitSubject *subject; PolkitSubject *subject;
PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (self->context != NULL, FALSE); g_return_val_if_fail (self->context != NULL, FALSE);
@@ -175,11 +225,14 @@ nm_auth_chain_add_call (NMAuthChain *self,
self->calls = g_slist_append (self->calls, call); self->calls = g_slist_append (self->calls, call);
if (allow_interaction)
flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
polkit_authority_check_authorization (self->authority, polkit_authority_check_authorization (self->authority,
subject, subject,
permission, permission,
NULL, NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, flags,
call->cancellable, call->cancellable,
pk_call_cb, pk_call_cb,
call); call);
@@ -205,6 +258,7 @@ nm_auth_chain_unref (NMAuthChain *self)
g_slist_free (self->calls); g_slist_free (self->calls);
g_clear_error (&self->error); g_clear_error (&self->error);
g_hash_table_destroy (self->data);
memset (self, 0, sizeof (NMAuthChain)); memset (self, 0, sizeof (NMAuthChain));
g_free (self); g_free (self);

View File

@@ -33,35 +33,40 @@
typedef struct NMAuthChain NMAuthChain; typedef struct NMAuthChain NMAuthChain;
enum { typedef enum {
NM_AUTH_CALL_RESULT_UNKNOWN, NM_AUTH_CALL_RESULT_UNKNOWN,
NM_AUTH_CALL_RESULT_YES, NM_AUTH_CALL_RESULT_YES,
NM_AUTH_CALL_RESULT_AUTH, NM_AUTH_CALL_RESULT_AUTH,
NM_AUTH_CALL_RESULT_NO, NM_AUTH_CALL_RESULT_NO,
}; } NMAuthCallResult;
typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
GError *error, GError *error,
DBusGMethodInvocation *context, DBusGMethodInvocation *context,
gpointer user_data, gpointer user_data);
gpointer user_data2);
typedef void (*NMAuthChainCallFunc) (NMAuthChain *chain, typedef void (*NMAuthChainCallFunc) (NMAuthChain *chain,
const char *permission, const char *permission,
GError *error, GError *error,
guint result, NMAuthCallResult result,
gpointer user_data, gpointer user_data);
gpointer user_data2);
NMAuthChain *nm_auth_chain_new (PolkitAuthority *authority, NMAuthChain *nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context, DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func, NMAuthChainResultFunc done_func,
NMAuthChainCallFunc call_func, NMAuthChainCallFunc call_func,
gpointer user_data, gpointer user_data);
gpointer user_data2);
gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag);
void nm_auth_chain_set_data (NMAuthChain *chain,
const char *tag,
gpointer data,
GDestroyNotify data_destroy);
gboolean nm_auth_chain_add_call (NMAuthChain *chain, gboolean nm_auth_chain_add_call (NMAuthChain *chain,
const char *permission); const char *permission,
gboolean allow_interaction);
void nm_auth_chain_unref (NMAuthChain *chain); void nm_auth_chain_unref (NMAuthChain *chain);

View File

@@ -73,7 +73,9 @@ static gboolean impl_manager_deactivate_connection (NMManager *manager,
static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError **err); static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError **err);
static gboolean impl_manager_enable (NMManager *manager, gboolean enable, GError **err); static void impl_manager_enable (NMManager *manager,
gboolean enable,
DBusGMethodInvocation *context);
static void impl_manager_get_permissions (NMManager *manager, static void impl_manager_get_permissions (NMManager *manager,
DBusGMethodInvocation *context); DBusGMethodInvocation *context);
@@ -2727,6 +2729,27 @@ do_sleep_wake (NMManager *self)
nm_manager_update_state (self); nm_manager_update_state (self);
} }
static gboolean
return_permission_denied_error (PolkitAuthority *authority,
const char *detail,
DBusGMethodInvocation *context)
{
GError *error;
g_assert (context);
if (!authority) {
error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"%s request failed: PolicyKit not initialized",
detail);
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE;
}
return TRUE;
}
static gboolean static gboolean
impl_manager_sleep (NMManager *self, gboolean do_sleep, GError **error) impl_manager_sleep (NMManager *self, gboolean do_sleep, GError **error)
{ {
@@ -2756,26 +2779,14 @@ impl_manager_sleep (NMManager *self, gboolean do_sleep, GError **error)
return TRUE; return TRUE;
} }
static gboolean static void
impl_manager_enable (NMManager *self, gboolean enable, GError **error) _internal_enable (NMManager *self, gboolean enable)
{ {
NMManagerPrivate *priv; NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *err = NULL;
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->net_enabled == enable) {
g_set_error (error,
NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
"Already %s", enable ? "enabled" : "disabled");
return FALSE;
}
/* Update "NetworkingEnabled" key in state file */ /* Update "NetworkingEnabled" key in state file */
if (priv->state_file) { if (priv->state_file) {
GError *err = NULL;
if (!write_value_to_state_file (priv->state_file, if (!write_value_to_state_file (priv->state_file,
"main", "NetworkingEnabled", "main", "NetworkingEnabled",
G_TYPE_BOOLEAN, (gpointer) &enable, G_TYPE_BOOLEAN, (gpointer) &enable,
@@ -2798,7 +2809,92 @@ impl_manager_enable (NMManager *self, gboolean enable, GError **error)
do_sleep_wake (self); do_sleep_wake (self);
g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED); g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED);
return TRUE; }
static void
enable_net_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;
NMAuthCallResult result;
gboolean enable;
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "result"));
enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable"));
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
if (error) {
nm_log_dbg (LOGD_CORE, "Enable request failed: %s", error->message);
ret_error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Enable request failed: %s",
error->message);
dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error);
} else if (result != NM_AUTH_CALL_RESULT_YES) {
ret_error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Not authorized to enable/disable networking");
dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error);
} else {
_internal_enable (self, enable);
dbus_g_method_return (context);
}
nm_auth_chain_unref (chain);
}
static void
enable_net_call_done_cb (NMAuthChain *chain,
const char *permission,
GError *error,
NMAuthCallResult result,
gpointer user_data)
{
if (!error)
nm_auth_chain_set_data (chain, "result", GUINT_TO_POINTER (result), NULL);
}
static void
impl_manager_enable (NMManager *self,
gboolean enable,
DBusGMethodInvocation *context)
{
NMManagerPrivate *priv;
NMAuthChain *chain;
GError *error;
g_return_if_fail (NM_IS_MANAGER (self));
priv = NM_MANAGER_GET_PRIVATE (self);
if (priv->net_enabled == enable) {
error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
"Already %s", enable ? "enabled" : "disabled");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
if (!return_permission_denied_error (priv->authority, "Permission", context))
return;
chain = nm_auth_chain_new (priv->authority,
context,
enable_net_done_cb,
enable_net_call_done_cb,
self);
g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE);
} }
/* Permissions */ /* Permissions */
@@ -2814,12 +2910,10 @@ static void
get_permissions_done_cb (NMAuthChain *chain, get_permissions_done_cb (NMAuthChain *chain,
GError *error, GError *error,
DBusGMethodInvocation *context, DBusGMethodInvocation *context,
gpointer user_data, gpointer user_data)
gpointer user_data2)
{ {
NMManager *self = NM_MANAGER (user_data); NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GHashTable *hash = user_data2;
GError *ret_error; GError *ret_error;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain); priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
@@ -2832,11 +2926,9 @@ get_permissions_done_cb (NMAuthChain *chain,
dbus_g_method_return_error (context, ret_error); dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error); g_error_free (ret_error);
} else { } else {
g_assert (user_data2); dbus_g_method_return (context, nm_auth_chain_get_data (chain, "results"));
dbus_g_method_return (context, hash);
} }
g_hash_table_destroy (hash);
nm_auth_chain_unref (chain); nm_auth_chain_unref (chain);
} }
@@ -2845,28 +2937,28 @@ get_permissions_call_done_cb (NMAuthChain *chain,
const char *permission, const char *permission,
GError *error, GError *error,
guint result, guint result,
gpointer user_data, gpointer user_data)
gpointer user_data2)
{ {
GHashTable *hash = user_data2; GHashTable *hash;
const char *str_result = NULL; const char *str_result = NULL;
if (!error) { if (error)
g_assert (result != NM_AUTH_CALL_RESULT_UNKNOWN); return;
if (result == NM_AUTH_CALL_RESULT_YES) hash = nm_auth_chain_get_data (chain, "results");
str_result = "yes";
else if (result == NM_AUTH_CALL_RESULT_NO)
str_result = "no";
else if (result == NM_AUTH_CALL_RESULT_AUTH)
str_result = "auth";
else {
nm_log_dbg (LOGD_CORE, "unknown auth chain result %d", result);
}
if (str_result) if (result == NM_AUTH_CALL_RESULT_YES)
g_hash_table_insert (hash, g_strdup (permission), g_strdup (str_result)); str_result = "yes";
else if (result == NM_AUTH_CALL_RESULT_NO)
str_result = "no";
else if (result == NM_AUTH_CALL_RESULT_AUTH)
str_result = "auth";
else {
nm_log_dbg (LOGD_CORE, "unknown auth chain result %d", result);
} }
if (str_result)
g_hash_table_insert (hash, g_strdup (permission), g_strdup (str_result));
} }
static void static void
@@ -2888,20 +2980,21 @@ impl_manager_get_permissions (NMManager *self,
return; return;
} }
results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
chain = nm_auth_chain_new (priv->authority, chain = nm_auth_chain_new (priv->authority,
context, context,
get_permissions_done_cb, get_permissions_done_cb,
get_permissions_call_done_cb, get_permissions_call_done_cb,
self, self);
results);
g_assert (chain); g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain); priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI); nm_auth_chain_set_data (chain, "results", results, (GDestroyNotify) g_hash_table_destroy);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE);
} }
/* Legacy 0.6 compatibility interface */ /* Legacy 0.6 compatibility interface */