2007-06-09 Havoc Pennington <hp@redhat.com>

* bus/policy.c (bus_policy_create_client_policy): gracefully
	continue if the connection has no unix user - just don't apply
	any unix user dependent rules.

	* bus/config-parser.c: remove dbus-userdb.h usage

	* bus/bus.c: remove dbus-userdb.h usage

	* dbus/dbus-transport.c (_dbus_transport_get_is_authenticated):
	support Windows user function; also, fix the logic for checking
	auth as root in the default auth code (broken in the previous
	commit)

	* dbus/dbus-connection.c
	(dbus_connection_set_windows_user_function): new function
	(dbus_connection_get_windows_user): new function
This commit is contained in:
Havoc Pennington 2007-06-09 23:41:33 +00:00
parent 2383267226
commit 7be5fd95cd
18 changed files with 646 additions and 194 deletions

View file

@ -1,3 +1,22 @@
2007-06-09 Havoc Pennington <hp@redhat.com>
* bus/policy.c (bus_policy_create_client_policy): gracefully
continue if the connection has no unix user - just don't apply
any unix user dependent rules.
* bus/config-parser.c: remove dbus-userdb.h usage
* bus/bus.c: remove dbus-userdb.h usage
* dbus/dbus-transport.c (_dbus_transport_get_is_authenticated):
support Windows user function; also, fix the logic for checking
auth as root in the default auth code (broken in the previous
commit)
* dbus/dbus-connection.c
(dbus_connection_set_windows_user_function): new function
(dbus_connection_get_windows_user): new function
2007-06-09 Havoc Pennington <hp@redhat.com>
* bus/dispatch.c (check_get_connection_unix_process_id): adapt

View file

@ -34,7 +34,6 @@
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-userdb.h>
struct BusContext
{
@ -794,7 +793,7 @@ bus_context_reload_config (BusContext *context,
dbus_bool_t ret;
/* Flush the user database cache */
_dbus_user_database_flush_system ();
_dbus_flush_caches ();
ret = FALSE;
_dbus_string_init_const (&config_file, context->config_file);
@ -995,11 +994,23 @@ bus_context_get_loop (BusContext *context)
}
dbus_bool_t
bus_context_allow_user (BusContext *context,
unsigned long uid)
bus_context_allow_unix_user (BusContext *context,
unsigned long uid)
{
return bus_policy_allow_user (context->policy,
uid);
return bus_policy_allow_unix_user (context->policy,
uid);
}
/* For now this is never actually called because the default
* DBusConnection behavior of 'same user that owns the bus can connect'
* is all it would do.
*/
dbus_bool_t
bus_context_allow_windows_user (BusContext *context,
const char *windows_sid)
{
return bus_policy_allow_windows_user (context->policy,
windows_sid);
}
BusPolicy *

View file

@ -85,8 +85,10 @@ BusConnections* bus_context_get_connections (BusContext
BusActivation* bus_context_get_activation (BusContext *context);
BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
DBusLoop* bus_context_get_loop (BusContext *context);
dbus_bool_t bus_context_allow_user (BusContext *context,
dbus_bool_t bus_context_allow_unix_user (BusContext *context,
unsigned long uid);
dbus_bool_t bus_context_allow_windows_user (BusContext *context,
const char *windows_sid);
BusPolicy* bus_context_get_policy (BusContext *context);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,

View file

@ -27,7 +27,6 @@
#include "selinux.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-userdb.h>
#include <string.h>
typedef enum
@ -983,8 +982,8 @@ start_busconfig_child (BusConfigParser *parser,
DBusString username;
_dbus_string_init_const (&username, user);
if (_dbus_get_user_id (&username,
&e->d.policy.gid_uid_or_at_console))
if (_dbus_parse_unix_user_from_config (&username,
&e->d.policy.gid_uid_or_at_console))
e->d.policy.type = POLICY_USER;
else
_dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
@ -995,8 +994,8 @@ start_busconfig_child (BusConfigParser *parser,
DBusString group_name;
_dbus_string_init_const (&group_name, group);
if (_dbus_get_group_id (&group_name,
&e->d.policy.gid_uid_or_at_console))
if (_dbus_parse_unix_group_from_config (&group_name,
&e->d.policy.gid_uid_or_at_console))
e->d.policy.type = POLICY_GROUP;
else
_dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
@ -1469,7 +1468,7 @@ append_rule_from_element (BusConfigParser *parser,
_dbus_string_init_const (&username, user);
if (_dbus_get_user_id (&username, &uid))
if (_dbus_parse_unix_user_from_config (&username, &uid))
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
if (rule == NULL)
@ -1501,7 +1500,7 @@ append_rule_from_element (BusConfigParser *parser,
_dbus_string_init_const (&groupname, group);
if (_dbus_get_user_id (&groupname, &gid))
if (_dbus_parse_unix_group_from_config (&groupname, &gid))
{
rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
if (rule == NULL)
@ -1571,7 +1570,7 @@ append_rule_from_element (BusConfigParser *parser,
case POLICY_CONSOLE:
if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
rule))
rule))
goto nomem;
break;
}

View file

@ -31,7 +31,6 @@
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-userdb.h>
static void bus_connection_remove_transactions (DBusConnection *connection);
@ -243,7 +242,9 @@ bus_connection_disconnected (DBusConnection *connection)
dbus_connection_set_unix_user_function (connection,
NULL, NULL, NULL);
dbus_connection_set_windows_user_function (connection,
NULL, NULL, NULL);
dbus_connection_set_dispatch_status_function (connection,
NULL, NULL, NULL);
@ -369,9 +370,9 @@ dispatch_status_function (DBusConnection *connection,
}
static dbus_bool_t
allow_user_function (DBusConnection *connection,
unsigned long uid,
void *data)
allow_unix_user_function (DBusConnection *connection,
unsigned long uid,
void *data)
{
BusConnectionData *d;
@ -379,7 +380,7 @@ allow_user_function (DBusConnection *connection,
_dbus_assert (d != NULL);
return bus_context_allow_user (d->connections->context, uid);
return bus_context_allow_unix_user (d->connections->context, uid);
}
static void
@ -597,9 +598,14 @@ bus_connections_setup_connection (BusConnections *connections,
NULL,
connection, NULL))
goto out;
/* For now we don't need to set a Windows user function because
* there are no policies in the config file controlling what
* Windows users can connect. The default 'same user that owns the
* bus can connect' behavior of DBusConnection is fine on Windows.
*/
dbus_connection_set_unix_user_function (connection,
allow_user_function,
allow_unix_user_function,
NULL, NULL);
dbus_connection_set_dispatch_status_function (connection,
@ -679,6 +685,9 @@ bus_connections_setup_connection (BusConnections *connections,
dbus_connection_set_unix_user_function (connection,
NULL, NULL, NULL);
dbus_connection_set_windows_user_function (connection,
NULL, NULL, NULL);
dbus_connection_set_dispatch_status_function (connection,
NULL, NULL, NULL);
@ -772,10 +781,10 @@ expire_incomplete_timeout (void *data)
}
dbus_bool_t
bus_connection_get_groups (DBusConnection *connection,
unsigned long **groups,
int *n_groups,
DBusError *error)
bus_connection_get_unix_groups (DBusConnection *connection,
unsigned long **groups,
int *n_groups,
DBusError *error)
{
BusConnectionData *d;
unsigned long uid;
@ -789,7 +798,7 @@ bus_connection_get_groups (DBusConnection *connection,
if (dbus_connection_get_unix_user (connection, &uid))
{
if (!_dbus_groups_from_uid (uid, groups, n_groups))
if (!_dbus_unix_groups_from_uid (uid, groups, n_groups))
{
_dbus_verbose ("Did not get any groups for UID %lu\n",
uid);
@ -807,15 +816,15 @@ bus_connection_get_groups (DBusConnection *connection,
}
dbus_bool_t
bus_connection_is_in_group (DBusConnection *connection,
unsigned long gid)
bus_connection_is_in_unix_group (DBusConnection *connection,
unsigned long gid)
{
int i;
unsigned long *group_ids;
int n_group_ids;
if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
NULL))
if (!bus_connection_get_unix_groups (connection, &group_ids, &n_group_ids,
NULL))
return FALSE;
i = 0;

View file

@ -105,12 +105,12 @@ dbus_bool_t bus_connection_complete (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,
unsigned long **groups,
int *n_groups,
DBusError *error);
dbus_bool_t bus_connection_is_in_unix_group (DBusConnection *connection,
unsigned long gid);
dbus_bool_t bus_connection_get_unix_groups (DBusConnection *connection,
unsigned long **groups,
int *n_groups,
DBusError *error);
BusClientPolicy* bus_connection_get_policy (DBusConnection *connection);
/* transaction API so we can send or not send a block of messages as a whole */

View file

@ -28,7 +28,6 @@
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
#include <dbus/dbus-userdb.h>
BusPolicyRule*
bus_policy_rule_new (BusPolicyRuleType type,
@ -296,7 +295,7 @@ bus_policy_create_client_policy (BusPolicy *policy,
int n_groups;
int i;
if (!bus_connection_get_groups (connection, &groups, &n_groups, error))
if (!bus_connection_get_unix_groups (connection, &groups, &n_groups, error))
goto failed;
i = 0;
@ -321,43 +320,39 @@ bus_policy_create_client_policy (BusPolicy *policy,
dbus_free (groups);
}
if (!dbus_connection_get_unix_user (connection, &uid))
if (dbus_connection_get_unix_user (connection, &uid))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"No user ID known for connection, cannot determine security policy\n");
goto failed;
}
if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
{
DBusList **list;
list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
uid);
if (list != NULL)
if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
{
if (!add_list_to_client (list, client))
DBusList **list;
list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
uid);
if (list != NULL)
{
if (!add_list_to_client (list, client))
goto nomem;
}
}
/* Add console rules */
at_console = _dbus_unix_user_is_at_console (uid, error);
if (at_console)
{
if (!add_list_to_client (&policy->at_console_true_rules, client))
goto nomem;
}
}
/* Add console rules */
at_console = _dbus_is_console_user (uid, error);
if (at_console)
{
if (!add_list_to_client (&policy->at_console_true_rules, client))
goto nomem;
}
else if (dbus_error_is_set (error) == TRUE)
{
goto failed;
}
else if (!add_list_to_client (&policy->at_console_false_rules, client))
{
goto nomem;
else if (dbus_error_is_set (error) == TRUE)
{
goto failed;
}
else if (!add_list_to_client (&policy->at_console_false_rules, client))
{
goto nomem;
}
}
if (!add_list_to_client (&policy->mandatory_rules,
@ -438,23 +433,23 @@ list_allows_user (dbus_bool_t def,
}
dbus_bool_t
bus_policy_allow_user (BusPolicy *policy,
unsigned long uid)
bus_policy_allow_unix_user (BusPolicy *policy,
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_groups_from_uid (uid, &group_ids, &n_group_ids))
if (!_dbus_unix_groups_from_uid (uid, &group_ids, &n_group_ids))
{
_dbus_verbose ("Did not get any groups for UID %lu\n",
uid);
return FALSE;
}
/* Default to "user owning bus" or root can connect */
allowed = uid == _dbus_getuid ();
/* Default to "user owning bus" can connect */
allowed = _dbus_unix_user_is_process_owner (uid);
allowed = list_allows_user (allowed,
&policy->default_rules,
@ -473,6 +468,23 @@ bus_policy_allow_user (BusPolicy *policy,
return allowed;
}
/* For now this is never actually called because the default
* DBusConnection behavior of 'same user that owns the bus can
* connect' is all it would do. Set the windows user function in
* connection.c if the config file ever supports doing something
* interesting here.
*/
dbus_bool_t
bus_policy_allow_windows_user (BusPolicy *policy,
const char *windows_sid)
{
/* Windows has no policies here since only the session bus
* is really used for now, so just checking that the
* connecting person is the same as the bus owner is fine.
*/
return _dbus_windows_user_is_process_owner (windows_sid);
}
dbus_bool_t
bus_policy_append_default_rule (BusPolicy *policy,
BusPolicyRule *rule)

View file

@ -113,8 +113,10 @@ void bus_policy_unref (BusPolicy *policy);
BusClientPolicy* bus_policy_create_client_policy (BusPolicy *policy,
DBusConnection *connection,
DBusError *error);
dbus_bool_t bus_policy_allow_user (BusPolicy *policy,
dbus_bool_t bus_policy_allow_unix_user (BusPolicy *policy,
unsigned long uid);
dbus_bool_t bus_policy_allow_windows_user (BusPolicy *policy,
const char *windows_sid);
dbus_bool_t bus_policy_append_default_rule (BusPolicy *policy,
BusPolicyRule *rule);
dbus_bool_t bus_policy_append_mandatory_rule (BusPolicy *policy,

View file

@ -4763,8 +4763,10 @@ dbus_connection_get_socket(DBusConnection *connection,
/**
* Gets the UNIX user ID of the connection if known. Returns #TRUE if
* the uid is filled in. Always returns #FALSE on non-UNIX platforms.
* Always returns #FALSE prior to authenticating the connection.
* the uid is filled in. Always returns #FALSE on non-UNIX platforms
* for now, though in theory someone could hook Windows to NIS or
* something. Always returns #FALSE prior to authenticating the
* connection.
*
* The UID is only read by servers from clients; clients can't usually
* get the UID of servers, because servers do not authenticate to
@ -4789,14 +4791,6 @@ dbus_connection_get_unix_user (DBusConnection *connection,
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (uid != NULL, FALSE);
#ifdef DBUS_WIN
/* FIXME this should be done at a lower level, but it's kind of hard,
* just want to be sure we don't ship with this API returning
* some weird internal fake uid for 1.0
*/
return FALSE;
#endif
CONNECTION_LOCK (connection);
@ -4805,6 +4799,11 @@ dbus_connection_get_unix_user (DBusConnection *connection,
else
result = _dbus_transport_get_unix_user (connection->transport,
uid);
#ifdef DBUS_WIN
_dbus_assert (!result);
#endif
CONNECTION_UNLOCK (connection);
return result;
@ -4812,7 +4811,7 @@ dbus_connection_get_unix_user (DBusConnection *connection,
/**
* Gets the process ID of the connection if any.
* Returns #TRUE if the uid is filled in.
* Returns #TRUE if the pid is filled in.
* Always returns #FALSE prior to authenticating the
* connection.
*
@ -4828,14 +4827,6 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (pid != NULL, FALSE);
#ifdef DBUS_WIN
/* FIXME this should be done at a lower level, but it's kind of hard,
* just want to be sure we don't ship with this API returning
* some weird internal fake uid for 1.0
*/
return FALSE;
#endif
CONNECTION_LOCK (connection);
@ -4844,6 +4835,10 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
else
result = _dbus_transport_get_unix_process_id (connection->transport,
pid);
#ifdef DBUS_WIN
_dbus_assert (!result);
#endif
CONNECTION_UNLOCK (connection);
return result;
@ -4858,14 +4853,13 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
*
* If the function is set to #NULL (as it is by default), then
* only the same UID as the server process will be allowed to
* connect.
* connect. Also, root is always allowed to connect.
*
* On Windows, the function will be set and its free_data_function will
* be invoked when the connection is freed or a new function is set.
* However, the function will never be called, because there are
* no UNIX user ids to pass to it.
*
* @todo add a Windows API analogous to dbus_connection_set_unix_user_function()
* no UNIX user ids to pass to it, or at least none of the existing
* auth protocols would allow authenticating as a UNIX user on Windows.
*
* @param connection the connection
* @param function the predicate
@ -4890,7 +4884,106 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
CONNECTION_UNLOCK (connection);
if (old_free_function != NULL)
(* old_free_function) (old_data);
(* old_free_function) (old_data);
}
/**
* Gets the Windows user SID of the connection if known. Returns
* #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
* platforms for now, though in theory someone could hook UNIX to
* Active Directory or something. Always returns #FALSE prior to
* authenticating the connection.
*
* The user is only read by servers from clients; clients can't usually
* get the user of servers, because servers do not authenticate to
* clients. The returned user is the user the connection authenticated
* as.
*
* The message bus is a server and the apps connecting to the bus
* are clients.
*
* The returned user string has to be freed with dbus_free().
*
* The return value indicates whether the user SID is available;
* if it's available but we don't have the memory to copy it,
* then the return value is #TRUE and #NULL is given as the SID.
*
* @todo We would like to be able to say "You can ask the bus to tell
* you the user of another connection though if you like; this is done
* with dbus_bus_get_windows_user()." But this has to be implemented
* in bus/driver.c and dbus/dbus-bus.c, and is pointless anyway
* since on Windows we only use the session bus for now.
*
* @param connection the connection
* @param windows_sid_p return location for an allocated copy of the user ID, or #NULL if no memory
* @returns #TRUE if user is available (returned value may be #NULL anyway if no memory)
*/
dbus_bool_t
dbus_connection_get_windows_user (DBusConnection *connection,
char **windows_sid_p)
{
dbus_bool_t result;
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (windows_sid_p != NULL, FALSE);
CONNECTION_LOCK (connection);
if (!_dbus_transport_get_is_authenticated (connection->transport))
result = FALSE;
else
result = _dbus_transport_get_windows_user (connection->transport,
windows_sid_p);
#ifdef DBUS_UNIX
_dbus_assert (!result);
#endif
CONNECTION_UNLOCK (connection);
return result;
}
/**
* Sets a predicate function used to determine whether a given user ID
* is allowed to connect. When an incoming connection has
* authenticated with a particular user ID, this function is called;
* if it returns #TRUE, the connection is allowed to proceed,
* otherwise the connection is disconnected.
*
* If the function is set to #NULL (as it is by default), then
* only the same user owning the server process will be allowed to
* connect.
*
* On UNIX, the function will be set and its free_data_function will
* be invoked when the connection is freed or a new function is set.
* However, the function will never be called, because there is no
* way right now to authenticate as a Windows user on UNIX.
*
* @param connection the connection
* @param function the predicate
* @param data data to pass to the predicate
* @param free_data_function function to free the data
*/
void
dbus_connection_set_windows_user_function (DBusConnection *connection,
DBusAllowWindowsUserFunction function,
void *data,
DBusFreeFunction free_data_function)
{
void *old_data = NULL;
DBusFreeFunction old_free_function = NULL;
_dbus_return_if_fail (connection != NULL);
CONNECTION_LOCK (connection);
_dbus_transport_set_windows_user_function (connection->transport,
function, data, free_data_function,
&old_data, &old_free_function);
CONNECTION_UNLOCK (connection);
if (old_free_function != NULL)
(* old_free_function) (old_data);
}
/**

View file

@ -132,14 +132,28 @@ typedef void (* DBusDispatchStatusFunction) (DBusConnection *connection,
* to do. Set with dbus_connection_set_wakeup_main_function().
*/
typedef void (* DBusWakeupMainFunction) (void *data);
/**
* Called during authentication on UNIX systems to check whether the given
* user ID is allowed to connect. Never called on Windows. Set with
* Called during authentication to check whether the given UNIX user
* ID is allowed to connect, if the client tried to auth as a UNIX
* user ID. Normally on Windows this would never happen. Set with
* dbus_connection_set_unix_user_function().
*/
typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection,
unsigned long uid,
void *data);
/**
* Called during authentication to check whether the given Windows user
* ID is allowed to connect, if the client tried to auth as a Windows
* user ID. Normally on UNIX this would never happen. Set with
* dbus_connection_set_windows_user_function().
*/
typedef dbus_bool_t (* DBusAllowWindowsUserFunction) (DBusConnection *connection,
const char *user_sid,
void *data);
/**
* Called when a pending call now has a reply available. Set with
* dbus_pending_call_set_notify().
@ -219,6 +233,12 @@ void dbus_connection_set_unix_user_function (DBusConnection
DBusAllowUnixUserFunction function,
void *data,
DBusFreeFunction free_data_function);
dbus_bool_t dbus_connection_get_windows_user (DBusConnection *connection,
char **windows_sid_p);
void dbus_connection_set_windows_user_function (DBusConnection *connection,
DBusAllowWindowsUserFunction function,
void *data,
DBusFreeFunction free_data_function);
void dbus_connection_set_route_peer_messages (DBusConnection *connection,
dbus_bool_t value);

View file

@ -2916,4 +2916,17 @@ _dbus_get_standard_session_servicedirs (DBusList **dirs)
return FALSE;
}
/**
* Called when the bus daemon is signaled to reload its configuration; any
* caches should be nuked. Of course any caches that need explicit reload
* are probably broken, but c'est la vie.
*
*
*/
void
_dbus_flush_caches (void)
{
_dbus_user_database_flush_system ();
}
/* tests in dbus-sysdeps-util.c */

View file

@ -120,8 +120,6 @@ dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info,
DBusError *error);
void _dbus_group_info_free (DBusGroupInfo *info);
dbus_pid_t _dbus_getpid (void);
dbus_uid_t _dbus_getuid (void);
dbus_gid_t _dbus_getgid (void);

View file

@ -780,6 +780,98 @@ _dbus_group_info_fill_gid (DBusGroupInfo *info,
return fill_group_info (info, gid, NULL, error);
}
/**
* Parse a UNIX user from the bus config file. On Windows, this should
* simply always fail (just return #FALSE).
*
* @param username the username text
* @param uid_p place to return the uid
* @returns #TRUE on success
*/
dbus_bool_t
_dbus_parse_unix_user_from_config (const DBusString *username,
dbus_uid_t *uid_p)
{
return _dbus_get_user_id (username, uid_p);
}
/**
* Parse a UNIX group from the bus config file. On Windows, this should
* simply always fail (just return #FALSE).
*
* @param groupname the groupname text
* @param gid_p place to return the gid
* @returns #TRUE on success
*/
dbus_bool_t
_dbus_parse_unix_group_from_config (const DBusString *groupname,
dbus_gid_t *gid_p)
{
return _dbus_get_group_id (groupname, gid_p);
}
/**
* Gets all groups corresponding to the given UNIX user ID. On UNIX,
* just calls _dbus_groups_from_uid(). On Windows, should always
* fail since we don't know any UNIX groups.
*
* @param uid the UID
* @param group_ids return location for array of group IDs
* @param n_group_ids return location for length of returned array
* @returns #TRUE if the UID existed and we got some credentials
*/
dbus_bool_t
_dbus_unix_groups_from_uid (dbus_uid_t uid,
dbus_gid_t **group_ids,
int *n_group_ids)
{
return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
}
/**
* Checks to see if the UNIX user ID is at the console.
* Should always fail on Windows (set the error to
* #DBUS_ERROR_NOT_SUPPORTED).
*
* @param uid UID of person to check
* @param error return location for errors
* @returns #TRUE if the UID is the same as the console user and there are no errors
*/
dbus_bool_t
_dbus_unix_user_is_at_console (dbus_uid_t uid,
DBusError *error)
{
return _dbus_is_console_user (uid, error);
}
/**
* Checks to see if the UNIX user ID matches the UID of
* the process. Should always return #FALSE on Windows.
*
* @param uid the UNIX user ID
* @returns #TRUE if this uid owns the process.
*/
dbus_bool_t
_dbus_unix_user_is_process_owner (dbus_uid_t uid)
{
return uid == _dbus_getuid ();
}
/**
* Checks to see if the Windows user SID matches the owner of
* the process. Should always return #FALSE on UNIX.
*
* @param windows_sid the Windows user SID
* @returns #TRUE if this user owns the process.
*/
dbus_bool_t
_dbus_windows_user_is_process_owner (const char *windows_sid)
{
return FALSE;
}
/** @} */ /* End of DBusInternalsUtils functions */
/**

View file

@ -173,6 +173,18 @@ dbus_bool_t _dbus_append_desired_identity (DBusString *str);
dbus_bool_t _dbus_homedir_from_current_process (const DBusString **homedir);
dbus_bool_t _dbus_homedir_from_username (const DBusString *username,
DBusString *homedir);
dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username,
dbus_uid_t *uid_p);
dbus_bool_t _dbus_parse_unix_group_from_config (const DBusString *groupname,
dbus_gid_t *gid_p);
dbus_bool_t _dbus_unix_groups_from_uid (dbus_uid_t uid,
dbus_gid_t **group_ids,
int *n_group_ids);
dbus_bool_t _dbus_unix_user_is_at_console (dbus_uid_t uid,
DBusError *error);
dbus_bool_t _dbus_unix_user_is_process_owner (dbus_uid_t uid);
dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid);
/** Opaque type representing an atomically-modifiable integer
* that can be used from multiple threads.
@ -420,6 +432,14 @@ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs,
unsigned long _dbus_pid_for_log (void);
/* FIXME move back to dbus-sysdeps-unix.h probably -
* the PID file handling just needs a little more abstraction
* in the bus daemon first.
*/
dbus_pid_t _dbus_getpid (void);
void _dbus_flush_caches (void);
/** @} */
DBUS_END_DECLS

View file

@ -161,8 +161,10 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *speci
#endif
run_data_test ("credentials", specific_test, _dbus_credentials_test, test_data_dir);
#ifdef DBUS_UNIX
run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir);
#endif
run_test ("keyring", specific_test, _dbus_keyring_test);

View file

@ -104,6 +104,11 @@ struct DBusTransport
void *unix_user_data; /**< Data for unix_user_function */
DBusFreeFunction free_unix_user_data; /**< Function to free unix_user_data */
DBusAllowWindowsUserFunction windows_user_function; /**< Function for checking whether a user is authorized. */
void *windows_user_data; /**< Data for windows_user_function */
DBusFreeFunction free_windows_user_data; /**< Function to free windows_user_data */
unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */
unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */

View file

@ -167,6 +167,10 @@ _dbus_transport_init_base (DBusTransport *transport,
transport->unix_user_data = NULL;
transport->free_unix_user_data = NULL;
transport->windows_user_function = NULL;
transport->windows_user_data = NULL;
transport->free_windows_user_data = NULL;
transport->expected_guid = NULL;
/* Try to default to something that won't totally hose the system,
@ -202,6 +206,9 @@ _dbus_transport_finalize_base (DBusTransport *transport)
if (transport->free_unix_user_data != NULL)
(* transport->free_unix_user_data) (transport->unix_user_data);
if (transport->free_windows_user_data != NULL)
(* transport->free_windows_user_data) (transport->windows_user_data);
_dbus_message_loader_unref (transport->loader);
_dbus_auth_unref (transport->auth);
@ -491,12 +498,157 @@ _dbus_transport_get_is_connected (DBusTransport *transport)
return !transport->disconnected;
}
static dbus_bool_t
auth_via_unix_user_function (DBusTransport *transport)
{
DBusCredentials *auth_identity;
dbus_bool_t allow;
DBusConnection *connection;
DBusAllowUnixUserFunction unix_user_function;
void *unix_user_data;
dbus_uid_t uid;
/* Dropping the lock here probably isn't that safe. */
auth_identity = _dbus_auth_get_identity (transport->auth);
_dbus_assert (auth_identity != NULL);
connection = transport->connection;
unix_user_function = transport->unix_user_function;
unix_user_data = transport->unix_user_data;
uid = _dbus_credentials_get_unix_uid (auth_identity),
_dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
_dbus_connection_unlock (connection);
allow = (* unix_user_function) (connection,
uid,
unix_user_data);
_dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
_dbus_connection_lock (connection);
if (allow)
{
_dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
}
else
{
_dbus_verbose ("Client UID "DBUS_UID_FORMAT
" was rejected, disconnecting\n",
_dbus_credentials_get_unix_uid (auth_identity));
_dbus_transport_disconnect (transport);
}
return allow;
}
static dbus_bool_t
auth_via_windows_user_function (DBusTransport *transport)
{
DBusCredentials *auth_identity;
dbus_bool_t allow;
DBusConnection *connection;
DBusAllowWindowsUserFunction windows_user_function;
void *windows_user_data;
char *windows_sid;
/* Dropping the lock here probably isn't that safe. */
auth_identity = _dbus_auth_get_identity (transport->auth);
_dbus_assert (auth_identity != NULL);
connection = transport->connection;
windows_user_function = transport->windows_user_function;
windows_user_data = transport->unix_user_data;
windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
if (windows_sid == NULL)
{
/* OOM */
return FALSE;
}
_dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
_dbus_connection_unlock (connection);
allow = (* windows_user_function) (connection,
windows_sid,
windows_user_data);
_dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
_dbus_connection_lock (connection);
if (allow)
{
_dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
}
else
{
_dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
_dbus_credentials_get_windows_sid (auth_identity));
_dbus_transport_disconnect (transport);
}
return allow;
}
static dbus_bool_t
auth_via_default_rules (DBusTransport *transport)
{
DBusCredentials *auth_identity;
DBusCredentials *our_identity;
dbus_bool_t allow;
auth_identity = _dbus_auth_get_identity (transport->auth);
_dbus_assert (auth_identity != NULL);
/* By default, connection is allowed if the client is
* 1) root or 2) has the same UID as us
*/
our_identity = _dbus_credentials_new_from_current_process ();
if (our_identity == NULL)
{
/* OOM */
return FALSE;
}
if (_dbus_credentials_get_unix_uid (auth_identity) == 0 ||
_dbus_credentials_same_user (our_identity,
auth_identity))
{
/* FIXME the verbose spam here is unix-specific */
_dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
" matching our UID "DBUS_UID_FORMAT"\n",
_dbus_credentials_get_unix_uid(auth_identity),
_dbus_credentials_get_unix_uid(our_identity));
/* We have authenticated! */
allow = TRUE;
}
else
{
/* FIXME the verbose spam here is unix-specific */
_dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
" but our UID is "DBUS_UID_FORMAT", disconnecting\n",
_dbus_credentials_get_unix_uid(our_identity),
_dbus_credentials_get_unix_uid(our_identity));
_dbus_transport_disconnect (transport);
allow = FALSE;
}
_dbus_credentials_unref (our_identity);
return allow;
}
/**
* Returns #TRUE if we have been authenticated. Will return #TRUE
* even if the transport is disconnected.
*
* @todo we drop connection->mutex when calling the unix_user_function,
* which may not be safe really.
* and windows_user_function, which may not be safe really.
*
* @param transport the transport
* @returns whether we're authenticated
@ -532,6 +684,8 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
}
}
/* If we're the client, verify the GUID
*/
if (maybe_authenticated && !transport->is_server)
{
const char *server_guid;
@ -560,106 +714,40 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
}
}
}
/* If we've authenticated as some identity, check that the auth
* identity is the same as our own identity. In the future, we
* may have API allowing applications to specify how this is
* done, for example they may allow connection as any identity,
* but then impose restrictions on certain identities.
* Or they may give certain identities extra privileges.
/* If we're the server, see if we want to allow this identity to proceed.
*/
if (maybe_authenticated && transport->is_server)
{
dbus_bool_t allow;
DBusCredentials *auth_identity;
auth_identity = _dbus_auth_get_identity (transport->auth);
_dbus_assert (auth_identity != NULL);
/* If we have a UNIX user and a unix user function, delegate
* deciding whether auth credentials are good enough to the app;
* otherwise, use our default decision process.
/* If we have an auth'd user and a user function, delegate
* deciding whether auth credentials are good enough to the
* app; otherwise, use our default decision process.
*/
if (transport->unix_user_function != NULL &&
_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
{
dbus_bool_t allow;
DBusConnection *connection;
DBusAllowUnixUserFunction unix_user_function;
void *unix_user_data;
dbus_uid_t uid;
/* Dropping the lock here probably isn't that safe. */
connection = transport->connection;
unix_user_function = transport->unix_user_function;
unix_user_data = transport->unix_user_data;
uid = _dbus_credentials_get_unix_uid (auth_identity),
_dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
_dbus_connection_unlock (connection);
allow = (* unix_user_function) (connection,
uid,
unix_user_data);
_dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
_dbus_connection_lock (connection);
if (allow)
{
_dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
}
else
{
_dbus_verbose ("Client UID "DBUS_UID_FORMAT
" was rejected, disconnecting\n",
_dbus_credentials_get_unix_uid (auth_identity));
_dbus_transport_disconnect (transport);
_dbus_connection_unref_unlocked (connection);
return FALSE;
}
allow = auth_via_unix_user_function (transport);
}
else if (transport->windows_user_function != NULL &&
_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
{
allow = auth_via_windows_user_function (transport);
}
else
{
DBusCredentials *our_identity;
/* By default, connection is allowed if the client is
* 1) root or 2) has the same UID as us
*/
our_identity = _dbus_credentials_new_from_current_process ();
if (our_identity == NULL)
{
/* OOM */
_dbus_connection_unref_unlocked (transport->connection);
return FALSE;
}
if (_dbus_credentials_get_unix_uid (auth_identity) == 0 ||
!_dbus_credentials_same_user (our_identity,
auth_identity))
{
/* FIXME the verbose spam here is unix-specific */
_dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
" but our UID is "DBUS_UID_FORMAT", disconnecting\n",
_dbus_credentials_get_unix_uid(our_identity),
_dbus_credentials_get_unix_uid(our_identity));
_dbus_transport_disconnect (transport);
_dbus_connection_unref_unlocked (transport->connection);
return FALSE;
}
else
{
/* FIXME the verbose spam here is unix-specific */
_dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
" matching our UID "DBUS_UID_FORMAT"\n",
_dbus_credentials_get_unix_uid(auth_identity),
_dbus_credentials_get_unix_uid(our_identity));
}
allow = auth_via_default_rules (transport);
}
if (!allow)
maybe_authenticated = FALSE;
}
transport->authenticated = maybe_authenticated;
_dbus_connection_unref_unlocked (transport->connection);
@ -1136,6 +1224,65 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
transport->free_unix_user_data = free_data_function;
}
/**
* See dbus_connection_get_windows_user().
*
* @param transport the transport
* @param windows_sid_p return location for the user ID
* @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
*/
dbus_bool_t
_dbus_transport_get_windows_user (DBusTransport *transport,
char **windows_sid_p)
{
DBusCredentials *auth_identity;
*windows_sid_p = NULL;
if (!transport->authenticated)
return FALSE;
auth_identity = _dbus_auth_get_identity (transport->auth);
if (_dbus_credentials_include (auth_identity,
DBUS_CREDENTIAL_WINDOWS_SID))
{
/* If no memory, we are supposed to return TRUE and set NULL */
*windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
return TRUE;
}
else
return FALSE;
}
/**
* See dbus_connection_set_windows_user_function().
*
* @param transport the transport
* @param function the predicate
* @param data data to pass to the predicate
* @param free_data_function function to free the data
* @param old_data the old user data to be freed
* @param old_free_data_function old free data function to free it with
*/
void
_dbus_transport_set_windows_user_function (DBusTransport *transport,
DBusAllowWindowsUserFunction function,
void *data,
DBusFreeFunction free_data_function,
void **old_data,
DBusFreeFunction *old_free_data_function)
{
*old_data = transport->windows_user_data;
*old_free_data_function = transport->free_windows_user_data;
transport->windows_user_function = function;
transport->windows_user_data = data;
transport->free_windows_user_data = free_data_function;
}
/**
* Sets the SASL authentication mechanisms supported by this transport.
*

View file

@ -68,6 +68,14 @@ void _dbus_transport_set_unix_user_function (DBusTransport
DBusFreeFunction free_data_function,
void **old_data,
DBusFreeFunction *old_free_data_function);
dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
char **windows_sid_p);
void _dbus_transport_set_windows_user_function (DBusTransport *transport,
DBusAllowWindowsUserFunction function,
void *data,
DBusFreeFunction free_data_function,
void **old_data,
DBusFreeFunction *old_free_data_function);
dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport *transport,
const char **mechanisms);