diff options
| -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);  | 
