diff options
Diffstat (limited to 'libnm-util/nm-setting-connection.c')
| -rw-r--r-- | libnm-util/nm-setting-connection.c | 348 |
1 files changed, 345 insertions, 3 deletions
diff --git a/libnm-util/nm-setting-connection.c b/libnm-util/nm-setting-connection.c index 65f613eb..b3bf4443 100644 --- a/libnm-util/nm-setting-connection.c +++ b/libnm-util/nm-setting-connection.c @@ -19,12 +19,15 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include <string.h> #include <ctype.h> +#include "nm-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-param-spec-specialized.h" #include "nm-setting-connection.h" /** @@ -81,10 +84,20 @@ G_DEFINE_TYPE (NMSettingConnection, nm_setting_connection, NM_TYPE_SETTING) #define NM_SETTING_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_CONNECTION, NMSettingConnectionPrivate)) +typedef enum { + PERM_TYPE_USER = 0, +} PermType; + +typedef struct { + guint8 ptype; + char *item; +} Permission; + typedef struct { char *id; char *uuid; char *type; + GSList *permissions; /* list of Permission structs */ gboolean autoconnect; guint64 timestamp; gboolean read_only; @@ -95,6 +108,7 @@ enum { PROP_ID, PROP_UUID, PROP_TYPE, + PROP_PERMISSIONS, PROP_AUTOCONNECT, PROP_TIMESTAMP, PROP_READ_ONLY, @@ -102,6 +116,89 @@ enum { LAST_PROP }; +/***********************************************************************/ + +#define PERM_USER_PREFIX "user:" + +static Permission * +permission_new_from_str (const char *str) +{ + Permission *p; + const char *last_colon; + size_t ulen = 0, i; + + g_return_val_if_fail (strncmp (str, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0, NULL); + str += strlen (PERM_USER_PREFIX); + + last_colon = strrchr (str, ':'); + if (last_colon) { + /* Ensure that somebody didn't pass "user::" */ + g_return_val_if_fail (last_colon > str, NULL); + + /* Reject :[detail] for now */ + g_return_val_if_fail (*(last_colon + 1) == '\0', NULL); + + /* Make sure we don't include detail in the username */ + ulen = last_colon - str; + } else + ulen = strlen (str); + + /* Sanity check the length of the username */ + g_return_val_if_fail (ulen < 100, NULL); + + /* Make sure there's no ':' in the username */ + for (i = 0; i < ulen; i++) + g_return_val_if_fail (str[i] != ':', NULL); + + /* And the username must be valid UTF-8 */ + g_return_val_if_fail (g_utf8_validate (str, -1, NULL) == TRUE, NULL); + + /* Yay, valid... create the new permission */ + p = g_slice_new0 (Permission); + p->ptype = PERM_TYPE_USER; + if (last_colon) { + p->item = g_malloc (ulen + 1); + memcpy (p->item, str, ulen); + p->item[ulen] = '\0'; + } else + p->item = g_strdup (str); + + return p; +} + +static Permission * +permission_new (const char *uname) +{ + Permission *p; + + g_return_val_if_fail (uname, NULL); + g_return_val_if_fail (uname[0] != '\0', NULL); + g_return_val_if_fail (strchr (uname, ':') == NULL, NULL); + g_return_val_if_fail (g_utf8_validate (uname, -1, NULL) == TRUE, NULL); + + /* Yay, valid... create the new permission */ + p = g_slice_new0 (Permission); + p->ptype = PERM_TYPE_USER; + p->item = g_strdup (uname); + return p; +} + +static char * +permission_to_string (Permission *p) +{ + return g_strdup_printf (PERM_USER_PREFIX "%s:", p->item); +} + +static void +permission_free (Permission *p) +{ + g_free (p->item); + memset (p, 0, sizeof (*p)); + g_slice_free (Permission, p); +} + +/***********************************************************************/ + /** * nm_setting_connection_new: * @@ -162,6 +259,177 @@ nm_setting_connection_get_connection_type (NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->type; } + +/** + * nm_setting_connection_get_num_permissions: + * @setting: the #NMSettingConnection + * + * Returns the number of entires in the #NMSettingConnection:permissions + * property of this setting. + * + * Returns: the number of permissions entires + */ +guint32 +nm_setting_connection_get_num_permissions (NMSettingConnection *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), 0); + + return g_slist_length (NM_SETTING_CONNECTION_GET_PRIVATE (setting)->permissions); +} + +/** + * nm_setting_connection_get_permission: + * @setting: the #NMSettingConnection + * @idx: the zero-based index of the permissions entry + * @out_ptype: on return, the permission type (at this time, always "user") + * @out_pitem: on return, the permission item (formatted accoring to @ptype, see + * #NMSettingConnection:permissions for more detail + * @out_detail: on return, the permission detail (at this time, always NULL) + * + * Retrieve one of the entries of the #NMSettingConnection:permissions property + * of this setting. + * + * Returns: %TRUE if a permission was returned, %FALSE if @idx was invalid + */ +gboolean +nm_setting_connection_get_permission (NMSettingConnection *setting, + guint32 idx, + const char **out_ptype, + const char **out_pitem, + const char **out_detail) +{ + NMSettingConnectionPrivate *priv; + Permission *p; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + g_return_val_if_fail (idx < g_slist_length (priv->permissions), FALSE); + + p = g_slist_nth_data (priv->permissions, idx); + if (out_ptype) + *out_ptype = "user"; + if (out_pitem) + *out_pitem = p->item; + if (out_detail) + *out_detail = NULL; + + return TRUE; +} + +/** + * nm_setting_connection_permissions_user_allowed: + * @setting: the #NMSettingConnection + * @uname: the user name to check permissions for + * + * Checks whether the given username is allowed to view/access this connection. + * + * Returns: %TRUE if the requested user is allowed to view this connection, + * %FALSE if the given user is not allowed to view this connection + */ +gboolean +nm_setting_connection_permissions_user_allowed (NMSettingConnection *setting, + const char *uname) +{ + NMSettingConnectionPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + g_return_val_if_fail (uname != NULL, FALSE); + g_return_val_if_fail (*uname != '\0', FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + /* If no permissions, visible to all */ + if (priv->permissions == NULL) + return TRUE; + + /* Find the username in the permissions list */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + Permission *p = iter->data; + + if (strcmp (uname, p->item) == 0) + return TRUE; + } + + return FALSE; +} + +/** + * nm_setting_connection_add_permission: + * @setting: the #NMSettingConnection + * @ptype: the permission type; at this time only "user" is supported + * @pitem: the permission item formatted as required for @ptype + * @detail: (allow-none): unused at this time; must be %NULL + * + * Adds a permission to the connection's permission list. At this time, only + * the "user" permission type is supported, and @pitem must be a username. See + * #NMSettingConnection:permissions: for more details. + * + * Returns: TRUE if the permission was unique and was successfully added to the + * list, FALSE if @ptype or @pitem was invalid or it the permission was already + * present in the list + */ +gboolean +nm_setting_connection_add_permission (NMSettingConnection *setting, + const char *ptype, + const char *pitem, + const char *detail) +{ + NMSettingConnectionPrivate *priv; + Permission *p; + GSList *iter; + + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); + g_return_val_if_fail (ptype, FALSE); + g_return_val_if_fail (strlen (ptype) > 0, FALSE); + g_return_val_if_fail (detail == NULL, FALSE); + + /* Only "user" for now... */ + g_return_val_if_fail (strcmp (ptype, "user") == 0, FALSE); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + + /* No dupes */ + for (iter = priv->permissions; iter; iter = g_slist_next (iter)) { + p = iter->data; + if (strcmp (pitem, p->item) == 0) + return FALSE; + } + + p = permission_new (pitem); + g_return_val_if_fail (p != NULL, FALSE); + priv->permissions = g_slist_append (priv->permissions, p); + + return TRUE; +} + +/** + * nm_setting_connection_remove_permission: + * @setting: the #NMSettingConnection + * @idx: the zero-based index of the permission to remove + * + * Removes the permission at index @idx from the connection. + */ +void +nm_setting_connection_remove_permission (NMSettingConnection *setting, + guint32 idx) +{ + NMSettingConnectionPrivate *priv; + GSList *iter; + + g_return_if_fail (NM_IS_SETTING_CONNECTION (setting)); + + priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); + iter = g_slist_nth (priv->permissions, idx); + g_return_if_fail (iter != NULL); + + permission_free ((Permission *) iter->data); + priv->permissions = g_slist_delete_link (priv->permissions, iter); +} + + /** * nm_setting_connection_get_autoconnect: * @setting: the #NMSettingConnection @@ -308,13 +576,30 @@ finalize (GObject *object) g_free (priv->id); g_free (priv->uuid); g_free (priv->type); + nm_utils_slist_free (priv->permissions, (GDestroyNotify) permission_free); G_OBJECT_CLASS (nm_setting_connection_parent_class)->finalize (object); } +static GSList * +perm_stringlist_to_permlist (GSList *strlist) +{ + GSList *list = NULL, *iter; + + for (iter = strlist; iter; iter = g_slist_next (iter)) { + Permission *p; + + p = permission_new_from_str ((const char *) iter->data); + if (p) + list = g_slist_append (list, p); + } + + return list; +} + static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (object); @@ -331,6 +616,10 @@ set_property (GObject *object, guint prop_id, g_free (priv->type); priv->type = g_value_dup_string (value); break; + case PROP_PERMISSIONS: + nm_utils_slist_free (priv->permissions, (GDestroyNotify) permission_free); + priv->permissions = perm_stringlist_to_permlist (g_value_get_boxed (value)); + break; case PROP_AUTOCONNECT: priv->autoconnect = g_value_get_boolean (value); break; @@ -346,11 +635,22 @@ set_property (GObject *object, guint prop_id, } } +static GSList * +perm_permlist_to_stringlist (GSList *permlist) +{ + GSList *list = NULL, *iter; + + for (iter = permlist; iter; iter = g_slist_next (iter)) + list = g_slist_append (list, permission_to_string ((Permission *) iter->data)); + return list; +} + static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMSettingConnection *setting = NM_SETTING_CONNECTION (object); + NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); switch (prop_id) { case PROP_ID: @@ -362,6 +662,9 @@ get_property (GObject *object, guint prop_id, case PROP_TYPE: g_value_set_string (value, nm_setting_connection_get_connection_type (setting)); break; + case PROP_PERMISSIONS: + g_value_take_boxed (value, perm_permlist_to_stringlist (priv->permissions)); + break; case PROP_AUTOCONNECT: g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting)); break; @@ -465,6 +768,45 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); /** + * NMSettingConnection:permissions: + * + * An array of strings defining what access a given user has to this + * connection. If this is NULL or empty, all users are allowed to access + * this connection. Otherwise a user is allowed to access this connection + * if and only if they are in this list. Each entry is of the form + * "[type]:[id]:[reserved]", for example: + * + * user:dcbw:blah + * + * At this time only the 'user' [type] is allowed. Any other values are + * ignored and reserved for future use. [id] is the username that this + * permission refers to, which may not contain the ':' character. Any + * [reserved] information present must be ignored and is reserved for + * future use. All of [type], [id], and [reserved] must be valid UTF-8. + */ + g_object_class_install_property + (object_class, PROP_PERMISSIONS, + _nm_param_spec_specialized (NM_SETTING_CONNECTION_PERMISSIONS, + "Permissions", + "An array of strings defining what access a given " + "user has to this connection. If this is NULL or " + "empty, all users are allowed to access this " + "connection. Otherwise a user is allowed to access " + "this connection if and only if they are in this " + "array. Each entry is of the form " + "\"[type]:[id]:[reserved]\", for example: " + "\"user:dcbw:blah\" At this time only the 'user' " + "[type] is allowed. Any other values are ignored and " + "reserved for future use. [id] is the username that " + "this permission refers to, which may not contain the " + "':' character. Any [reserved] information (if " + "present) must be ignored and is reserved for future " + "use. All of [type], [id], and [reserved] must be " + "valid UTF-8.", + DBUS_TYPE_G_LIST_OF_STRING, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** * NMSettingConnection:autoconnect: * * Whether or not the connection should be automatically connected by |