mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-04 12:00:16 +01:00
2003-03-23 Havoc Pennington <hp@pobox.com>
* bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny policies code * dbus/dbus-hash.h: add ULONG hash keys * dbus/dbus-sysdeps.c (_dbus_get_groups): new (_dbus_get_group_id): new function
This commit is contained in:
parent
b6ffea177f
commit
a26607ab68
15 changed files with 796 additions and 75 deletions
10
ChangeLog
10
ChangeLog
|
|
@ -1,3 +1,13 @@
|
|||
2003-03-23 Havoc Pennington <hp@pobox.com>
|
||||
|
||||
* bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny
|
||||
policies code
|
||||
|
||||
* dbus/dbus-hash.h: add ULONG hash keys
|
||||
|
||||
* dbus/dbus-sysdeps.c (_dbus_get_groups): new
|
||||
(_dbus_get_group_id): new function
|
||||
|
||||
2003-03-20 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* dbus/dbus-connection.c (dbus_connection_set_unix_user_function):
|
||||
|
|
|
|||
205
bus/bus.c
205
bus/bus.c
|
|
@ -41,7 +41,7 @@ struct BusContext
|
|||
BusActivation *activation;
|
||||
BusRegistry *registry;
|
||||
DBusList *default_rules; /**< Default policy rules */
|
||||
DBusList *override_rules; /**< Override policy rules */
|
||||
DBusList *mandatory_rules; /**< Mandatory policy rules */
|
||||
DBusHashTable *rules_by_uid; /**< per-UID policy rules */
|
||||
DBusHashTable *rules_by_gid; /**< per-GID policy rules */
|
||||
};
|
||||
|
|
@ -117,13 +117,26 @@ new_connection_callback (DBusServer *server,
|
|||
}
|
||||
|
||||
static void
|
||||
free_rule_func (void *data)
|
||||
free_rule_func (void *data,
|
||||
void *user_data)
|
||||
{
|
||||
BusPolicyRule *rule = data;
|
||||
|
||||
bus_policy_rule_unref (rule);
|
||||
}
|
||||
|
||||
static void
|
||||
free_rule_list_func (void *data)
|
||||
{
|
||||
DBusList **list = data;
|
||||
|
||||
_dbus_list_foreach (list, free_rule_func, NULL);
|
||||
|
||||
_dbus_list_clear (list);
|
||||
|
||||
dbus_free (list);
|
||||
}
|
||||
|
||||
BusContext*
|
||||
bus_context_new (const char *address,
|
||||
const char **service_dirs,
|
||||
|
|
@ -179,18 +192,18 @@ bus_context_new (const char *address,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_INT,
|
||||
context->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG,
|
||||
NULL,
|
||||
free_rule_func);
|
||||
free_rule_list_func);
|
||||
if (context->rules_by_uid == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_INT,
|
||||
context->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG,
|
||||
NULL,
|
||||
free_rule_func);
|
||||
free_rule_list_func);
|
||||
if (context->rules_by_gid == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
|
|
@ -328,3 +341,183 @@ bus_context_get_activation (BusContext *context)
|
|||
{
|
||||
return context->activation;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
list_allows_user (dbus_bool_t def,
|
||||
DBusList **list,
|
||||
unsigned long uid,
|
||||
const unsigned long *group_ids,
|
||||
int n_group_ids)
|
||||
{
|
||||
DBusList *link;
|
||||
dbus_bool_t allowed;
|
||||
|
||||
allowed = def;
|
||||
|
||||
link = _dbus_list_get_first_link (list);
|
||||
while (link != NULL)
|
||||
{
|
||||
BusPolicyRule *rule = link->data;
|
||||
link = _dbus_list_get_next_link (list, link);
|
||||
|
||||
if (rule->type == BUS_POLICY_RULE_USER)
|
||||
{
|
||||
if (rule->d.user.uid != uid)
|
||||
continue;
|
||||
}
|
||||
else if (rule->type == BUS_POLICY_RULE_GROUP)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < n_group_ids)
|
||||
{
|
||||
if (rule->d.group.gid == group_ids[i])
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i == n_group_ids)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
allowed = rule->allow;
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid)
|
||||
{
|
||||
dbus_bool_t allowed;
|
||||
unsigned long *group_ids;
|
||||
int n_group_ids;
|
||||
|
||||
/* On OOM or error we always reject the user */
|
||||
if (!_dbus_get_groups (uid, &group_ids, &n_group_ids))
|
||||
{
|
||||
_dbus_verbose ("Did not get any groups for UID %lu\n",
|
||||
uid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
allowed = FALSE;
|
||||
|
||||
allowed = list_allows_user (allowed,
|
||||
&context->default_rules,
|
||||
uid,
|
||||
group_ids, n_group_ids);
|
||||
|
||||
allowed = list_allows_user (allowed,
|
||||
&context->mandatory_rules,
|
||||
uid,
|
||||
group_ids, n_group_ids);
|
||||
|
||||
dbus_free (group_ids);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
add_list_to_policy (DBusList **list,
|
||||
BusPolicy *policy)
|
||||
{
|
||||
DBusList *link;
|
||||
|
||||
link = _dbus_list_get_first_link (list);
|
||||
while (link != NULL)
|
||||
{
|
||||
BusPolicyRule *rule = link->data;
|
||||
link = _dbus_list_get_next_link (list, link);
|
||||
|
||||
switch (rule->type)
|
||||
{
|
||||
case BUS_POLICY_RULE_USER:
|
||||
case BUS_POLICY_RULE_GROUP:
|
||||
/* These aren't per-connection policies */
|
||||
break;
|
||||
|
||||
case BUS_POLICY_RULE_OWN:
|
||||
case BUS_POLICY_RULE_SEND:
|
||||
case BUS_POLICY_RULE_RECEIVE:
|
||||
/* These are per-connection */
|
||||
if (!bus_policy_append_rule (policy, rule))
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BusPolicy*
|
||||
bus_context_create_connection_policy (BusContext *context,
|
||||
DBusConnection *connection)
|
||||
{
|
||||
BusPolicy *policy;
|
||||
unsigned long uid;
|
||||
DBusList **list;
|
||||
|
||||
_dbus_assert (dbus_connection_get_is_authenticated (connection));
|
||||
|
||||
policy = bus_policy_new ();
|
||||
if (policy == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!add_list_to_policy (&context->default_rules,
|
||||
policy))
|
||||
goto failed;
|
||||
|
||||
/* we avoid the overhead of looking up user's groups
|
||||
* if we don't have any group rules anyway
|
||||
*/
|
||||
if (_dbus_hash_table_get_n_entries (context->rules_by_gid) > 0)
|
||||
{
|
||||
const unsigned long *groups;
|
||||
int n_groups;
|
||||
int i;
|
||||
|
||||
if (!bus_connection_get_groups (connection, &groups, &n_groups))
|
||||
goto failed;
|
||||
|
||||
i = 0;
|
||||
while (i < n_groups)
|
||||
{
|
||||
list = _dbus_hash_table_lookup_ulong (context->rules_by_gid,
|
||||
groups[i]);
|
||||
|
||||
if (list != NULL)
|
||||
{
|
||||
if (!add_list_to_policy (list, policy))
|
||||
goto failed;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dbus_connection_get_unix_user (connection, &uid))
|
||||
goto failed;
|
||||
|
||||
list = _dbus_hash_table_lookup_ulong (context->rules_by_uid,
|
||||
uid);
|
||||
|
||||
if (!add_list_to_policy (list, policy))
|
||||
goto failed;
|
||||
|
||||
if (!add_list_to_policy (&context->mandatory_rules,
|
||||
policy))
|
||||
goto failed;
|
||||
|
||||
bus_policy_optimize (policy);
|
||||
|
||||
return policy;
|
||||
|
||||
failed:
|
||||
bus_policy_unref (policy);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
24
bus/bus.h
24
bus/bus.h
|
|
@ -32,19 +32,25 @@
|
|||
typedef struct BusActivation BusActivation;
|
||||
typedef struct BusConnections BusConnections;
|
||||
typedef struct BusContext BusContext;
|
||||
typedef struct BusPolicy BusPolicy;
|
||||
typedef struct BusPolicyRule BusPolicyRule;
|
||||
typedef struct BusRegistry BusRegistry;
|
||||
typedef struct BusService BusService;
|
||||
typedef struct BusTransaction BusTransaction;
|
||||
|
||||
BusContext* bus_context_new (const char *address,
|
||||
const char **service_dirs,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
BusContext* bus_context_new (const char *address,
|
||||
const char **service_dirs,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
dbus_bool_t bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid);
|
||||
BusPolicy* bus_context_create_connection_policy (BusContext *context,
|
||||
DBusConnection *connection);
|
||||
|
||||
|
||||
#endif /* BUS_BUS_H */
|
||||
|
|
|
|||
123
bus/connection.c
123
bus/connection.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "connection.h"
|
||||
#include "dispatch.h"
|
||||
#include "loop.h"
|
||||
#include "policy.h"
|
||||
#include "services.h"
|
||||
#include "utils.h"
|
||||
#include <dbus/dbus-list.h>
|
||||
|
|
@ -48,6 +49,9 @@ typedef struct
|
|||
DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
|
||||
DBusMessage *oom_message;
|
||||
DBusPreallocatedSend *oom_preallocated;
|
||||
unsigned long *group_ids;
|
||||
int n_group_ids;
|
||||
BusPolicy *policy;
|
||||
} BusConnectionData;
|
||||
|
||||
#define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
|
||||
|
|
@ -231,6 +235,20 @@ remove_connection_timeout (DBusTimeout *timeout,
|
|||
bus_loop_remove_timeout (timeout, connection_timeout_callback, connection);
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
allow_user_function (DBusConnection *connection,
|
||||
unsigned long uid,
|
||||
void *data)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
return bus_context_allow_user (d->connections->context, uid);
|
||||
}
|
||||
|
||||
static void
|
||||
free_connection_data (void *data)
|
||||
{
|
||||
|
|
@ -246,6 +264,11 @@ free_connection_data (void *data)
|
|||
|
||||
if (d->oom_message)
|
||||
dbus_message_unref (d->oom_message);
|
||||
|
||||
if (d->policy)
|
||||
bus_policy_unref (d->policy);
|
||||
|
||||
dbus_free (d->group_ids);
|
||||
|
||||
dbus_free (d->name);
|
||||
|
||||
|
|
@ -333,6 +356,9 @@ bus_connections_setup_connection (BusConnections *connections,
|
|||
}
|
||||
|
||||
retval = FALSE;
|
||||
|
||||
d->n_group_ids = 0;
|
||||
d->group_ids = NULL;
|
||||
|
||||
if (!dbus_connection_set_watch_functions (connection,
|
||||
(DBusAddWatchFunction) add_connection_watch,
|
||||
|
|
@ -387,6 +413,103 @@ bus_connections_setup_connection (BusConnections *connections,
|
|||
return retval;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_connection_get_groups (DBusConnection *connection,
|
||||
const unsigned long **groups,
|
||||
int *n_groups)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
*groups = NULL;
|
||||
*n_groups = 0;
|
||||
|
||||
/* we do a lazy lookup on groups a user is in for two reasons:
|
||||
* 1) we can't do it on connection setup since the user
|
||||
* hasn't authenticated and 2) it might be expensive
|
||||
* and we don't need to do it if there are no group-based
|
||||
* rules in the config file
|
||||
*/
|
||||
|
||||
if (d->n_group_ids == 0)
|
||||
{
|
||||
unsigned long uid;
|
||||
|
||||
if (dbus_connection_get_unix_user (connection, &uid))
|
||||
{
|
||||
if (!_dbus_get_groups (uid, &d->group_ids, &d->n_group_ids))
|
||||
{
|
||||
_dbus_verbose ("Did not get any groups for UID %lu\n",
|
||||
uid);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*groups = d->group_ids;
|
||||
*n_groups = d->n_group_ids;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_connection_is_in_group (DBusConnection *connection,
|
||||
unsigned long gid)
|
||||
{
|
||||
int i;
|
||||
const unsigned long *group_ids;
|
||||
int n_group_ids;
|
||||
|
||||
if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids))
|
||||
return FALSE;
|
||||
|
||||
i = 0;
|
||||
while (i < n_group_ids)
|
||||
{
|
||||
if (group_ids[i] == gid)
|
||||
return TRUE;
|
||||
++i;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BusPolicy*
|
||||
bus_connection_get_policy (DBusConnection *connection)
|
||||
{
|
||||
BusConnectionData *d;
|
||||
|
||||
d = BUS_CONNECTION_DATA (connection);
|
||||
|
||||
_dbus_assert (d != NULL);
|
||||
|
||||
if (!dbus_connection_get_is_authenticated (connection))
|
||||
{
|
||||
_dbus_verbose ("Tried to get policy for unauthenticated connection!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We do lazy creation of the policy because
|
||||
* it can only be done post-authentication.
|
||||
*/
|
||||
if (d->policy == NULL)
|
||||
{
|
||||
d->policy =
|
||||
bus_context_create_connection_policy (d->connections->context,
|
||||
connection);
|
||||
|
||||
/* we may have a NULL policy on OOM or error getting list of
|
||||
* groups for a user. In the latter case we don't handle it so
|
||||
* well currently, just keep pretending we're out of memory,
|
||||
* which is kind of bizarre.
|
||||
*/
|
||||
}
|
||||
|
||||
return d->policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls function on each connection; if the function returns
|
||||
|
|
|
|||
|
|
@ -66,6 +66,13 @@ const char *bus_connection_get_name (DBusConnection *connection);
|
|||
/* called by dispatch.c when the connection is dropped */
|
||||
void bus_connection_disconnected (DBusConnection *connection);
|
||||
|
||||
dbus_bool_t bus_connection_is_in_group (DBusConnection *connection,
|
||||
unsigned long gid);
|
||||
dbus_bool_t bus_connection_get_groups (DBusConnection *connection,
|
||||
const unsigned long **groups,
|
||||
int *n_groups);
|
||||
BusPolicy* bus_connection_get_policy (DBusConnection *connection);
|
||||
|
||||
/* transaction API so we can send or not send a block of messages as a whole */
|
||||
BusTransaction* bus_transaction_new (BusContext *context);
|
||||
BusContext* bus_transaction_get_context (BusTransaction *transaction);
|
||||
|
|
|
|||
20
bus/policy.c
20
bus/policy.c
|
|
@ -156,7 +156,7 @@ remove_rules_by_type_up_to (BusPolicy *policy,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
bus_policy_optimize (BusPolicy *policy)
|
||||
{
|
||||
DBusList *link;
|
||||
|
|
@ -175,6 +175,9 @@ bus_policy_optimize (BusPolicy *policy)
|
|||
* file.
|
||||
*/
|
||||
|
||||
_dbus_verbose ("Optimizing policy with %d rules\n",
|
||||
_dbus_list_get_length (&policy->rules));
|
||||
|
||||
link = _dbus_list_get_first (&policy->rules);
|
||||
while (link != NULL)
|
||||
{
|
||||
|
|
@ -208,6 +211,21 @@ bus_policy_optimize (BusPolicy *policy)
|
|||
|
||||
link = next;
|
||||
}
|
||||
|
||||
_dbus_verbose ("After optimization, policy has %d rules\n",
|
||||
_dbus_list_get_length (&policy->rules));
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_policy_append_rule (BusPolicy *policy,
|
||||
BusPolicyRule *rule)
|
||||
{
|
||||
if (!_dbus_list_append (policy->rules, rule))
|
||||
return FALSE;
|
||||
|
||||
bus_policy_rule_ref (rule);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
|
|
|
|||
24
bus/policy.h
24
bus/policy.h
|
|
@ -28,14 +28,13 @@
|
|||
#include <dbus/dbus-string.h>
|
||||
#include "bus.h"
|
||||
|
||||
typedef struct BusPolicy BusPolicy;
|
||||
typedef struct BusPolicyRule BusPolicyRule;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BUS_POLICY_RULE_SEND,
|
||||
BUS_POLICY_RULE_RECEIVE,
|
||||
BUS_POLICY_RULE_OWN
|
||||
BUS_POLICY_RULE_OWN,
|
||||
BUS_POLICY_RULE_USER,
|
||||
BUS_POLICY_RULE_GROUP
|
||||
} BusPolicyRuleType;
|
||||
|
||||
struct BusPolicyRule
|
||||
|
|
@ -68,6 +67,18 @@ struct BusPolicyRule
|
|||
char *service_name;
|
||||
} own;
|
||||
|
||||
struct
|
||||
{
|
||||
char *user;
|
||||
unsigned long uid;
|
||||
} user;
|
||||
|
||||
struct
|
||||
{
|
||||
char *group;
|
||||
unsigned long gid;
|
||||
} group;
|
||||
|
||||
} d;
|
||||
};
|
||||
|
||||
|
|
@ -90,7 +101,8 @@ dbus_bool_t bus_policy_check_can_receive (BusPolicy *policy,
|
|||
dbus_bool_t bus_policy_check_can_own (BusPolicy *policy,
|
||||
DBusConnection *connection,
|
||||
const DBusString *service_name);
|
||||
|
||||
|
||||
dbus_bool_t bus_policy_append_rule (BusPolicy *policy,
|
||||
BusPolicyRule *rule);
|
||||
void bus_policy_optimize (BusPolicy *policy);
|
||||
|
||||
#endif /* BUS_POLICY_H */
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ AC_C_BIGENDIAN
|
|||
AC_CHECK_LIB(socket,socket)
|
||||
AC_CHECK_LIB(nsl,gethostbyname)
|
||||
|
||||
AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep poll setenv socketpair)
|
||||
AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep poll setenv socketpair getgrouplist)
|
||||
|
||||
AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
|
||||
|
||||
|
|
|
|||
|
|
@ -2214,6 +2214,8 @@ dbus_connection_handle_watch (DBusConnection *connection,
|
|||
* Gets the UNIX user ID of the connection if any.
|
||||
* Returns #TRUE if the uid is filled in.
|
||||
* Always returns #FALSE on non-UNIX platforms.
|
||||
* Always returns #FALSE prior to authenticating the
|
||||
* connection.
|
||||
*
|
||||
* @param connection the connection
|
||||
* @param uid return location for the user ID
|
||||
|
|
@ -2226,8 +2228,12 @@ dbus_connection_get_unix_user (DBusConnection *connection,
|
|||
dbus_bool_t result;
|
||||
|
||||
dbus_mutex_lock (connection->mutex);
|
||||
result = _dbus_transport_get_unix_user (connection->transport,
|
||||
uid);
|
||||
|
||||
if (!_dbus_transport_get_is_authenticated (connection->transport))
|
||||
result = FALSE;
|
||||
else
|
||||
result = _dbus_transport_get_unix_user (connection->transport,
|
||||
uid);
|
||||
dbus_mutex_unlock (connection->mutex);
|
||||
|
||||
return result;
|
||||
|
|
|
|||
143
dbus/dbus-hash.c
143
dbus/dbus-hash.c
|
|
@ -313,6 +313,7 @@ _dbus_hash_table_new (DBusHashType type,
|
|||
{
|
||||
case DBUS_HASH_INT:
|
||||
case DBUS_HASH_POINTER:
|
||||
case DBUS_HASH_ULONG:
|
||||
table->find_function = find_direct_function;
|
||||
break;
|
||||
case DBUS_HASH_STRING:
|
||||
|
|
@ -642,6 +643,25 @@ _dbus_hash_iter_get_int_key (DBusHashIter *iter)
|
|||
return _DBUS_POINTER_TO_INT (real->entry->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for the current entry.
|
||||
* Only works for hash tables of type #DBUS_HASH_ULONG.
|
||||
*
|
||||
* @param iter the hash table iterator.
|
||||
*/
|
||||
unsigned long
|
||||
_dbus_hash_iter_get_ulong_key (DBusHashIter *iter)
|
||||
{
|
||||
DBusRealHashIter *real;
|
||||
|
||||
real = (DBusRealHashIter*) iter;
|
||||
|
||||
_dbus_assert (real->table != NULL);
|
||||
_dbus_assert (real->entry != NULL);
|
||||
|
||||
return (unsigned long) real->entry->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for the current entry.
|
||||
* Only works for hash tables of type #DBUS_HASH_STRING
|
||||
|
|
@ -963,6 +983,7 @@ rebuild_table (DBusHashTable *table)
|
|||
idx = string_hash (entry->key) & table->mask;
|
||||
break;
|
||||
case DBUS_HASH_INT:
|
||||
case DBUS_HASH_ULONG:
|
||||
case DBUS_HASH_POINTER:
|
||||
idx = RANDOM_INDEX (table, entry->key);
|
||||
break;
|
||||
|
|
@ -1059,6 +1080,31 @@ _dbus_hash_table_lookup_pointer (DBusHashTable *table,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the value for a given integer in a hash table
|
||||
* of type #DBUS_HASH_ULONG. Returns %NULL if the value
|
||||
* is not present. (A not-present entry is indistinguishable
|
||||
* from an entry with a value of %NULL.)
|
||||
* @param table the hash table.
|
||||
* @param key the integer to look up.
|
||||
* @returns the value of the hash entry.
|
||||
*/
|
||||
void*
|
||||
_dbus_hash_table_lookup_ulong (DBusHashTable *table,
|
||||
unsigned long key)
|
||||
{
|
||||
DBusHashEntry *entry;
|
||||
|
||||
_dbus_assert (table->key_type == DBUS_HASH_ULONG);
|
||||
|
||||
entry = (* table->find_function) (table, (void*) key, FALSE, NULL);
|
||||
|
||||
if (entry)
|
||||
return entry->value;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the hash entry for the given key. If no hash entry
|
||||
* for the key exists, does nothing.
|
||||
|
|
@ -1144,6 +1190,34 @@ _dbus_hash_table_remove_pointer (DBusHashTable *table,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the hash entry for the given key. If no hash entry
|
||||
* for the key exists, does nothing.
|
||||
*
|
||||
* @param table the hash table.
|
||||
* @param key the hash key.
|
||||
* @returns #TRUE if the entry existed
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_hash_table_remove_ulong (DBusHashTable *table,
|
||||
unsigned long key)
|
||||
{
|
||||
DBusHashEntry *entry;
|
||||
DBusHashEntry **bucket;
|
||||
|
||||
_dbus_assert (table->key_type == DBUS_HASH_ULONG);
|
||||
|
||||
entry = (* table->find_function) (table, (void*) key, FALSE, &bucket);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
remove_entry (table, bucket, entry);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hash entry with the given key and value.
|
||||
* The key and value are not copied; they are stored
|
||||
|
|
@ -1267,6 +1341,48 @@ _dbus_hash_table_insert_pointer (DBusHashTable *table,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a hash entry with the given key and value.
|
||||
* The key and value are not copied; they are stored
|
||||
* in the hash table by reference. If an entry with the
|
||||
* given key already exists, the previous key and value
|
||||
* are overwritten (and freed if the hash table has
|
||||
* a key_free_function and/or value_free_function).
|
||||
*
|
||||
* Returns #FALSE if memory for the new hash entry
|
||||
* can't be allocated.
|
||||
*
|
||||
* @param table the hash table.
|
||||
* @param key the hash entry key.
|
||||
* @param value the hash entry value.
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_hash_table_insert_ulong (DBusHashTable *table,
|
||||
unsigned long key,
|
||||
void *value)
|
||||
{
|
||||
DBusHashEntry *entry;
|
||||
|
||||
_dbus_assert (table->key_type == DBUS_HASH_ULONG);
|
||||
|
||||
entry = (* table->find_function) (table, (void*) key, TRUE, NULL);
|
||||
|
||||
if (entry == NULL)
|
||||
return FALSE; /* no memory */
|
||||
|
||||
if (table->free_key_function && entry->key != (void*) key)
|
||||
(* table->free_key_function) (entry->key);
|
||||
|
||||
if (table->free_value_function && entry->value != value)
|
||||
(* table->free_value_function) (entry->value);
|
||||
|
||||
entry->key = (void*) key;
|
||||
entry->value = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of hash entries in a hash table.
|
||||
*
|
||||
|
|
@ -1316,6 +1432,7 @@ _dbus_hash_test (void)
|
|||
int i;
|
||||
DBusHashTable *table1;
|
||||
DBusHashTable *table2;
|
||||
DBusHashTable *table3;
|
||||
DBusHashIter iter;
|
||||
#define N_HASH_KEYS 5000
|
||||
char **keys;
|
||||
|
|
@ -1352,6 +1469,11 @@ _dbus_hash_test (void)
|
|||
if (table2 == NULL)
|
||||
goto out;
|
||||
|
||||
table3 = _dbus_hash_table_new (DBUS_HASH_ULONG,
|
||||
NULL, dbus_free);
|
||||
if (table3 == NULL)
|
||||
goto out;
|
||||
|
||||
/* Insert and remove a bunch of stuff, counting the table in between
|
||||
* to be sure it's not broken and that iteration works
|
||||
*/
|
||||
|
|
@ -1379,9 +1501,18 @@ _dbus_hash_test (void)
|
|||
if (!_dbus_hash_table_insert_int (table2,
|
||||
i, value))
|
||||
goto out;
|
||||
|
||||
value = _dbus_strdup (keys[i]);
|
||||
if (value == NULL)
|
||||
goto out;
|
||||
|
||||
if (!_dbus_hash_table_insert_ulong (table3,
|
||||
i, value))
|
||||
goto out;
|
||||
|
||||
_dbus_assert (count_entries (table1) == i + 1);
|
||||
_dbus_assert (count_entries (table2) == i + 1);
|
||||
_dbus_assert (count_entries (table3) == i + 1);
|
||||
|
||||
value = _dbus_hash_table_lookup_string (table1, keys[i]);
|
||||
_dbus_assert (value != NULL);
|
||||
|
|
@ -1390,6 +1521,10 @@ _dbus_hash_test (void)
|
|||
value = _dbus_hash_table_lookup_int (table2, i);
|
||||
_dbus_assert (value != NULL);
|
||||
_dbus_assert (strcmp (value, keys[i]) == 0);
|
||||
|
||||
value = _dbus_hash_table_lookup_ulong (table3, i);
|
||||
_dbus_assert (value != NULL);
|
||||
_dbus_assert (strcmp (value, keys[i]) == 0);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
|
@ -1402,19 +1537,25 @@ _dbus_hash_test (void)
|
|||
|
||||
_dbus_hash_table_remove_int (table2, i);
|
||||
|
||||
_dbus_hash_table_remove_ulong (table3, i);
|
||||
|
||||
_dbus_assert (count_entries (table1) == i);
|
||||
_dbus_assert (count_entries (table2) == i);
|
||||
_dbus_assert (count_entries (table3) == i);
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
_dbus_hash_table_ref (table1);
|
||||
_dbus_hash_table_ref (table2);
|
||||
_dbus_hash_table_ref (table3);
|
||||
_dbus_hash_table_unref (table1);
|
||||
_dbus_hash_table_unref (table2);
|
||||
_dbus_hash_table_unref (table3);
|
||||
_dbus_hash_table_unref (table1);
|
||||
_dbus_hash_table_unref (table2);
|
||||
|
||||
_dbus_hash_table_unref (table3);
|
||||
table3 = NULL;
|
||||
|
||||
/* Insert a bunch of stuff then check
|
||||
* that iteration works correctly (finds the right
|
||||
|
|
|
|||
|
|
@ -52,53 +52,61 @@ typedef struct DBusHashIter DBusHashIter;
|
|||
*/
|
||||
typedef enum
|
||||
{
|
||||
DBUS_HASH_STRING, /**< Hash keys are strings. */
|
||||
DBUS_HASH_INT, /**< Hash keys are integers. */
|
||||
DBUS_HASH_POINTER /**< Hash keys are pointers. */
|
||||
DBUS_HASH_STRING, /**< Hash keys are strings. */
|
||||
DBUS_HASH_INT, /**< Hash keys are integers. */
|
||||
DBUS_HASH_POINTER, /**< Hash keys are pointers. */
|
||||
DBUS_HASH_ULONG /**< Hash keys are unsigned long. */
|
||||
} DBusHashType;
|
||||
|
||||
DBusHashTable* _dbus_hash_table_new (DBusHashType type,
|
||||
DBusFreeFunction key_free_function,
|
||||
DBusFreeFunction value_free_function);
|
||||
void _dbus_hash_table_ref (DBusHashTable *table);
|
||||
void _dbus_hash_table_unref (DBusHashTable *table);
|
||||
DBusHashTable* _dbus_hash_table_new (DBusHashType type,
|
||||
DBusFreeFunction key_free_function,
|
||||
DBusFreeFunction value_free_function);
|
||||
void _dbus_hash_table_ref (DBusHashTable *table);
|
||||
void _dbus_hash_table_unref (DBusHashTable *table);
|
||||
void _dbus_hash_iter_init (DBusHashTable *table,
|
||||
DBusHashIter *iter);
|
||||
dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter);
|
||||
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
|
||||
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
|
||||
void _dbus_hash_iter_set_value (DBusHashIter *iter,
|
||||
void *value);
|
||||
int _dbus_hash_iter_get_int_key (DBusHashIter *iter);
|
||||
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
|
||||
unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter);
|
||||
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashIter *iter);
|
||||
void* _dbus_hash_table_lookup_string (DBusHashTable *table,
|
||||
const char *key);
|
||||
void* _dbus_hash_table_lookup_int (DBusHashTable *table,
|
||||
int key);
|
||||
void* _dbus_hash_table_lookup_pointer (DBusHashTable *table,
|
||||
void *key);
|
||||
void* _dbus_hash_table_lookup_ulong (DBusHashTable *table,
|
||||
unsigned long key);
|
||||
dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table,
|
||||
const char *key);
|
||||
dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table,
|
||||
int key);
|
||||
dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table,
|
||||
void *key);
|
||||
dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table,
|
||||
unsigned long key);
|
||||
dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table,
|
||||
char *key,
|
||||
void *value);
|
||||
dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table,
|
||||
int key,
|
||||
void *value);
|
||||
dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table,
|
||||
void *key,
|
||||
void *value);
|
||||
dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table,
|
||||
unsigned long key,
|
||||
void *value);
|
||||
int _dbus_hash_table_get_n_entries (DBusHashTable *table);
|
||||
|
||||
void _dbus_hash_iter_init (DBusHashTable *table,
|
||||
DBusHashIter *iter);
|
||||
dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter);
|
||||
|
||||
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
|
||||
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
|
||||
void _dbus_hash_iter_set_value (DBusHashIter *iter,
|
||||
void *value);
|
||||
int _dbus_hash_iter_get_int_key (DBusHashIter *iter);
|
||||
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
|
||||
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashIter *iter);
|
||||
void* _dbus_hash_table_lookup_string (DBusHashTable *table,
|
||||
const char *key);
|
||||
void* _dbus_hash_table_lookup_int (DBusHashTable *table,
|
||||
int key);
|
||||
void* _dbus_hash_table_lookup_pointer (DBusHashTable *table,
|
||||
void *key);
|
||||
dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table,
|
||||
const char *key);
|
||||
dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table,
|
||||
int key);
|
||||
dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table,
|
||||
void *key);
|
||||
dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table,
|
||||
char *key,
|
||||
void *value);
|
||||
dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table,
|
||||
int key,
|
||||
void *value);
|
||||
dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table,
|
||||
void *key,
|
||||
void *value);
|
||||
int _dbus_hash_table_get_n_entries (DBusHashTable *table);
|
||||
|
||||
|
||||
DBUS_END_DECLS;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
#include <sys/uio.h>
|
||||
|
|
@ -1217,6 +1218,20 @@ _dbus_credentials_from_username (const DBusString *username,
|
|||
return get_user_info (username, -1, credentials, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the credentials corresponding to the given user ID.
|
||||
*
|
||||
* @param user_id the user ID
|
||||
* @param credentials credentials to fill in
|
||||
* @returns #TRUE if the username existed and we got some credentials
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_credentials_from_user_id (unsigned long user_id,
|
||||
DBusCredentials *credentials)
|
||||
{
|
||||
return get_user_info (NULL, user_id, credentials, NULL, NULL);
|
||||
}
|
||||
|
||||
static DBusMutex *user_info_lock = NULL;
|
||||
/**
|
||||
* Initializes the global mutex for the process's user information.
|
||||
|
|
@ -1398,6 +1413,174 @@ _dbus_credentials_match (const DBusCredentials *expected_credentials,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets group ID from group name.
|
||||
*
|
||||
* @param group_name name of the group
|
||||
* @param gid location to store group ID
|
||||
* @returns #TRUE if group was known
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_get_group_id (const DBusString *group_name,
|
||||
unsigned long *gid)
|
||||
{
|
||||
const char *group_c_str;
|
||||
|
||||
_dbus_string_get_const_data (group_name, &group_c_str);
|
||||
|
||||
/* For now assuming that the getgrnam() and getgrgid() flavors
|
||||
* always correspond to the pwnam flavors, if not we have
|
||||
* to add more configure checks.
|
||||
*/
|
||||
|
||||
#if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R)
|
||||
{
|
||||
struct group *g;
|
||||
int result;
|
||||
char buf[1024];
|
||||
struct group g_str;
|
||||
|
||||
g = NULL;
|
||||
#ifdef HAVE_POSIX_GETPWNAME_R
|
||||
|
||||
result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
|
||||
&g);
|
||||
#else
|
||||
p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
|
||||
result = 0;
|
||||
#endif /* !HAVE_POSIX_GETPWNAME_R */
|
||||
if (result == 0 && g == &g_str)
|
||||
{
|
||||
*gid = g->gr_gid;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus_verbose ("Group %s unknown\n", group_c_str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#else /* ! HAVE_GETPWNAM_R */
|
||||
{
|
||||
/* I guess we're screwed on thread safety here */
|
||||
struct group *g;
|
||||
|
||||
g = getgrnam (group_c_str);
|
||||
|
||||
if (g != NULL)
|
||||
{
|
||||
*gid = g->gr_gid;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus_verbose ("Group %s unknown\n", group_c_str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif /* ! HAVE_GETPWNAM_R */
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all groups for a particular user. Returns #FALSE
|
||||
* if no memory, or user isn't known, but always initializes
|
||||
* group_ids to a NULL array.
|
||||
*
|
||||
* @todo failing to distinguish "out of memory" from
|
||||
* "unknown user" is kind of bogus and would probably
|
||||
* result in a failure in a comprehensive test suite.
|
||||
*
|
||||
* @param uid the user ID
|
||||
* @param group_ids return location for array of group IDs
|
||||
* @param n_group_ids return location for length of returned array
|
||||
* @returns #TRUE on success
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_get_groups (unsigned long uid,
|
||||
unsigned long **group_ids,
|
||||
int *n_group_ids)
|
||||
{
|
||||
DBusCredentials creds;
|
||||
DBusString username;
|
||||
const char *username_c;
|
||||
dbus_bool_t retval;
|
||||
|
||||
*group_ids = NULL;
|
||||
*n_group_ids = 0;
|
||||
|
||||
retval = FALSE;
|
||||
|
||||
if (!_dbus_string_init (&username, _DBUS_INT_MAX))
|
||||
return FALSE;
|
||||
|
||||
if (!get_user_info (NULL, uid, &creds,
|
||||
NULL, &username) ||
|
||||
creds.gid < 0)
|
||||
goto out;
|
||||
|
||||
_dbus_string_get_const_data (&username, &username_c);
|
||||
|
||||
#ifdef HAVE_GETGROUPLIST
|
||||
{
|
||||
gid_t *buf;
|
||||
int buf_count;
|
||||
int i;
|
||||
|
||||
buf_count = 17;
|
||||
buf = dbus_new (gid_t, buf_count);
|
||||
if (buf == NULL)
|
||||
goto out;
|
||||
|
||||
if (getgrouplist (username_c,
|
||||
creds.gid,
|
||||
buf, &buf_count) < 0)
|
||||
{
|
||||
gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
|
||||
if (new == NULL)
|
||||
{
|
||||
dbus_free (buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = new;
|
||||
|
||||
getgrouplist (username_c, creds.gid, buf, &buf_count);
|
||||
}
|
||||
|
||||
*group_ids = dbus_new (unsigned long, buf_count);
|
||||
if (*group_ids == NULL)
|
||||
{
|
||||
dbus_free (buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < buf_count; ++i)
|
||||
(*group_ids)[i] = buf[i];
|
||||
|
||||
*n_group_ids = buf_count;
|
||||
|
||||
dbus_free (buf);
|
||||
}
|
||||
#else /* HAVE_GETGROUPLIST */
|
||||
{
|
||||
/* We just get the one group ID */
|
||||
*group_ids = dbus_new (unsigned long, 1);
|
||||
if (*group_ids == NULL)
|
||||
goto out;
|
||||
|
||||
*n_group_ids = 1;
|
||||
|
||||
(*group_ids)[0] = creds.gid;
|
||||
}
|
||||
#endif /* HAVE_GETGROUPLIST */
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
out:
|
||||
_dbus_string_free (&username);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the uid of the current process to the given string.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ dbus_bool_t _dbus_send_credentials_unix_socket (int server_fd,
|
|||
|
||||
dbus_bool_t _dbus_credentials_from_username (const DBusString *username,
|
||||
DBusCredentials *credentials);
|
||||
dbus_bool_t _dbus_credentials_from_user_id (unsigned long user_id,
|
||||
DBusCredentials *credentials);
|
||||
dbus_bool_t _dbus_credentials_from_uid_string (const DBusString *uid_str,
|
||||
DBusCredentials *credentials);
|
||||
void _dbus_credentials_from_current_process (DBusCredentials *credentials);
|
||||
|
|
@ -110,6 +112,12 @@ dbus_bool_t _dbus_user_info_from_current_process (const DBusString **userna
|
|||
const DBusString **homedir,
|
||||
const DBusCredentials **credentials);
|
||||
|
||||
dbus_bool_t _dbus_get_group_id (const DBusString *group_name,
|
||||
unsigned long *gid);
|
||||
dbus_bool_t _dbus_get_groups (unsigned long uid,
|
||||
unsigned long **group_ids,
|
||||
int *n_group_ids);
|
||||
|
||||
typedef int dbus_atomic_t;
|
||||
|
||||
dbus_atomic_t _dbus_atomic_inc (dbus_atomic_t *atomic);
|
||||
|
|
|
|||
|
|
@ -353,10 +353,12 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
|
|||
return TRUE;
|
||||
else
|
||||
{
|
||||
dbus_bool_t maybe_authenticated;
|
||||
|
||||
if (transport->disconnected)
|
||||
return FALSE;
|
||||
|
||||
transport->authenticated =
|
||||
maybe_authenticated =
|
||||
(!(transport->send_credentials_pending ||
|
||||
transport->receive_credentials_pending)) &&
|
||||
_dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED;
|
||||
|
|
@ -369,7 +371,7 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
|
|||
* Or they may give certain identities extra privileges.
|
||||
*/
|
||||
|
||||
if (transport->authenticated && transport->is_server)
|
||||
if (maybe_authenticated && transport->is_server)
|
||||
{
|
||||
DBusCredentials auth_identity;
|
||||
|
||||
|
|
@ -413,6 +415,8 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
transport->authenticated = maybe_authenticated;
|
||||
|
||||
return transport->authenticated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ Elements:
|
|||
multiple <auth> elements, the last one wins (they are not merged).
|
||||
|
||||
<policy>
|
||||
context="(default|required)" one of the context/user/group
|
||||
context="(default|mandatory)" one of the context/user/group
|
||||
attributes is mandatory
|
||||
user="username or userid"
|
||||
group="group name or gid"
|
||||
|
|
@ -72,8 +72,10 @@ Elements:
|
|||
Policies are applied to a connection as follows:
|
||||
- all context="default" policies are applied
|
||||
- all group="connection's user's group" policies are applied
|
||||
in undefined order
|
||||
- all user="connection's auth user" policies are applied
|
||||
- all context="required" policies are applied
|
||||
in undefined order
|
||||
- all context="mandatory" policies are applied
|
||||
|
||||
Policies applied later will override those applied earlier,
|
||||
when the policies overlap. Multiple policies with the same
|
||||
|
|
@ -157,4 +159,4 @@ Elements:
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue