system-settings: add permissions

Since the new PolicyKit does away with easy checking of authorizations,
we get to implement it by ourselves, but that's OK since we can actually
use it for a lot more stuff.  So add the GetPermissions call which returns
the permissions the caller actually has, and a signal informing callers
that their permissions might have changed.  Hook this all up to
PolicyKit so it's useful.
This commit is contained in:
Dan Williams
2009-08-24 13:03:09 -05:00
parent 909375920b
commit 2dbaab2221
9 changed files with 348 additions and 12 deletions

View File

@@ -39,6 +39,43 @@
</arg>
</signal>
<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="GetPermissions">
<tp:docstring>
Returns a bitfield indicating certain operations the caller is permitted to perform. Some of these operations may require authorization by the user.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_get_permissions"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="permissions" type="u" direction="out" tp:type="NM_SETTINGS_SYSTEM_PERMISSIONS">
<tp:docstring>
A bitfield of permitted operations. Some of these operations may require the user to authorize via password entry or other means.
</tp:docstring>
</arg>
</method>
<tp:flags name="NM_SETTINGS_SYSTEM_PERMISSIONS" value-prefix="NM_SETTINGS_SYSTEM_PERMISSION" type="u">
<tp:flag suffix="NONE" value="0x0">
<tp:docstring>No permissions.</tp:docstring>
</tp:flag>
<tp:flag suffix="CONNECTION_MODIFY" value="0x1">
<tp:docstring>Can modify/add/delete connections.</tp:docstring>
</tp:flag>
<tp:flag suffix="WIFI_SHARING_PROTECTED" value="0x2">
<tp:docstring>Can share connections via a encrypted user-created WiFi network.</tp:docstring>
</tp:flag>
<tp:flag suffix="WIFI_SHARING_OPEN" value="0x4">
<tp:docstring>Can share connections via a open/unencrypted user-created WiFi network.</tp:docstring>
</tp:flag>
<tp:flag suffix="HOSTNAME_MODIFY" value="0x8">
<tp:docstring>Can modify the persistent system hostname.</tp:docstring>
</tp:flag>
</tp:flags>
</interface>
</node>

View File

@@ -135,6 +135,7 @@ global:
nm_settings_service_get_type;
nm_settings_system_interface_get_type;
nm_settings_system_interface_add_connection;
nm_settings_system_interface_get_permissions;
nm_settings_system_interface_save_hostname;
nm_settings_error_quark;
nm_settings_get_type;

View File

@@ -105,9 +105,53 @@ save_hostname (NMSettingsSystemInterface *settings,
NMSettingsSystemSaveHostnameFunc callback,
gpointer user_data)
{
// FIXME: implement using get_permissions as a template
return FALSE;
}
typedef struct {
NMSettingsSystemInterface *settings;
NMSettingsSystemGetPermissionsFunc callback;
gpointer callback_data;
} GetPermissionsInfo;
static void
get_permissions_cb (DBusGProxy *proxy,
DBusGProxyCall *call,
gpointer user_data)
{
GetPermissionsInfo *info = user_data;
NMSettingsSystemPermission permissions = NM_SETTINGS_SYSTEM_PERMISSION_NONE;
GError *error = NULL;
dbus_g_proxy_end_call (proxy, call, &error,
G_TYPE_UINT, &permissions,
G_TYPE_INVALID);
info->callback (info->settings, permissions, error, info->callback_data);
g_clear_error (&error);
}
static gboolean
get_permissions (NMSettingsSystemInterface *settings,
NMSettingsSystemGetPermissionsFunc callback,
gpointer user_data)
{
NMRemoteSettingsSystemPrivate *priv = NM_REMOTE_SETTINGS_SYSTEM_GET_PRIVATE (settings);
GetPermissionsInfo *info;
info = g_malloc0 (sizeof (GetPermissionsInfo));
info->settings = settings;
info->callback = callback;
info->callback_data = user_data;
dbus_g_proxy_begin_call (priv->proxy, "GetPermissions",
get_permissions_cb,
info,
g_free,
G_TYPE_INVALID);
return TRUE;
}
/****************************************************************/
static void
@@ -115,6 +159,7 @@ settings_system_interface_init (NMSettingsSystemInterface *klass)
{
/* interface implementation */
klass->save_hostname = save_hostname;
klass->get_permissions = get_permissions;
}
/**

View File

@@ -56,9 +56,33 @@ nm_settings_system_interface_save_hostname (NMSettingsSystemInterface *settings,
return FALSE;
}
/**
* nm_settings_system_interface_get_permissions:
* @settings: a object implementing %NMSettingsSystemInterface
* @callback: callback to be called when the permissions operation completes
* @user_data: caller-specific data passed to @callback
*
* Requests an indication of the operations the caller is permitted to perform
* including those that may require authorization.
**/
gboolean
nm_settings_system_interface_get_permissions (NMSettingsSystemInterface *settings,
NMSettingsSystemGetPermissionsFunc callback,
gpointer user_data)
{
g_return_val_if_fail (settings != NULL, FALSE);
g_return_val_if_fail (NM_IS_SETTINGS_SYSTEM_INTERFACE (settings), FALSE);
g_return_val_if_fail (callback != NULL, FALSE);
if (NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->get_permissions)
return NM_SETTINGS_SYSTEM_INTERFACE_GET_INTERFACE (settings)->get_permissions (settings, callback, user_data);
return FALSE;
}
static void
nm_settings_system_interface_init (gpointer g_iface)
{
GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
static gboolean initialized = FALSE;
if (initialized)
@@ -81,6 +105,15 @@ nm_settings_system_interface_init (gpointer g_iface)
FALSE,
G_PARAM_READABLE));
/* Signals */
g_signal_new (NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS,
iface_type,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMSettingsSystemInterface, check_permissions),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
initialized = TRUE;
}

View File

@@ -26,6 +26,14 @@
#include "NetworkManager.h"
typedef enum {
NM_SETTINGS_SYSTEM_PERMISSION_NONE = 0x0,
NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY = 0x1,
NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED = 0x2,
NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN = 0x4,
NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY = 0x8
} NMSettingsSystemPermission;
#define NM_TYPE_SETTINGS_SYSTEM_INTERFACE (nm_settings_system_interface_get_type ())
#define NM_SETTINGS_SYSTEM_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_SYSTEM_INTERFACE, NMSettingsSystemInterface))
#define NM_IS_SETTINGS_SYSTEM_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_SYSTEM_INTERFACE))
@@ -34,6 +42,8 @@
#define NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME "hostname"
#define NM_SETTINGS_SYSTEM_INTERFACE_CAN_MODIFY "can-modify"
#define NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS "check-permissions"
typedef enum {
NM_SETTINGS_SYSTEM_INTERFACE_PROP_FIRST = 0x1000,
@@ -49,6 +59,11 @@ typedef void (*NMSettingsSystemSaveHostnameFunc) (NMSettingsSystemInterface *set
GError *error,
gpointer user_data);
typedef void (*NMSettingsSystemGetPermissionsFunc) (NMSettingsSystemInterface *settings,
NMSettingsSystemPermission permissions,
GError *error,
gpointer user_data);
struct _NMSettingsSystemInterface {
GTypeInterface g_iface;
@@ -57,6 +72,13 @@ struct _NMSettingsSystemInterface {
const char *hostname,
NMSettingsSystemSaveHostnameFunc callback,
gpointer user_data);
gboolean (*get_permissions) (NMSettingsSystemInterface *settings,
NMSettingsSystemGetPermissionsFunc callback,
gpointer user_data);
/* Signals */
void (*check_permissions) (NMSettingsSystemInterface *settings);
};
GType nm_settings_system_interface_get_type (void);
@@ -66,4 +88,8 @@ gboolean nm_settings_system_interface_save_hostname (NMSettingsSystemInterface *
NMSettingsSystemSaveHostnameFunc callback,
gpointer user_data);
gboolean nm_settings_system_interface_get_permissions (NMSettingsSystemInterface *settings,
NMSettingsSystemGetPermissionsFunc callback,
gpointer user_data);
#endif /* NM_SETTINGS_SYSTEM_INTERFACE_H */

View File

@@ -18,4 +18,31 @@
</defaults>
</action>
<action id="org.freedesktop.network-manager-settings.system.hostname.modify">
<_description>Modify persistent system hostname</_description>
<_message>System policy prevents modification of the persistent system hostname</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
<action id="org.freedesktop.network-manager-settings.system.wifi.share.protected">
<_description>Connection sharing via a protected WiFi network</_description>
<_message>System policy prevents sharing connections via a protected WiFi network</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="org.freedesktop.network-manager-settings.system.wifi.share.open">
<_description>Connection sharing via an open WiFi network</_description>
<_message>System policy prevents sharing connections via an open WiFi network</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig>

View File

@@ -24,6 +24,9 @@
#include <polkit/polkit.h>
#define NM_SYSCONFIG_POLICY_ACTION "org.freedesktop.network-manager-settings.system.modify"
#define NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY "org.freedesktop.network-manager-settings.system.modify"
#define NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_PROTECTED "org.freedesktop.network-manager-settings.system.wifi.share.protected"
#define NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_OPEN "org.freedesktop.network-manager-settings.system.wifi.share.open"
#define NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY "org.freedesktop.network-manager-settings.system.hostname.modify"
#endif /* NM_POLKIT_HELPERS_H */

View File

@@ -296,7 +296,7 @@ dbus_update (NMExportedConnection *exported,
g_assert (call);
polkit_authority_check_authorization (priv->authority,
call->subject,
NM_SYSCONFIG_POLICY_ACTION,
NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
call->cancellable,
@@ -371,7 +371,7 @@ dbus_delete (NMExportedConnection *exported,
g_assert (call);
polkit_authority_check_authorization (priv->authority,
call->subject,
NM_SYSCONFIG_POLICY_ACTION,
NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
call->cancellable,
@@ -453,7 +453,7 @@ dbus_get_secrets (NMExportedConnection *exported,
g_assert (call);
polkit_authority_check_authorization (priv->authority,
call->subject,
NM_SYSCONFIG_POLICY_ACTION,
NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
call->cancellable,

View File

@@ -70,6 +70,9 @@ static void impl_settings_save_hostname (NMSysconfigSettings *self,
const char *hostname,
DBusGMethodInvocation *context);
static void impl_settings_get_permissions (NMSysconfigSettings *self,
DBusGMethodInvocation *context);
#include "nm-settings-system-glue.h"
static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
@@ -513,15 +516,19 @@ typedef struct {
NMSysconfigSettings *self;
DBusGMethodInvocation *context;
PolkitSubject *subject;
GCancellable *cancellable;
NMConnection *connection;
NMSettingsAddConnectionFunc callback;
gpointer callback_data;
char *hostname;
NMSettingsSystemPermission permissions;
guint32 permissions_calls;
} PolkitCall;
#include "nm-dbus-manager.h"
static PolkitCall *
polkit_call_new (NMSysconfigSettings *self,
DBusGMethodInvocation *context,
@@ -547,7 +554,6 @@ polkit_call_new (NMSysconfigSettings *self,
}
if (hostname)
call->hostname = g_strdup (hostname);
call->cancellable = g_cancellable_new ();
sender = dbus_g_method_get_sender (context);
call->subject = polkit_system_bus_name_new (sender);
@@ -563,7 +569,6 @@ polkit_call_free (PolkitCall *call)
g_object_unref (call->connection);
g_free (call->hostname);
g_object_unref (call->subject);
g_object_unref (call->cancellable);
g_free (call);
}
@@ -670,10 +675,10 @@ add_connection (NMSettingsService *service,
g_assert (call);
polkit_authority_check_authorization (priv->authority,
call->subject,
NM_SYSCONFIG_POLICY_ACTION,
NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
call->cancellable,
NULL,
pk_add_cb,
call);
}
@@ -757,14 +762,169 @@ impl_settings_save_hostname (NMSysconfigSettings *self,
g_assert (call);
polkit_authority_check_authorization (priv->authority,
call->subject,
NM_SYSCONFIG_POLICY_ACTION,
NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY,
NULL,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
call->cancellable,
NULL,
pk_hostname_cb,
call);
}
static void
pk_authority_changed_cb (GObject *object, gpointer user_data)
{
/* Let clients know they should re-check their authorization */
g_signal_emit_by_name (NM_SYSCONFIG_SETTINGS (user_data),
NM_SETTINGS_SYSTEM_INTERFACE_CHECK_PERMISSIONS);
}
typedef struct {
PolkitCall *pk_call;
const char *pk_action;
NMSettingsSystemPermission permission;
} PermissionsCall;
static void
permission_call_done (GObject *object, GAsyncResult *result, gpointer user_data)
{
PermissionsCall *call = user_data;
PolkitCall *pk_call = call->pk_call;
NMSysconfigSettings *self = pk_call->self;
NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
PolkitAuthorizationResult *pk_result;
GError *error = NULL;
pk_result = polkit_authority_check_authorization_finish (priv->authority,
result,
&error);
/* Some random error happened */
if (error) {
g_warning ("%s.%d (%s): error checking '%s' permission: (%d) %s",
__FILE__, __LINE__, __func__,
call->pk_action,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
if (error)
g_error_free (error);
} else {
/* If the caller is authorized, or the caller could authorize via a
* challenge, then authorization is possible. Otherwise, caller is out of
* luck.
*/
if ( polkit_authorization_result_get_is_authorized (pk_result)
|| polkit_authorization_result_get_is_challenge (pk_result))
pk_call->permissions |= call->permission;
}
g_object_unref (pk_result);
pk_call->permissions_calls--;
if (pk_call->permissions_calls == 0) {
/* All the permissions calls are done, return the full permissions
* bitfield back to the user.
*/
dbus_g_method_return (pk_call->context, pk_call->permissions);
polkit_call_free (pk_call);
}
memset (call, 0, sizeof (PermissionsCall));
g_free (call);
}
static void
start_permission_check (NMSysconfigSettings *self,
PolkitCall *pk_call,
const char *pk_action,
NMSettingsSystemPermission permission)
{
NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
PermissionsCall *call;
g_return_if_fail (pk_call != NULL);
g_return_if_fail (pk_action != NULL);
g_return_if_fail (permission != NM_SETTINGS_SYSTEM_PERMISSION_NONE);
call = g_malloc0 (sizeof (PermissionsCall));
call->pk_call = pk_call;
call->pk_action = pk_action;
call->permission = permission;
pk_call->permissions_calls++;
polkit_authority_check_authorization (priv->authority,
pk_call->subject,
pk_action,
NULL,
0,
NULL,
permission_call_done,
call);
}
static void
impl_settings_get_permissions (NMSysconfigSettings *self,
DBusGMethodInvocation *context)
{
PolkitCall *call;
call = polkit_call_new (self, context, NULL, NULL, NULL, FALSE);
g_assert (call);
/* Start checks for the various permissions */
/* Only check for connection-modify if one of our plugins supports it. */
if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) {
start_permission_check (self, call,
NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY,
NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY);
}
/* Only check for hostname-modify if one of our plugins supports it. */
if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
start_permission_check (self, call,
NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY,
NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY);
}
// FIXME: hook these into plugin permissions like the modify permissions */
start_permission_check (self, call,
NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_OPEN,
NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN);
start_permission_check (self, call,
NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_PROTECTED,
NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED);
}
static gboolean
get_permissions (NMSettingsSystemInterface *settings,
NMSettingsSystemGetPermissionsFunc callback,
gpointer user_data)
{
NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (settings);
NMSettingsSystemPermission permissions = NM_SETTINGS_SYSTEM_PERMISSION_NONE;
/* Local caller (ie, NM) gets full permissions by default because it doesn't
* need authorization. However, permissions are still subject to plugin's
* restrictions. i.e. if no plugins support connection-modify, then even
* the local caller won't get that permission.
*/
/* Only check for connection-modify if one of our plugins supports it. */
if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS))
permissions |= NM_SETTINGS_SYSTEM_PERMISSION_CONNECTION_MODIFY;
/* Only check for hostname-modify if one of our plugins supports it. */
if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME))
permissions |= NM_SETTINGS_SYSTEM_PERMISSION_HOSTNAME_MODIFY;
// FIXME: hook these into plugin permissions like the modify permissions */
permissions |= NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_OPEN;
permissions |= NM_SETTINGS_SYSTEM_PERMISSION_WIFI_SHARE_PROTECTED;
callback (settings, permissions, NULL, user_data);
return TRUE;
}
static gboolean
have_connection_for_device (NMSysconfigSettings *self, GByteArray *mac)
{
@@ -1115,6 +1275,8 @@ finalize (GObject *object)
static void
settings_system_interface_init (NMSettingsSystemInterface *iface)
{
iface->get_permissions = get_permissions;
dbus_g_object_type_install_info (G_TYPE_FROM_INTERFACE (iface),
&dbus_glib_nm_settings_system_object_info);
}
@@ -1206,7 +1368,9 @@ nm_sysconfig_settings_init (NMSysconfigSettings *self)
priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
priv->authority = polkit_authority_get ();
if (!priv->authority)
if (priv->authority)
g_signal_connect (priv->authority, "changed", G_CALLBACK (pk_authority_changed_cb), self);
else
g_warning ("%s: failed to create PolicyKit authority.", __func__);
/* Grab hostname on startup and use that if no plugins provide one */