2007-06-09 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Sat, 9 Jun 2007 23:41:33 +0000 (23:41 +0000)
committerHavoc Pennington <hp@redhat.com>
Sat, 9 Jun 2007 23:41:33 +0000 (23:41 +0000)
* 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

18 files changed:
ChangeLog
bus/bus.c
bus/bus.h
bus/config-parser.c
bus/connection.c
bus/connection.h
bus/policy.c
bus/policy.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-sysdeps-unix.c
dbus/dbus-sysdeps-unix.h
dbus/dbus-sysdeps-util-unix.c
dbus/dbus-sysdeps.h
dbus/dbus-test.c
dbus/dbus-transport-protected.h
dbus/dbus-transport.c
dbus/dbus-transport.h

index 4fe45e2..c7d2479 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
 
index e1396f2..073f0a5 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -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 *
index bb51004..e17de06 100644 (file)
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -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,
index 27528e0..7b6a368 100644 (file)
@@ -27,7 +27,6 @@
 #include "selinux.h"
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-internals.h>
-#include <dbus/dbus-userdb.h>
 #include <string.h>
 
 typedef enum
@@ -983,8 +982,8 @@ start_busconfig_child (BusConfigParser   *parser,
           DBusString username;
           _dbus_string_init_const (&username, user);
 
-          if (_dbus_get_user_id (&username,
-                                 &e->d.policy.gid_uid_or_at_console))
+          if (_dbus_parse_unix_user_from_config (&username,
+                                                 &e->d.policy.gid_uid_or_at_console))
             e->d.policy.type = POLICY_USER;
           else
             _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n",
@@ -995,8 +994,8 @@ start_busconfig_child (BusConfigParser   *parser,
           DBusString group_name;
           _dbus_string_init_const (&group_name, group);
 
-          if (_dbus_get_group_id (&group_name,
-                                  &e->d.policy.gid_uid_or_at_console))
+          if (_dbus_parse_unix_group_from_config (&group_name,
+                                                  &e->d.policy.gid_uid_or_at_console))
             e->d.policy.type = POLICY_GROUP;
           else
             _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n",
@@ -1469,7 +1468,7 @@ append_rule_from_element (BusConfigParser   *parser,
           
           _dbus_string_init_const (&username, user);
       
-          if (_dbus_get_user_id (&username, &uid))
+          if (_dbus_parse_unix_user_from_config (&username, &uid))
             {
               rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); 
               if (rule == NULL)
@@ -1501,7 +1500,7 @@ append_rule_from_element (BusConfigParser   *parser,
           
           _dbus_string_init_const (&groupname, group);
           
-          if (_dbus_get_user_id (&groupname, &gid))
+          if (_dbus_parse_unix_group_from_config (&groupname, &gid))
             {
               rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); 
               if (rule == NULL)
@@ -1571,7 +1570,7 @@ append_rule_from_element (BusConfigParser   *parser,
 
         case POLICY_CONSOLE:
           if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console,
-                                             rule))
+                                               rule))
             goto nomem;
           break;
         }
index d063afc..10247e2 100644 (file)
@@ -31,7 +31,6 @@
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-timeout.h>
-#include <dbus/dbus-userdb.h>
 
 static void bus_connection_remove_transactions (DBusConnection *connection);
 
@@ -243,7 +242,9 @@ bus_connection_disconnected (DBusConnection *connection)
   
   dbus_connection_set_unix_user_function (connection,
                                           NULL, NULL, NULL);
-
+  dbus_connection_set_windows_user_function (connection,
+                                             NULL, NULL, NULL);
+  
   dbus_connection_set_dispatch_status_function (connection,
                                                 NULL, NULL, NULL);
   
@@ -369,9 +370,9 @@ dispatch_status_function (DBusConnection    *connection,
 }
 
 static dbus_bool_t
-allow_user_function (DBusConnection *connection,
-                     unsigned long   uid,
-                     void           *data)
+allow_unix_user_function (DBusConnection *connection,
+                          unsigned long   uid,
+                          void           *data)
 {
   BusConnectionData *d;
     
@@ -379,7 +380,7 @@ allow_user_function (DBusConnection *connection,
 
   _dbus_assert (d != NULL);
   
-  return bus_context_allow_user (d->connections->context, uid);
+  return bus_context_allow_unix_user (d->connections->context, uid);
 }
 
 static void
@@ -597,9 +598,14 @@ bus_connections_setup_connection (BusConnections *connections,
                                               NULL,
                                               connection, NULL))
     goto out;
-  
+
+  /* For now we don't need to set a Windows user function because
+   * there are no policies in the config file controlling what
+   * Windows users can connect. The default 'same user that owns the
+   * bus can connect' behavior of DBusConnection is fine on Windows.
+   */
   dbus_connection_set_unix_user_function (connection,
-                                          allow_user_function,
+                                          allow_unix_user_function,
                                           NULL, NULL);
 
   dbus_connection_set_dispatch_status_function (connection,
@@ -679,6 +685,9 @@ bus_connections_setup_connection (BusConnections *connections,
       dbus_connection_set_unix_user_function (connection,
                                               NULL, NULL, NULL);
 
+      dbus_connection_set_windows_user_function (connection,
+                                                 NULL, NULL, NULL);
+      
       dbus_connection_set_dispatch_status_function (connection,
                                                     NULL, NULL, NULL);
 
@@ -772,10 +781,10 @@ expire_incomplete_timeout (void *data)
 }
 
 dbus_bool_t
-bus_connection_get_groups  (DBusConnection   *connection,
-                            unsigned long   **groups,
-                            int              *n_groups,
-                            DBusError        *error)
+bus_connection_get_unix_groups  (DBusConnection   *connection,
+                                 unsigned long   **groups,
+                                 int              *n_groups,
+                                 DBusError        *error)
 {
   BusConnectionData *d;
   unsigned long uid;
@@ -789,7 +798,7 @@ bus_connection_get_groups  (DBusConnection   *connection,
 
   if (dbus_connection_get_unix_user (connection, &uid))
     {
-      if (!_dbus_groups_from_uid (uid, groups, n_groups))
+      if (!_dbus_unix_groups_from_uid (uid, groups, n_groups))
         {
           _dbus_verbose ("Did not get any groups for UID %lu\n",
                          uid);
@@ -807,15 +816,15 @@ bus_connection_get_groups  (DBusConnection   *connection,
 }
 
 dbus_bool_t
-bus_connection_is_in_group (DBusConnection *connection,
-                            unsigned long   gid)
+bus_connection_is_in_unix_group (DBusConnection *connection,
+                                 unsigned long   gid)
 {
   int i;
   unsigned long *group_ids;
   int n_group_ids;
 
-  if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
-                                  NULL))
+  if (!bus_connection_get_unix_groups (connection, &group_ids, &n_group_ids,
+                                       NULL))
     return FALSE;
 
   i = 0;
index a0703c5..75d94cf 100644 (file)
@@ -105,12 +105,12 @@ dbus_bool_t bus_connection_complete (DBusConnection               *connection,
 /* called by dispatch.c when the connection is dropped */
 void        bus_connection_disconnected (DBusConnection *connection);
 
-dbus_bool_t      bus_connection_is_in_group (DBusConnection       *connection,
-                                             unsigned long         gid);
-dbus_bool_t      bus_connection_get_groups  (DBusConnection       *connection,
-                                             unsigned long       **groups,
-                                             int                  *n_groups,
-                                             DBusError            *error);
+dbus_bool_t      bus_connection_is_in_unix_group (DBusConnection       *connection,
+                                                  unsigned long         gid);
+dbus_bool_t      bus_connection_get_unix_groups  (DBusConnection       *connection,
+                                                  unsigned long       **groups,
+                                                  int                  *n_groups,
+                                                  DBusError            *error);
 BusClientPolicy* bus_connection_get_policy  (DBusConnection       *connection);
 
 /* transaction API so we can send or not send a block of messages as a whole */
index 7782563..0d467ab 100644 (file)
@@ -28,7 +28,6 @@
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-internals.h>
-#include <dbus/dbus-userdb.h>
 
 BusPolicyRule*
 bus_policy_rule_new (BusPolicyRuleType type,
@@ -296,7 +295,7 @@ bus_policy_create_client_policy (BusPolicy      *policy,
       int n_groups;
       int i;
       
-      if (!bus_connection_get_groups (connection, &groups, &n_groups, error))
+      if (!bus_connection_get_unix_groups (connection, &groups, &n_groups, error))
         goto failed;
       
       i = 0;
@@ -321,43 +320,39 @@ bus_policy_create_client_policy (BusPolicy      *policy,
 
       dbus_free (groups);
     }
-
-  if (!dbus_connection_get_unix_user (connection, &uid))
+  
+  if (dbus_connection_get_unix_user (connection, &uid))
     {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "No user ID known for connection, cannot determine security policy\n");
-      goto failed;
-    }
+      if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
+        {
+          DBusList **list;
+          
+          list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
+                                                uid);
+          
+          if (list != NULL)
+            {
+              if (!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)
index e2574bc..b58b386 100644 (file)
@@ -113,8 +113,10 @@ void             bus_policy_unref                 (BusPolicy        *policy);
 BusClientPolicy* bus_policy_create_client_policy  (BusPolicy        *policy,
                                                    DBusConnection   *connection,
                                                    DBusError        *error);
-dbus_bool_t      bus_policy_allow_user            (BusPolicy        *policy,
+dbus_bool_t      bus_policy_allow_unix_user       (BusPolicy        *policy,
                                                    unsigned long     uid);
+dbus_bool_t      bus_policy_allow_windows_user    (BusPolicy        *policy,
+                                                   const char       *windows_sid);
 dbus_bool_t      bus_policy_append_default_rule   (BusPolicy        *policy,
                                                    BusPolicyRule    *rule);
 dbus_bool_t      bus_policy_append_mandatory_rule (BusPolicy        *policy,
index 5dc463a..1cd3d05 100644 (file)
@@ -4763,8 +4763,10 @@ dbus_connection_get_socket(DBusConnection              *connection,
 
 /**
  * Gets the UNIX user ID of the connection if known.  Returns #TRUE if
- * the uid is filled in.  Always returns #FALSE on non-UNIX platforms.
- * Always returns #FALSE prior to authenticating the connection.
+ * the uid is filled in.  Always returns #FALSE on non-UNIX platforms
+ * for now, though in theory someone could hook Windows to NIS or
+ * something.  Always returns #FALSE prior to authenticating the
+ * connection.
  *
  * The UID is only read by servers from clients; clients can't usually
  * get the UID of servers, because servers do not authenticate to
@@ -4789,14 +4791,6 @@ dbus_connection_get_unix_user (DBusConnection *connection,
 
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (uid != NULL, FALSE);
-
-#ifdef DBUS_WIN
-  /* FIXME this should be done at a lower level, but it's kind of hard,
-   * just want to be sure we don't ship with this API returning
-   * some weird internal fake uid for 1.0
-   */
-  return FALSE;
-#endif
   
   CONNECTION_LOCK (connection);
 
@@ -4805,6 +4799,11 @@ dbus_connection_get_unix_user (DBusConnection *connection,
   else
     result = _dbus_transport_get_unix_user (connection->transport,
                                             uid);
+
+#ifdef DBUS_WIN
+  _dbus_assert (!result);
+#endif
+  
   CONNECTION_UNLOCK (connection);
 
   return result;
@@ -4812,7 +4811,7 @@ dbus_connection_get_unix_user (DBusConnection *connection,
 
 /**
  * Gets the process ID of the connection if any.
- * Returns #TRUE if the uid is filled in.
+ * Returns #TRUE if the pid is filled in.
  * Always returns #FALSE prior to authenticating the
  * connection.
  *
@@ -4828,14 +4827,6 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
 
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (pid != NULL, FALSE);
-
-#ifdef DBUS_WIN
-  /* FIXME this should be done at a lower level, but it's kind of hard,
-   * just want to be sure we don't ship with this API returning
-   * some weird internal fake uid for 1.0
-   */
-  return FALSE;
-#endif
   
   CONNECTION_LOCK (connection);
 
@@ -4844,6 +4835,10 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
   else
     result = _dbus_transport_get_unix_process_id (connection->transport,
                                                  pid);
+#ifdef DBUS_WIN
+  _dbus_assert (!result);
+#endif
+  
   CONNECTION_UNLOCK (connection);
 
   return result;
@@ -4858,14 +4853,13 @@ dbus_connection_get_unix_process_id (DBusConnection *connection,
  *
  * If the function is set to #NULL (as it is by default), then
  * only the same UID as the server process will be allowed to
- * connect.
+ * connect. Also, root is always allowed to connect.
  *
  * On Windows, the function will be set and its free_data_function will
  * be invoked when the connection is freed or a new function is set.
  * However, the function will never be called, because there are
- * no UNIX user ids to pass to it.
- * 
- * @todo add a Windows API analogous to dbus_connection_set_unix_user_function()
+ * no UNIX user ids to pass to it, or at least none of the existing
+ * auth protocols would allow authenticating as a UNIX user on Windows.
  * 
  * @param connection the connection
  * @param function the predicate
@@ -4890,7 +4884,106 @@ dbus_connection_set_unix_user_function (DBusConnection             *connection,
   CONNECTION_UNLOCK (connection);
 
   if (old_free_function != NULL)
-    (* old_free_function) (old_data);    
+    (* old_free_function) (old_data);
+}
+
+/**
+ * Gets the Windows user SID of the connection if known.  Returns
+ * #TRUE if the ID is filled in.  Always returns #FALSE on non-Windows
+ * platforms for now, though in theory someone could hook UNIX to
+ * Active Directory or something.  Always returns #FALSE prior to
+ * authenticating the connection.
+ *
+ * The user is only read by servers from clients; clients can't usually
+ * get the user of servers, because servers do not authenticate to
+ * clients. The returned user is the user the connection authenticated
+ * as.
+ *
+ * The message bus is a server and the apps connecting to the bus
+ * are clients.
+ *
+ * The returned user string has to be freed with dbus_free().
+ *
+ * The return value indicates whether the user SID is available;
+ * if it's available but we don't have the memory to copy it,
+ * then the return value is #TRUE and #NULL is given as the SID.
+ * 
+ * @todo We would like to be able to say "You can ask the bus to tell
+ * you the user of another connection though if you like; this is done
+ * with dbus_bus_get_windows_user()." But this has to be implemented
+ * in bus/driver.c and dbus/dbus-bus.c, and is pointless anyway
+ * since on Windows we only use the session bus for now.
+ *
+ * @param connection the connection
+ * @param windows_sid_p return location for an allocated copy of the user ID, or #NULL if no memory
+ * @returns #TRUE if user is available (returned value may be #NULL anyway if no memory)
+ */
+dbus_bool_t
+dbus_connection_get_windows_user (DBusConnection             *connection,
+                                  char                      **windows_sid_p)
+{
+  dbus_bool_t result;
+
+  _dbus_return_val_if_fail (connection != NULL, FALSE);
+  _dbus_return_val_if_fail (windows_sid_p != NULL, FALSE);
+  
+  CONNECTION_LOCK (connection);
+
+  if (!_dbus_transport_get_is_authenticated (connection->transport))
+    result = FALSE;
+  else
+    result = _dbus_transport_get_windows_user (connection->transport,
+                                               windows_sid_p);
+
+#ifdef DBUS_UNIX
+  _dbus_assert (!result);
+#endif
+  
+  CONNECTION_UNLOCK (connection);
+
+  return result;
+}
+
+/**
+ * Sets a predicate function used to determine whether a given user ID
+ * is allowed to connect. When an incoming connection has
+ * authenticated with a particular user ID, this function is called;
+ * if it returns #TRUE, the connection is allowed to proceed,
+ * otherwise the connection is disconnected.
+ *
+ * If the function is set to #NULL (as it is by default), then
+ * only the same user owning the server process will be allowed to
+ * connect.
+ *
+ * On UNIX, the function will be set and its free_data_function will
+ * be invoked when the connection is freed or a new function is set.
+ * However, the function will never be called, because there is no
+ * way right now to authenticate as a Windows user on UNIX.
+ * 
+ * @param connection the connection
+ * @param function the predicate
+ * @param data data to pass to the predicate
+ * @param free_data_function function to free the data
+ */
+void
+dbus_connection_set_windows_user_function (DBusConnection              *connection,
+                                           DBusAllowWindowsUserFunction function,
+                                           void                        *data,
+                                           DBusFreeFunction             free_data_function)
+{
+  void *old_data = NULL;
+  DBusFreeFunction old_free_function = NULL;
+
+  _dbus_return_if_fail (connection != NULL);
+  
+  CONNECTION_LOCK (connection);
+  _dbus_transport_set_windows_user_function (connection->transport,
+                                             function, data, free_data_function,
+                                             &old_data, &old_free_function);
+  CONNECTION_UNLOCK (connection);
+
+  if (old_free_function != NULL)
+    (* old_free_function) (old_data);
 }
 
 /**
index 819e96c..2b673fd 100644 (file)
@@ -132,14 +132,28 @@ typedef void        (* DBusDispatchStatusFunction) (DBusConnection *connection,
  * to do. Set with dbus_connection_set_wakeup_main_function().
  */
 typedef void        (* DBusWakeupMainFunction)     (void           *data);
+
 /**
- * Called during authentication on UNIX systems to check whether the given
- * user ID is allowed to connect. Never called on Windows. Set with
+ * Called during authentication to check whether the given UNIX user
+ * ID is allowed to connect, if the client tried to auth as a UNIX
+ * user ID. Normally on Windows this would never happen. Set with
  * dbus_connection_set_unix_user_function().
  */ 
 typedef dbus_bool_t (* DBusAllowUnixUserFunction)  (DBusConnection *connection,
                                                     unsigned long   uid,
                                                     void           *data);
+
+/**
+ * Called during authentication to check whether the given Windows user
+ * ID is allowed to connect, if the client tried to auth as a Windows
+ * user ID. Normally on UNIX this would never happen. Set with
+ * dbus_connection_set_windows_user_function().
+ */ 
+typedef dbus_bool_t (* DBusAllowWindowsUserFunction)  (DBusConnection *connection,
+                                                       const char     *user_sid,
+                                                       void           *data);
+
+
 /**
  * Called when a pending call now has a reply available. Set with
  * dbus_pending_call_set_notify().
@@ -219,6 +233,12 @@ void               dbus_connection_set_unix_user_function       (DBusConnection
                                                                  DBusAllowUnixUserFunction   function,
                                                                  void                       *data,
                                                                  DBusFreeFunction            free_data_function);
+dbus_bool_t        dbus_connection_get_windows_user             (DBusConnection             *connection,
+                                                                 char                      **windows_sid_p); 
+void               dbus_connection_set_windows_user_function    (DBusConnection             *connection,
+                                                                 DBusAllowWindowsUserFunction function,
+                                                                 void                       *data,
+                                                                 DBusFreeFunction            free_data_function);
 void               dbus_connection_set_route_peer_messages      (DBusConnection             *connection,
                                                                  dbus_bool_t                 value);
 
index 135f7c9..f1c133f 100644 (file)
@@ -2916,4 +2916,17 @@ _dbus_get_standard_session_servicedirs (DBusList **dirs)
   return FALSE;
 }
 
+/**
+ * Called when the bus daemon is signaled to reload its configuration; any
+ * caches should be nuked. Of course any caches that need explicit reload
+ * are probably broken, but c'est la vie.
+ *
+ * 
+ */
+void
+_dbus_flush_caches (void)
+{
+  _dbus_user_database_flush_system ();
+}
+
 /* tests in dbus-sysdeps-util.c */
index 58fce9c..0e8bdbb 100644 (file)
@@ -120,8 +120,6 @@ dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo    *info,
                                        DBusError        *error);
 void        _dbus_group_info_free     (DBusGroupInfo    *info);
 
-
-dbus_pid_t    _dbus_getpid (void);
 dbus_uid_t    _dbus_getuid (void);
 dbus_gid_t    _dbus_getgid (void);
 
index 9963432..339b8f9 100644 (file)
@@ -780,6 +780,98 @@ _dbus_group_info_fill_gid (DBusGroupInfo *info,
   return fill_group_info (info, gid, NULL, error);
 }
 
+/**
+ * Parse a UNIX user from the bus config file. On Windows, this should
+ * simply always fail (just return #FALSE).
+ *
+ * @param username the username text
+ * @param uid_p place to return the uid
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_parse_unix_user_from_config (const DBusString  *username,
+                                   dbus_uid_t        *uid_p)
+{
+  return _dbus_get_user_id (username, uid_p);
+
+}
+
+/**
+ * Parse a UNIX group from the bus config file. On Windows, this should
+ * simply always fail (just return #FALSE).
+ *
+ * @param groupname the groupname text
+ * @param gid_p place to return the gid
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_parse_unix_group_from_config (const DBusString  *groupname,
+                                    dbus_gid_t        *gid_p)
+{
+  return _dbus_get_group_id (groupname, gid_p);
+}
+
+/**
+ * Gets all groups corresponding to the given UNIX user ID. On UNIX,
+ * just calls _dbus_groups_from_uid(). On Windows, should always
+ * fail since we don't know any UNIX groups.
+ *
+ * @param uid the UID
+ * @param group_ids return location for array of group IDs
+ * @param n_group_ids return location for length of returned array
+ * @returns #TRUE if the UID existed and we got some credentials
+ */
+dbus_bool_t
+_dbus_unix_groups_from_uid (dbus_uid_t            uid,
+                            dbus_gid_t          **group_ids,
+                            int                  *n_group_ids)
+{
+  return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
+}
+
+/**
+ * Checks to see if the UNIX user ID is at the console.
+ * Should always fail on Windows (set the error to
+ * #DBUS_ERROR_NOT_SUPPORTED).
+ *
+ * @param uid UID of person to check 
+ * @param error return location for errors
+ * @returns #TRUE if the UID is the same as the console user and there are no errors
+ */
+dbus_bool_t
+_dbus_unix_user_is_at_console (dbus_uid_t         uid,
+                               DBusError         *error)
+{
+  return _dbus_is_console_user (uid, error);
+
+}
+
+/**
+ * Checks to see if the UNIX user ID matches the UID of
+ * the process. Should always return #FALSE on Windows.
+ *
+ * @param uid the UNIX user ID
+ * @returns #TRUE if this uid owns the process.
+ */
+dbus_bool_t
+_dbus_unix_user_is_process_owner (dbus_uid_t uid)
+{
+  return uid == _dbus_getuid ();
+}
+
+/**
+ * Checks to see if the Windows user SID matches the owner of
+ * the process. Should always return #FALSE on UNIX.
+ *
+ * @param windows_sid the Windows user SID
+ * @returns #TRUE if this user owns the process.
+ */
+dbus_bool_t
+_dbus_windows_user_is_process_owner (const char *windows_sid)
+{
+  return FALSE;
+}
+
 /** @} */ /* End of DBusInternalsUtils functions */
 
 /**
index f83c17c..87bfc8f 100644 (file)
@@ -173,6 +173,18 @@ dbus_bool_t _dbus_append_desired_identity       (DBusString *str);
 dbus_bool_t _dbus_homedir_from_current_process  (const DBusString **homedir);
 dbus_bool_t _dbus_homedir_from_username         (const DBusString  *username,
                                                  DBusString        *homedir);
+dbus_bool_t _dbus_parse_unix_user_from_config   (const DBusString  *username,
+                                                 dbus_uid_t        *uid_p);
+dbus_bool_t _dbus_parse_unix_group_from_config  (const DBusString  *groupname,
+                                                 dbus_gid_t        *gid_p);
+dbus_bool_t _dbus_unix_groups_from_uid          (dbus_uid_t         uid,
+                                                 dbus_gid_t       **group_ids,
+                                                 int               *n_group_ids);
+dbus_bool_t _dbus_unix_user_is_at_console       (dbus_uid_t         uid,
+                                                 DBusError         *error);
+dbus_bool_t _dbus_unix_user_is_process_owner    (dbus_uid_t         uid);
+dbus_bool_t _dbus_windows_user_is_process_owner (const char        *windows_sid);
+
 
 /** Opaque type representing an atomically-modifiable integer
  * that can be used from multiple threads.
@@ -420,6 +432,14 @@ dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs,
 
 unsigned long _dbus_pid_for_log (void);
 
+/* FIXME move back to dbus-sysdeps-unix.h probably -
+ * the PID file handling just needs a little more abstraction
+ * in the bus daemon first.
+ */
+dbus_pid_t    _dbus_getpid (void);
+
+void _dbus_flush_caches (void);
+
 /** @} */
 
 DBUS_END_DECLS
index a1df360..818c4ed 100644 (file)
@@ -161,8 +161,10 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *speci
 #endif
   
   run_data_test ("credentials", specific_test, _dbus_credentials_test, test_data_dir);
-  
+
+#ifdef DBUS_UNIX
   run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir);
+#endif
   
   run_test ("keyring", specific_test, _dbus_keyring_test);
   
index bfdff0e..6d3f1f3 100644 (file)
@@ -104,6 +104,11 @@ struct DBusTransport
   void *unix_user_data;                         /**< Data for unix_user_function */
   
   DBusFreeFunction free_unix_user_data;         /**< Function to free unix_user_data */
+
+  DBusAllowWindowsUserFunction windows_user_function; /**< Function for checking whether a user is authorized. */
+  void *windows_user_data;                            /**< Data for windows_user_function */
+  
+  DBusFreeFunction free_windows_user_data;            /**< Function to free windows_user_data */
   
   unsigned int disconnected : 1;              /**< #TRUE if we are disconnected. */
   unsigned int authenticated : 1;             /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */
index e922eb5..029cc6c 100644 (file)
@@ -167,6 +167,10 @@ _dbus_transport_init_base (DBusTransport             *transport,
   transport->unix_user_data = NULL;
   transport->free_unix_user_data = NULL;
 
+  transport->windows_user_function = NULL;
+  transport->windows_user_data = NULL;
+  transport->free_windows_user_data = NULL;
+  
   transport->expected_guid = NULL;
   
   /* Try to default to something that won't totally hose the system,
@@ -202,6 +206,9 @@ _dbus_transport_finalize_base (DBusTransport *transport)
 
   if (transport->free_unix_user_data != NULL)
     (* transport->free_unix_user_data) (transport->unix_user_data);
+
+  if (transport->free_windows_user_data != NULL)
+    (* transport->free_windows_user_data) (transport->windows_user_data);
   
   _dbus_message_loader_unref (transport->loader);
   _dbus_auth_unref (transport->auth);
@@ -491,12 +498,157 @@ _dbus_transport_get_is_connected (DBusTransport *transport)
   return !transport->disconnected;
 }
 
+static dbus_bool_t
+auth_via_unix_user_function (DBusTransport *transport)
+{
+  DBusCredentials *auth_identity;
+  dbus_bool_t allow;
+  DBusConnection *connection;
+  DBusAllowUnixUserFunction unix_user_function;
+  void *unix_user_data;
+  dbus_uid_t uid;
+
+  /* Dropping the lock here probably isn't that safe. */
+  
+  auth_identity = _dbus_auth_get_identity (transport->auth);
+  _dbus_assert (auth_identity != NULL);
+
+  connection = transport->connection;
+  unix_user_function = transport->unix_user_function;
+  unix_user_data = transport->unix_user_data;
+  uid = _dbus_credentials_get_unix_uid (auth_identity),
+              
+    _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
+  _dbus_connection_unlock (connection);
+
+  allow = (* unix_user_function) (connection,
+                                  uid,
+                                  unix_user_data);
+              
+  _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
+  _dbus_connection_lock (connection);
+
+  if (allow)
+    {
+      _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
+    }
+  else
+    {
+      _dbus_verbose ("Client UID "DBUS_UID_FORMAT
+                     " was rejected, disconnecting\n",
+                     _dbus_credentials_get_unix_uid (auth_identity));
+      _dbus_transport_disconnect (transport);
+    }
+
+  return allow;
+}
+
+static dbus_bool_t
+auth_via_windows_user_function (DBusTransport *transport)
+{
+  DBusCredentials *auth_identity;  
+  dbus_bool_t allow;
+  DBusConnection *connection;
+  DBusAllowWindowsUserFunction windows_user_function;
+  void *windows_user_data;
+  char *windows_sid;
+
+  /* Dropping the lock here probably isn't that safe. */
+  
+  auth_identity = _dbus_auth_get_identity (transport->auth);
+  _dbus_assert (auth_identity != NULL);
+
+  connection = transport->connection;
+  windows_user_function = transport->windows_user_function;
+  windows_user_data = transport->unix_user_data;
+  windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
+
+  if (windows_sid == NULL)
+    {
+      /* OOM */
+      return FALSE;
+    }
+                
+  _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
+  _dbus_connection_unlock (connection);
+
+  allow = (* windows_user_function) (connection,
+                                     windows_sid,
+                                     windows_user_data);
+              
+  _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
+  _dbus_connection_lock (connection);
+
+  if (allow)
+    {
+      _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
+    }
+  else
+    {
+      _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
+                     _dbus_credentials_get_windows_sid (auth_identity));
+      _dbus_transport_disconnect (transport);
+    }
+
+  return allow;
+}
+
+static dbus_bool_t
+auth_via_default_rules (DBusTransport *transport)
+{
+  DBusCredentials *auth_identity;
+  DBusCredentials *our_identity;
+  dbus_bool_t allow;
+  
+  auth_identity = _dbus_auth_get_identity (transport->auth);
+  _dbus_assert (auth_identity != NULL);
+
+  /* By default, connection is allowed if the client is
+   * 1) root or 2) has the same UID as us
+   */
+              
+  our_identity = _dbus_credentials_new_from_current_process ();
+  if (our_identity == NULL)
+    {
+      /* OOM */
+      return FALSE;
+    }
+              
+  if (_dbus_credentials_get_unix_uid (auth_identity) == 0 ||
+      _dbus_credentials_same_user (our_identity,
+                                   auth_identity))
+    {
+      /* FIXME the verbose spam here is unix-specific */                  
+      _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
+                     " matching our UID "DBUS_UID_FORMAT"\n",
+                     _dbus_credentials_get_unix_uid(auth_identity),
+                     _dbus_credentials_get_unix_uid(our_identity));
+      /* We have authenticated! */
+      allow = TRUE;
+    }
+  else
+    {
+      /* FIXME the verbose spam here is unix-specific */
+      _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
+                     " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
+                     _dbus_credentials_get_unix_uid(our_identity),
+                     _dbus_credentials_get_unix_uid(our_identity));
+      _dbus_transport_disconnect (transport);
+      allow = FALSE;
+    }  
+
+  _dbus_credentials_unref (our_identity);
+  
+  return allow;
+}
+
+
 /**
  * Returns #TRUE if we have been authenticated.  Will return #TRUE
  * even if the transport is disconnected.
  *
  * @todo we drop connection->mutex when calling the unix_user_function,
- * which may not be safe really.
+ * and windows_user_function, which may not be safe really.
  *
  * @param transport the transport
  * @returns whether we're authenticated
@@ -532,6 +684,8 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
             }
         }
 
+      /* If we're the client, verify the GUID
+       */
       if (maybe_authenticated && !transport->is_server)
         {
           const char *server_guid;
@@ -560,106 +714,40 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
                 }
             }
         }
-      
-      /* If we've authenticated as some identity, check that the auth
-       * identity is the same as our own identity.  In the future, we
-       * may have API allowing applications to specify how this is
-       * done, for example they may allow connection as any identity,
-       * but then impose restrictions on certain identities.
-       * Or they may give certain identities extra privileges.
+
+      /* If we're the server, see if we want to allow this identity to proceed.
        */
-      
       if (maybe_authenticated && transport->is_server)
         {
+          dbus_bool_t allow;
           DBusCredentials *auth_identity;
-
+          
           auth_identity = _dbus_auth_get_identity (transport->auth);
           _dbus_assert (auth_identity != NULL);
-
-          /* If we have a UNIX user and a unix user function, delegate
-           * deciding whether auth credentials are good enough to the app;
-           * otherwise, use our default decision process.
+          
+          /* If we have an auth'd user and a user function, delegate
+           * deciding whether auth credentials are good enough to the
+           * app; otherwise, use our default decision process.
            */
           if (transport->unix_user_function != NULL &&
               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
             {
-              dbus_bool_t allow;
-              DBusConnection *connection;
-              DBusAllowUnixUserFunction unix_user_function;
-              void *unix_user_data;
-              dbus_uid_t uid;
-              
-              /* Dropping the lock here probably isn't that safe. */
-
-              connection = transport->connection;
-              unix_user_function = transport->unix_user_function;
-              unix_user_data = transport->unix_user_data;
-              uid = _dbus_credentials_get_unix_uid (auth_identity),
-              
-              _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
-              _dbus_connection_unlock (connection);
-
-              allow = (* unix_user_function) (connection,
-                                              uid,
-                                              unix_user_data);
-              
-              _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
-              _dbus_connection_lock (connection);
-
-              if (allow)
-                {
-                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
-                }
-              else
-                {
-                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT
-                                 " was rejected, disconnecting\n",
-                                 _dbus_credentials_get_unix_uid (auth_identity));
-                  _dbus_transport_disconnect (transport);
-                  _dbus_connection_unref_unlocked (connection);
-                  return FALSE;
-                }
+              allow = auth_via_unix_user_function (transport);
             }
+          else if (transport->windows_user_function != NULL &&
+                   _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
+            {
+              allow = auth_via_windows_user_function (transport);
+            }      
           else
             {
-              DBusCredentials *our_identity;
-
-              /* By default, connection is allowed if the client is
-               * 1) root or 2) has the same UID as us
-               */
-              
-              our_identity = _dbus_credentials_new_from_current_process ();
-              if (our_identity == NULL)
-                {
-                  /* OOM */
-                  _dbus_connection_unref_unlocked (transport->connection);
-                  return FALSE;
-                }
-              
-              if (_dbus_credentials_get_unix_uid (auth_identity) == 0 ||
-                  !_dbus_credentials_same_user (our_identity,
-                                                auth_identity))
-                {
-                  /* FIXME the verbose spam here is unix-specific */
-                  _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
-                                 " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
-                                 _dbus_credentials_get_unix_uid(our_identity),
-                                 _dbus_credentials_get_unix_uid(our_identity));
-                  _dbus_transport_disconnect (transport);
-                  _dbus_connection_unref_unlocked (transport->connection);
-                  return FALSE;
-                }
-              else
-                {
-                  /* FIXME the verbose spam here is unix-specific */                  
-                  _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
-                                 " matching our UID "DBUS_UID_FORMAT"\n",
-                                 _dbus_credentials_get_unix_uid(auth_identity),
-                                 _dbus_credentials_get_unix_uid(our_identity));
-                }
+              allow = auth_via_default_rules (transport);
             }
+          
+          if (!allow)
+            maybe_authenticated = FALSE;
         }
-      
+
       transport->authenticated = maybe_authenticated;
 
       _dbus_connection_unref_unlocked (transport->connection);
@@ -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
index 4784e46..9e952a1 100644 (file)
@@ -68,6 +68,14 @@ void               _dbus_transport_set_unix_user_function (DBusTransport
                                                            DBusFreeFunction            free_data_function,
                                                            void                      **old_data,
                                                            DBusFreeFunction           *old_free_data_function);
+dbus_bool_t        _dbus_transport_get_windows_user       (DBusTransport              *transport,
+                                                           char                      **windows_sid_p);
+void               _dbus_transport_set_windows_user_function (DBusTransport              *transport,
+                                                              DBusAllowWindowsUserFunction   function,
+                                                              void                       *data,
+                                                              DBusFreeFunction            free_data_function,
+                                                              void                      **old_data,
+                                                              DBusFreeFunction           *old_free_data_function);
 dbus_bool_t        _dbus_transport_set_auth_mechanisms    (DBusTransport              *transport,
                                                            const char                **mechanisms);