diff options
author | Havoc Pennington <hp@redhat.com> | 2007-06-09 23:41:33 +0000 |
---|---|---|
committer | Havoc Pennington <hp@redhat.com> | 2007-06-09 23:41:33 +0000 |
commit | 7be5fd95cdccdca28937804f32ca8b1308887d09 (patch) | |
tree | 2425bc50d77fbbbe6b6077d9e6dd053b936dcde1 | |
parent | 23832672266bb4ff23b66247c0cfa1a2ed0cc97b (diff) |
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
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | bus/bus.c | 23 | ||||
-rw-r--r-- | bus/bus.h | 4 | ||||
-rw-r--r-- | bus/config-parser.c | 15 | ||||
-rw-r--r-- | bus/connection.c | 43 | ||||
-rw-r--r-- | bus/connection.h | 12 | ||||
-rw-r--r-- | bus/policy.c | 88 | ||||
-rw-r--r-- | bus/policy.h | 4 | ||||
-rw-r--r-- | dbus/dbus-connection.c | 141 | ||||
-rw-r--r-- | dbus/dbus-connection.h | 24 | ||||
-rw-r--r-- | dbus/dbus-sysdeps-unix.c | 13 | ||||
-rw-r--r-- | dbus/dbus-sysdeps-unix.h | 2 | ||||
-rw-r--r-- | dbus/dbus-sysdeps-util-unix.c | 92 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 20 | ||||
-rw-r--r-- | dbus/dbus-test.c | 4 | ||||
-rw-r--r-- | dbus/dbus-transport-protected.h | 5 | ||||
-rw-r--r-- | dbus/dbus-transport.c | 319 | ||||
-rw-r--r-- | dbus/dbus-transport.h | 8 |
18 files changed, 644 insertions, 192 deletions
@@ -1,5 +1,24 @@ 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 since sysdeps-unix.h stuff isn't included anymore @@ -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 * @@ -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, diff --git a/bus/config-parser.c b/bus/config-parser.c index 27528e03..7b6a368c 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -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; } diff --git a/bus/connection.c b/bus/connection.c index d063afca..10247e25 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -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; diff --git a/bus/connection.h b/bus/connection.h index a0703c55..75d94cf9 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -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 */ diff --git a/bus/policy.c b/bus/policy.c index 7782563b..0d467ab9 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -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 (!add_list_to_client (list, client)) + goto nomem; + } + } - if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0) - { - DBusList **list; + /* Add console rules */ + at_console = _dbus_unix_user_is_at_console (uid, error); - list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid, - uid); - - if (list != NULL) + if (at_console) { - if (!add_list_to_client (list, client)) + 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) diff --git a/bus/policy.h b/bus/policy.h index e2574bc3..b58b3862 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -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, diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 5dc463a4..1cd3d05d 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -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); } /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 819e96c8..2b673fda 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -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); diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 135f7c9f..f1c133fd 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -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 */ diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index 58fce9ce..0e8bdbb3 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -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); diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index 9963432b..339b8f96 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -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 */ /** diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index f83c17ca..87bfc8fa 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -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 diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index a1df3604..818c4ed0 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -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); diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index bfdff0e2..6d3f1f3c 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -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 */ diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index e922eb5d..029cc6cf 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -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); @@ -1137,6 +1225,65 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport, } /** + * 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. * * @param transport the transport diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 4784e462..9e952a1e 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -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); |