core: add permissions framework for various operations (rh #585182) (bgo #619323)

This commit is contained in:
Dan Williams 2010-05-28 18:23:00 -07:00
parent 6810ef1422
commit 716a9c6c0d
12 changed files with 698 additions and 2 deletions

View file

@ -44,6 +44,14 @@ object. dbus-glib generates the same bound function names for D-Bus the methods
<arg name="enable" type="b" direction="in"/>
</method>
<method name="GetPermissions">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_get_permissions"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="permissions" type="a{ss}" direction="out"/>
</method>
<signal name="CheckPermissions"/>
<property name="NetworkingEnabled" type="b" access="read"/>
<property name="WirelessEnabled" type="b" access="readwrite"/>
<property name="WirelessHardwareEnabled" type="b" access="read"/>

View file

@ -116,6 +116,34 @@
</arg>
</method>
<method name="GetPermissions">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_get_permissions"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<tp:docstring>
Returns the permissions a caller has for various authenticated operations
that NetworkManager provides, like Enable/Disable networking, changing
WiFi, WWAN, and WiMAX state, etc.
</tp:docstring>
<arg name="permissions" type="a{ss}" direction="out">
<tp:docstring>
Dictionary of available permissions and results. Each permission
is represented by a name (ie "org.freedesktop.NetworkManager.Foobar")
and each result is one of the following values: "yes" (the permission
is available), "auth" (the permission is available after a successful
authentication), or "no" (the permission is denied). Clients may use
these values in the UI to indicate the ability to perform certain
operations.
</tp:docstring>
</arg>
</method>
<signal name="CheckPermissions">
<tp:docstring>
Emitted when system authorization details change, indicating that
clients may wish to recheck permissions with GetPermissions.
</tp:docstring>
</signal>
<method name="SetLogging">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_set_logging"/>
<tp:docstring>

View file

@ -34,6 +34,7 @@ global:
nm_client_get_device_by_path;
nm_client_get_devices;
nm_client_get_manager_running;
nm_client_get_permission_result;
nm_client_get_state;
nm_client_get_type;
nm_client_networking_get_enabled;

View file

@ -58,6 +58,9 @@ typedef struct {
GPtrArray *devices;
GPtrArray *active_connections;
DBusGProxyCall *perm_call;
GHashTable *permissions;
gboolean have_networking_enabled;
gboolean networking_enabled;
gboolean wireless_enabled;
@ -84,6 +87,7 @@ enum {
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
PERMISSION_CHANGED,
LAST_SIGNAL
};
@ -118,6 +122,8 @@ nm_client_init (NMClient *client)
priv->state = NM_STATE_UNKNOWN;
priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
g_signal_connect (client,
"notify::" NM_CLIENT_NETWORKING_ENABLED,
G_CALLBACK (handle_net_enabled_changed),
@ -284,6 +290,114 @@ register_for_property_changed (NMClient *client)
property_changed_info);
}
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan"
#define NM_AUTH_PERMISSION_USE_USER_CONNECTIONS "org.freedesktop.NetworkManager.use-user-connections"
static NMClientPermission
nm_permission_to_client (const char *nm)
{
if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK))
return NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK;
else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI))
return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI;
else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN))
return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN;
else if (!strcmp (nm, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS))
return NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS;
return NM_CLIENT_PERMISSION_NONE;
}
static NMClientPermissionResult
nm_permission_result_to_client (const char *nm)
{
if (!strcmp (nm, "yes"))
return NM_CLIENT_PERMISSION_RESULT_YES;
else if (!strcmp (nm, "no"))
return NM_CLIENT_PERMISSION_RESULT_NO;
else if (!strcmp (nm, "auth"))
return NM_CLIENT_PERMISSION_RESULT_AUTH;
return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
}
static void
get_permissions_reply (DBusGProxy *proxy,
GHashTable *permissions,
GError *error,
gpointer user_data)
{
NMClient *self = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
GHashTableIter iter;
gpointer key, value;
NMClientPermission perm;
NMClientPermissionResult perm_result;
GList *keys, *keys_iter;
priv->perm_call = NULL;
/* get list of old permissions for change notification */
keys = g_hash_table_get_keys (priv->permissions);
g_hash_table_remove_all (priv->permissions);
if (!error) {
/* Process new permissions */
g_hash_table_iter_init (&iter, permissions);
while (g_hash_table_iter_next (&iter, &key, &value)) {
perm = nm_permission_to_client ((const char *) key);
perm_result = nm_permission_result_to_client ((const char *) value);
if (perm) {
g_hash_table_insert (priv->permissions,
GUINT_TO_POINTER (perm),
GUINT_TO_POINTER (perm_result));
/* Remove this permission from the list of previous permissions
* we'll be sending NM_CLIENT_PERMISSION_RESULT_UNKNOWN for
* in the change signal since it is still a known permission.
*/
keys = g_list_remove (keys, GUINT_TO_POINTER (perm));
}
}
}
/* Signal changes in all updated permissions */
g_hash_table_iter_init (&iter, priv->permissions);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
GPOINTER_TO_UINT (key),
GPOINTER_TO_UINT (value));
}
/* And signal changes in all permissions that used to be valid but for
* some reason weren't received in the last request (if any).
*/
for (keys_iter = keys; keys_iter; keys_iter = g_list_next (keys_iter)) {
g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
GPOINTER_TO_UINT (keys_iter->data),
NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
}
g_list_free (keys);
}
static DBusGProxyCall *
get_permissions (NMClient *self)
{
return org_freedesktop_NetworkManager_get_permissions_async (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
get_permissions_reply,
self);
}
static void
client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
{
NMClient *self = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
if (!priv->perm_call)
priv->perm_call = get_permissions (self);
}
static GObject*
constructor (GType type,
guint n_construct_params,
@ -324,6 +438,15 @@ constructor (GType type,
object,
NULL);
/* Permissions */
dbus_g_proxy_add_signal (priv->client_proxy, "CheckPermissions", G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->client_proxy,
"CheckPermissions",
G_CALLBACK (client_recheck_permissions),
object,
NULL);
priv->perm_call = get_permissions (NM_CLIENT (object));
priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
@ -381,12 +504,17 @@ dispose (GObject *object)
return;
}
if (priv->perm_call)
dbus_g_proxy_cancel_call (priv->client_proxy, priv->perm_call);
g_object_unref (priv->client_proxy);
g_object_unref (priv->bus_proxy);
free_object_array (&priv->devices);
free_object_array (&priv->active_connections);
g_hash_table_destroy (priv->permissions);
G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
}
@ -626,6 +754,22 @@ nm_client_class_init (NMClientClass *client_class)
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
/**
* NMClient::permission-changed:
* @widget: the client that received the signal
* @permission: a permission from #NMClientPermission
* @result: the permission's result, one of #NMClientPermissionResult
*
* Notifies that a permission has changed
**/
signals[PERMISSION_CHANGED] =
g_signal_new ("permission-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
_nm_marshal_VOID__UINT_UINT,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
}
/**
@ -1158,3 +1302,25 @@ nm_client_get_manager_running (NMClient *client)
return NM_CLIENT_GET_PRIVATE (client)->manager_running;
}
/**
* nm_client_get_permission_result:
* @client: a #NMClient
* @permission: the permission for which to return the result, one of #NMClientPermission
*
* Requests the result of a specific permission, which indicates whether the
* client can or cannot perform the action the permission represents
*
* Returns: the permission's result, one of #NMClientPermissionResult
**/
NMClientPermissionResult
nm_client_get_permission_result (NMClient *client, NMClientPermission permission)
{
gpointer result;
g_return_val_if_fail (NM_IS_CLIENT (client), NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
result = g_hash_table_lookup (NM_CLIENT_GET_PRIVATE (client)->permissions,
GUINT_TO_POINTER (permission));
return GPOINTER_TO_UINT (result);
}

View file

@ -50,6 +50,25 @@ G_BEGIN_DECLS
#define NM_CLIENT_WWAN_HARDWARE_ENABLED "wwan-hardware-enabled"
#define NM_CLIENT_ACTIVE_CONNECTIONS "active-connections"
/* Permissions */
typedef enum {
NM_CLIENT_PERMISSION_NONE = 0,
NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK = 1,
NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI = 2,
NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN = 3,
NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS = 4,
NM_CLIENT_PERMISSION_LAST = NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS
} NMClientPermission;
typedef enum {
NM_CLIENT_PERMISSION_RESULT_UNKNOWN = 0,
NM_CLIENT_PERMISSION_RESULT_YES,
NM_CLIENT_PERMISSION_RESULT_AUTH,
NM_CLIENT_PERMISSION_RESULT_NO
} NMClientPermissionResult;
typedef struct {
NMObject parent;
} NMClient;
@ -105,6 +124,9 @@ gboolean nm_client_get_manager_running (NMClient *client);
const GPtrArray *nm_client_get_active_connections (NMClient *client);
void nm_client_sleep (NMClient *client, gboolean sleep);
NMClientPermissionResult nm_client_get_permission_result (NMClient *client,
NMClientPermission permission);
G_END_DECLS
#endif /* NM_CLIENT_H */

View file

@ -11,6 +11,8 @@ libnm-util/crypto.c
libnm-util/crypto_gnutls.c
libnm-util/crypto_nss.c
libnm-util/nm-utils.c
policy/org.freedesktop.network-manager-settings.system.policy.in
policy/org.freedesktop.NetworkManager.policy.in
src/nm-netlink-monitor.c
src/main.c
src/dhcp-manager/nm-dhcp-dhclient.c
@ -19,5 +21,4 @@ src/logging/nm-logging.c
src/named-manager/nm-named-manager.c
src/system-settings/nm-default-wired-connection.c
system-settings/plugins/ifcfg-rh/reader.c
policy/org.freedesktop.network-manager-settings.system.policy.in

View file

@ -1,6 +1,9 @@
polkit_policydir = $(datadir)/polkit-1/actions
dist_polkit_policy_in_files = org.freedesktop.network-manager-settings.system.policy.in
dist_polkit_policy_in_files = \
org.freedesktop.network-manager-settings.system.policy.in \
org.freedesktop.NetworkManager.policy.in
dist_polkit_policy_DATA = $(dist_polkit_policy_in_files:.policy.in=.policy)
@INTLTOOL_POLICY_RULE@

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
<vendor>NetworkManager</vendor>
<vendor_url>http://www.gnome.org/projects/NetworkManager</vendor_url>
<icon_name>nm-icon</icon_name>
<action id="org.freedesktop.NetworkManager.enable-disable-network">
<_description>Enable or disable system networking</_description>
<_message>System policy prevents enabling or disabling system networking</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="org.freedesktop.NetworkManager.enable-disable-wifi">
<_description>Enable or disable WiFi devices</_description>
<_message>System policy prevents enabling or disabling WiFi devices</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="org.freedesktop.NetworkManager.enable-disable-wwan">
<_description>Enable or disable mobile broadband devices</_description>
<_message>System policy prevents enabling or disabling mobile broadband devices</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="org.freedesktop.NetworkManager.use-user-connections">
<_description>Allow use of user-specific connections</_description>
<_message>System policy prevents use of user-specific connections</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>

View file

@ -133,6 +133,8 @@ NetworkManager_SOURCES = \
nm-system.h \
nm-manager.c \
nm-manager.h \
nm-manager-auth.c \
nm-manager-auth.h \
nm-netlink-monitor.c \
nm-netlink-monitor.h \
nm-activation-request.c \
@ -211,6 +213,7 @@ NetworkManager_CPPFLAGS = \
$(GUDEV_CFLAGS) \
$(LIBNL_CFLAGS) \
$(GMODULE_CFLAGS) \
$(POLKIT_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DBINDIR=\"$(bindir)\" \
-DSBINDIR=\"$(sbindir)\" \
@ -242,6 +245,7 @@ NetworkManager_LDADD = \
$(GUDEV_LIBS) \
$(LIBNL_LIBS) \
$(GMODULE_LIBS) \
$(POLKIT_LIBS) \
$(LIBM) \
$(LIBDL)

212
src/nm-manager-auth.c Normal file
View file

@ -0,0 +1,212 @@
/* -*- 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) 2010 Red Hat, Inc.
*/
#include "nm-manager-auth.h"
#include "nm-logging.h"
#include <dbus/dbus-glib-lowlevel.h>
#include <string.h>
struct NMAuthChain {
guint32 refcount;
PolkitAuthority *authority;
GSList *calls;
DBusGMethodInvocation *context;
GError *error;
NMAuthChainResultFunc done_func;
NMAuthChainCallFunc call_func;
gpointer user_data;
gpointer user_data2;
};
typedef struct {
NMAuthChain *chain;
GCancellable *cancellable;
char *permission;
gboolean disposed;
} PolkitCall;
NMAuthChain *
nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
NMAuthChainCallFunc call_func,
gpointer user_data,
gpointer user_data2)
{
NMAuthChain *self;
self = g_malloc0 (sizeof (NMAuthChain));
self->refcount = 1;
self->authority = g_object_ref (authority);
self->done_func = done_func;
self->call_func = call_func;
self->context = context;
self->user_data = user_data;
self->user_data2 = user_data2;
return self;
}
static void
nm_auth_chain_check_done (NMAuthChain *self)
{
g_return_if_fail (self != NULL);
if (g_slist_length (self->calls) == 0) {
/* Ensure we say alive across the callback */
self->refcount++;
self->done_func (self, self->error, self->context, self->user_data, self->user_data2);
nm_auth_chain_unref (self);
}
}
static void
polkit_call_cancel (PolkitCall *call)
{
call->disposed = TRUE;
g_cancellable_cancel (call->cancellable);
}
static void
polkit_call_free (PolkitCall *call)
{
g_return_if_fail (call != NULL);
call->disposed = TRUE;
g_free (call->permission);
call->permission = NULL;
call->chain = NULL;
g_object_unref (call->cancellable);
call->cancellable = NULL;
g_free (call);
}
static void
pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
PolkitCall *call = user_data;
NMAuthChain *chain;
PolkitAuthorizationResult *pk_result;
GError *error = NULL;
guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN;
/* If the call is already disposed do nothing */
if (call->disposed) {
polkit_call_free (call);
return;
}
chain = call->chain;
chain->calls = g_slist_remove (chain->calls, call);
pk_result = polkit_authority_check_authorization_finish (chain->authority,
result,
&error);
if (error) {
if (!chain->error)
chain->error = g_error_copy (error);
nm_log_warn (LOGD_CORE, "error requesting auth for %s: (%d) %s",
call->permission,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
} else {
if (polkit_authorization_result_get_is_authorized (pk_result)) {
/* Caller has the permission */
call_result = NM_AUTH_CALL_RESULT_YES;
} else if (polkit_authorization_result_get_is_challenge (pk_result)) {
/* Caller could authenticate to get the permission */
call_result = NM_AUTH_CALL_RESULT_AUTH;
} else
call_result = NM_AUTH_CALL_RESULT_NO;
}
chain->call_func (chain, call->permission, error, call_result, chain->user_data, chain->user_data2);
nm_auth_chain_check_done (chain);
g_clear_error (&error);
polkit_call_free (call);
if (pk_result)
g_object_unref (pk_result);
}
gboolean
nm_auth_chain_add_call (NMAuthChain *self,
const char *permission)
{
PolkitCall *call;
char *sender;
PolkitSubject *subject;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (self->context != NULL, FALSE);
g_return_val_if_fail (permission != NULL, FALSE);
sender = dbus_g_method_get_sender (self->context);
subject = polkit_system_bus_name_new (sender);
g_free (sender);
if (!subject)
return FALSE;
call = g_malloc0 (sizeof (PolkitCall));
call->chain = self;
call->permission = g_strdup (permission);
call->cancellable = g_cancellable_new ();
self->calls = g_slist_append (self->calls, call);
polkit_authority_check_authorization (self->authority,
subject,
permission,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
call->cancellable,
pk_call_cb,
call);
g_object_unref (subject);
return TRUE;
}
void
nm_auth_chain_unref (NMAuthChain *self)
{
GSList *iter;
g_return_if_fail (self != NULL);
self->refcount--;
if (self->refcount > 0)
return;
g_object_unref (self->authority);
for (iter = self->calls; iter; iter = g_slist_next (iter))
polkit_call_cancel ((PolkitCall *) iter->data);
g_slist_free (self->calls);
g_clear_error (&self->error);
memset (self, 0, sizeof (NMAuthChain));
g_free (self);
}

69
src/nm-manager-auth.h Normal file
View file

@ -0,0 +1,69 @@
/* -*- 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) 2010 Red Hat, Inc.
*/
#ifndef NM_MANAGER_AUTH_H
#define NM_MANAGER_AUTH_H
#include <polkit/polkit.h>
#include <glib.h>
#include <dbus/dbus-glib.h>
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan"
#define NM_AUTH_PERMISSION_USE_USER_CONNECTIONS "org.freedesktop.NetworkManager.use-user-connections"
typedef struct NMAuthChain NMAuthChain;
enum {
NM_AUTH_CALL_RESULT_UNKNOWN,
NM_AUTH_CALL_RESULT_YES,
NM_AUTH_CALL_RESULT_AUTH,
NM_AUTH_CALL_RESULT_NO,
};
typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data,
gpointer user_data2);
typedef void (*NMAuthChainCallFunc) (NMAuthChain *chain,
const char *permission,
GError *error,
guint result,
gpointer user_data,
gpointer user_data2);
NMAuthChain *nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
NMAuthChainCallFunc call_func,
gpointer user_data,
gpointer user_data2);
gboolean nm_auth_chain_add_call (NMAuthChain *chain,
const char *permission);
void nm_auth_chain_unref (NMAuthChain *chain);
#endif /* NM_MANAGER_AUTH_H */

View file

@ -54,6 +54,7 @@
#include "nm-secrets-provider-interface.h"
#include "nm-settings-interface.h"
#include "nm-settings-system-interface.h"
#include "nm-manager-auth.h"
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
@ -74,6 +75,9 @@ static gboolean impl_manager_sleep (NMManager *manager, gboolean sleep, GError *
static gboolean impl_manager_enable (NMManager *manager, gboolean enable, GError **err);
static void impl_manager_get_permissions (NMManager *manager,
DBusGMethodInvocation *context);
static gboolean impl_manager_set_logging (NMManager *manager,
const char *level,
const char *domains,
@ -196,6 +200,10 @@ typedef struct {
DBusGProxy *aipd_proxy;
PolkitAuthority *authority;
guint auth_changed_id;
GSList *auth_chains;
gboolean disposed;
} NMManagerPrivate;
@ -215,6 +223,7 @@ enum {
CONNECTION_ADDED,
CONNECTION_UPDATED,
CONNECTION_REMOVED,
CHECK_PERMISSIONS,
LAST_SIGNAL
};
@ -2792,6 +2801,109 @@ impl_manager_enable (NMManager *self, gboolean enable, GError **error)
return TRUE;
}
/* Permissions */
static void
pk_authority_changed_cb (GObject *object, gpointer user_data)
{
/* Let clients know they should re-check their authorization */
g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0);
}
static void
get_permissions_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data,
gpointer user_data2)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GHashTable *hash = user_data2;
GError *ret_error;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
if (error) {
nm_log_dbg (LOGD_CORE, "Permissions request failed: %s", error->message);
ret_error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Permissions request failed: %s",
error->message);
dbus_g_method_return_error (context, ret_error);
g_error_free (ret_error);
} else {
g_assert (user_data2);
dbus_g_method_return (context, hash);
}
g_hash_table_destroy (hash);
nm_auth_chain_unref (chain);
}
static void
get_permissions_call_done_cb (NMAuthChain *chain,
const char *permission,
GError *error,
guint result,
gpointer user_data,
gpointer user_data2)
{
GHashTable *hash = user_data2;
const char *str_result = NULL;
if (!error) {
g_assert (result != NM_AUTH_CALL_RESULT_UNKNOWN);
if (result == NM_AUTH_CALL_RESULT_YES)
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
impl_manager_get_permissions (NMManager *self,
DBusGMethodInvocation *context)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMAuthChain *chain;
GHashTable *results;
if (!priv->authority) {
GError *error;
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
"Permissions request failed: PolicyKit not initialized");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
chain = nm_auth_chain_new (priv->authority,
context,
get_permissions_done_cb,
get_permissions_call_done_cb,
self,
results);
g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS);
}
/* Legacy 0.6 compatibility interface */
static gboolean
@ -3078,6 +3190,10 @@ dispose (GObject *object)
pending_connection_info_destroy (priv->pending_connection_info);
priv->pending_connection_info = NULL;
g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL);
g_slist_free (priv->auth_chains);
g_object_unref (priv->authority);
while (g_slist_length (priv->secrets_calls))
free_get_secrets_info ((GetSecretsInfo *) priv->secrets_calls->data);
@ -3286,6 +3402,15 @@ nm_manager_init (NMManager *manager)
NULL);
} else
nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy");
priv->authority = polkit_authority_get ();
if (priv->authority) {
priv->auth_changed_id = g_signal_connect (priv->authority,
"changed",
G_CALLBACK (pk_authority_changed_cb),
manager);
} else
nm_log_warn (LOGD_CORE, "failed to create PolicyKit authority.");
}
static void
@ -3445,6 +3570,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
_nm_marshal_VOID__OBJECT_UINT,
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
signals[CHECK_PERMISSIONS] =
g_signal_new ("check-permissions",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/* StateChange is DEPRECATED */
signals[STATE_CHANGE] =
g_signal_new ("state-change",