2003-04-01 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Tue, 1 Apr 2003 05:33:01 +0000 (05:33 +0000)
committerHavoc Pennington <hp@redhat.com>
Tue, 1 Apr 2003 05:33:01 +0000 (05:33 +0000)
* dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new
function

* dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new

* dbus/dbus-internals.c (_dbus_dup_string_array): new function

* dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the
socket 0777, and unlink any existing socket.

* bus/bus.c (bus_context_new): change our UID/GID and fork if
the configuration file so specifies; set up auth mechanism
restrictions

* bus/config-parser.c (bus_config_parser_content): add support
for <fork> option and fill in code for <auth>

* bus/system.conf.in: add <fork/> to default configuration,
and limit auth mechanisms to EXTERNAL

* doc/config-file.txt (Elements): add <fork>

* dbus/dbus-sysdeps.c (_dbus_become_daemon): new function
(_dbus_change_identity): new function

19 files changed:
ChangeLog
bus/bus.c
bus/config-parser.c
bus/config-parser.h
bus/system.conf.in
dbus/dbus-auth.c
dbus/dbus-auth.h
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-server-debug-pipe.c
dbus/dbus-server-protected.h
dbus/dbus-server-unix.c
dbus/dbus-server.c
dbus/dbus-server.h
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h
dbus/dbus-transport.c
dbus/dbus-transport.h
doc/config-file.txt

index 4e987f4..602341a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2003-04-01  Havoc Pennington  <hp@pobox.com>
+
+       * dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new
+       function
+
+       * dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new
+
+       * dbus/dbus-internals.c (_dbus_dup_string_array): new function
+
+       * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the
+       socket 0777, and unlink any existing socket.
+
+       * bus/bus.c (bus_context_new): change our UID/GID and fork if
+       the configuration file so specifies; set up auth mechanism 
+       restrictions
+
+       * bus/config-parser.c (bus_config_parser_content): add support
+       for <fork> option and fill in code for <auth> 
+
+       * bus/system.conf.in: add <fork/> to default configuration, 
+       and limit auth mechanisms to EXTERNAL
+
+       * doc/config-file.txt (Elements): add <fork>
+
+       * dbus/dbus-sysdeps.c (_dbus_become_daemon): new function
+       (_dbus_change_identity): new function
+
 2003-03-31  Havoc Pennington  <hp@redhat.com>
 
        * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket) 
index ca9802c..1ca4feb 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -141,8 +141,15 @@ free_rule_list_func (void *data)
 static dbus_bool_t
 setup_server (BusContext *context,
               DBusServer *server,
+              char      **auth_mechanisms,
               DBusError  *error)
-{  
+{
+  if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  
   dbus_server_set_new_connection_function (server,
                                            new_connection_callback,
                                            context, NULL);
@@ -181,6 +188,10 @@ bus_context_new (const DBusString *config_file,
   BusConfigParser *parser;
   DBusString full_address;
   const char *service_dirs[] = { NULL, NULL };
+  const char *user;
+  char **auth_mechanisms;
+  DBusList **auth_mechanisms_list;
+  int len;
   
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -189,6 +200,7 @@ bus_context_new (const DBusString *config_file,
 
   parser = NULL;
   context = NULL;
+  auth_mechanisms = NULL;
   
   parser = bus_config_load (config_file, error);
   if (parser == NULL)
@@ -202,6 +214,36 @@ bus_context_new (const DBusString *config_file,
     }
   
   context->refcount = 1;
+
+  /* Build an array of auth mechanisms */
+  
+  auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
+  len = _dbus_list_get_length (auth_mechanisms_list);
+
+  if (len > 0)
+    {
+      int i;
+
+      auth_mechanisms = dbus_new0 (char*, len + 1);
+      if (auth_mechanisms == NULL)
+        goto failed;
+      
+      i = 0;
+      link = _dbus_list_get_first_link (auth_mechanisms_list);
+      while (link != NULL)
+        {
+          auth_mechanisms[i] = _dbus_strdup (link->data);
+          if (auth_mechanisms[i] == NULL)
+            goto failed;
+          link = _dbus_list_get_next_link (auth_mechanisms_list, link);
+        }
+    }
+  else
+    {
+      auth_mechanisms = NULL;
+    }
+
+  /* Listen on our addresses */
   
   addresses = bus_config_parser_get_addresses (parser);  
   
@@ -213,7 +255,7 @@ bus_context_new (const DBusString *config_file,
       server = dbus_server_listen (link->data, error);
       if (server == NULL)
         goto failed;
-      else if (!setup_server (context, server, error))
+      else if (!setup_server (context, server, auth_mechanisms, error))
         goto failed;
 
       if (!_dbus_list_append (&context->servers, server))
@@ -225,6 +267,31 @@ bus_context_new (const DBusString *config_file,
       link = _dbus_list_get_next_link (addresses, link);
     }
 
+  /* Here we change our credentials if required,
+   * as soon as we've set up our sockets
+   */
+  user = bus_config_parser_get_user (parser);
+  if (user != NULL)
+    {
+      DBusCredentials creds;
+      DBusString u;
+
+      _dbus_string_init_const (&u, user);
+
+      if (!_dbus_credentials_from_username (&u, &creds) ||
+          creds.uid < 0 ||
+          creds.gid < 0)
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "Could not get UID and GID for username \"%s\"",
+                          user);
+          goto failed;
+        }
+      
+      if (!_dbus_change_identity (creds.uid, creds.gid, error))
+        goto failed;
+    }
+  
   /* We have to build the address backward, so that
    * <listen> later in the config file have priority
    */
@@ -265,6 +332,8 @@ bus_context_new (const DBusString *config_file,
       BUS_SET_OOM (error);
       goto failed;
     }
+
+  /* Create activation subsystem */
   
   context->activation = bus_activation_new (context, &full_address,
                                             service_dirs, error);
@@ -306,12 +375,20 @@ bus_context_new (const DBusString *config_file,
       goto failed;
     }
 
+  /* Now become a daemon if appropriate */
+  if (bus_config_parser_get_fork (parser))
+    {
+      if (!_dbus_become_daemon (error))
+        goto failed;
+    }
+  
   bus_config_parser_unref (parser);
   _dbus_string_free (&full_address);
+  dbus_free_string_array (auth_mechanisms);
   
   return context;
   
- failed:
+ failed:  
   if (parser != NULL)
     bus_config_parser_unref (parser);
 
@@ -319,6 +396,7 @@ bus_context_new (const DBusString *config_file,
     bus_context_unref (context);
 
   _dbus_string_free (&full_address);
+  dbus_free_string_array (auth_mechanisms);
   return NULL;
 }
 
index 3923988..dc3cb4d 100644 (file)
@@ -37,7 +37,8 @@ typedef enum
   ELEMENT_POLICY,
   ELEMENT_LIMIT,
   ELEMENT_ALLOW,
-  ELEMENT_DENY
+  ELEMENT_DENY,
+  ELEMENT_FORK
 } ElementType;
 
 typedef struct
@@ -84,6 +85,10 @@ struct BusConfigParser
   char *user;          /**< user to run as */
 
   DBusList *listen_on; /**< List of addresses to listen to */
+
+  DBusList *mechanisms; /**< Auth mechanisms */
+  
+  unsigned int fork : 1; /**< TRUE to fork into daemon mode */
 };
 
 static const char*
@@ -111,6 +116,8 @@ element_type_to_name (ElementType type)
       return "allow";
     case ELEMENT_DENY:
       return "deny";
+    case ELEMENT_FORK:
+      return "fork";
     }
 
   _dbus_assert_not_reached ("bad element type");
@@ -195,9 +202,15 @@ merge_included (BusConfigParser *parser,
       included->user = NULL;
     }
 
+  if (included->fork)
+    parser->fork = TRUE;
+  
   while ((link = _dbus_list_pop_first_link (&included->listen_on)))
     _dbus_list_append_link (&parser->listen_on, link);
 
+  while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
+    _dbus_list_append_link (&parser->mechanisms, link);
+  
   return TRUE;
 }
 
@@ -409,6 +422,21 @@ start_busconfig_child (BusConfigParser   *parser,
 
       return TRUE;
     }
+  else if (strcmp (element_name, "fork") == 0)
+    {
+      if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error))
+        return FALSE;
+
+      if (push_element (parser, ELEMENT_FORK) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      parser->fork = TRUE;
+      
+      return TRUE;
+    }
   else if (strcmp (element_name, "listen") == 0)
     {
       if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
@@ -422,6 +450,19 @@ start_busconfig_child (BusConfigParser   *parser,
 
       return TRUE;
     }
+  else if (strcmp (element_name, "auth") == 0)
+    {
+      if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
+        return FALSE;
+
+      if (push_element (parser, ELEMENT_AUTH) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      return TRUE;
+    }
   else if (strcmp (element_name, "include") == 0)
     {
       Element *e;
@@ -654,6 +695,7 @@ bus_config_parser_end_element (BusConfigParser   *parser,
     case ELEMENT_LIMIT:
     case ELEMENT_ALLOW:
     case ELEMENT_DENY:
+    case ELEMENT_FORK:
       break;
     }
 
@@ -715,6 +757,7 @@ bus_config_parser_content (BusConfigParser   *parser,
     case ELEMENT_LIMIT:
     case ELEMENT_ALLOW:
     case ELEMENT_DENY:
+    case ELEMENT_FORK:
       if (all_whitespace (content))
         return TRUE;
       else
@@ -800,8 +843,19 @@ bus_config_parser_content (BusConfigParser   *parser,
 
     case ELEMENT_AUTH:
       {
+        char *s;
+        
         e->had_content = TRUE;
-        /* FIXME */
+
+        if (!_dbus_string_copy_data (content, &s))
+          goto nomem;
+
+        if (!_dbus_list_append (&parser->mechanisms,
+                                s))
+          {
+            dbus_free (s);
+            goto nomem;
+          }
       }
       break;
     }
@@ -851,6 +905,18 @@ bus_config_parser_get_addresses (BusConfigParser *parser)
   return &parser->listen_on;
 }
 
+DBusList**
+bus_config_parser_get_mechanisms (BusConfigParser *parser)
+{
+  return &parser->mechanisms;
+}
+
+dbus_bool_t
+bus_config_parser_get_fork (BusConfigParser   *parser)
+{
+  return parser->fork;
+}
+
 #ifdef DBUS_BUILD_TESTS
 #include <stdio.h>
 
index 8c66fa6..101b4c6 100644 (file)
@@ -55,8 +55,10 @@ dbus_bool_t      bus_config_parser_finished      (BusConfigParser   *parser,
                                                   DBusError         *error);
 
 /* Functions for extracting the parse results */
-const char*      bus_config_parser_get_user      (BusConfigParser   *parser);
-DBusList**       bus_config_parser_get_addresses (BusConfigParser   *parser);
+const char*      bus_config_parser_get_user       (BusConfigParser   *parser);
+DBusList**       bus_config_parser_get_addresses  (BusConfigParser   *parser);
+DBusList**       bus_config_parser_get_mechanisms (BusConfigParser   *parser);
+dbus_bool_t      bus_config_parser_get_fork       (BusConfigParser   *parser);
 
 /* Loader functions (backended off one of the XML parsers).  Returns a
  * finished ConfigParser.
index fe4e049..7752b57 100644 (file)
@@ -2,13 +2,29 @@
      Add a system-local.conf and edit that rather than changing this 
      file directly. -->
 
+<!-- Note that there are any number of ways you can hose yourself
+     security-wise by screwing up this file; in particular, you
+     probably don't want to listen on any more addresses, add any more
+     auth mechanisms, run as a different user, etc. -->
+
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
-  <user>fixme</user>
+
+  <!-- Run as special user -->
+  <user>messagebus</user>
+
+  <!-- Fork into daemon mode -->
+  <fork/>
+
+  <!-- Only allow socket-credentials-based authentication -->
+  <auth>EXTERNAL</auth>
+
+  <!-- Only listen on a local socket -->
   <listen>unix:path=@EXPANDED_LOCALSTATEDIR@/@DBUS_SYSTEM_SOCKET@</listen>
+
   <policy context="default">
-    <!-- Deny everything -->
+    <!-- Deny everything then punch holes -->
     <deny send="*"/>
     <deny receive="*"/>
     <deny own="*"/>
index fd4f60d..e687dd6 100644 (file)
@@ -159,6 +159,10 @@ struct DBusAuth
   DBusKeyring *keyring;             /**< Keyring for cookie mechanism. */
   int cookie_id;                    /**< ID of cookie to use */
   DBusString challenge;             /**< Challenge sent to client */
+
+  char **allowed_mechs;             /**< Mechanisms we're allowed to use,
+                                     * or #NULL if we can use any
+                                     */
   
   unsigned int needed_memory : 1;   /**< We needed memory to continue since last
                                      * successful getting something done
@@ -1134,13 +1138,19 @@ all_mechanisms[] = {
 };
 
 static const DBusAuthMechanismHandler*
-find_mech (const DBusString *name)
+find_mech (const DBusString  *name,
+           char             **allowed_mechs)
 {
   int i;
   
+  if (allowed_mechs != NULL &&
+      !_dbus_string_array_contains ((const char**) allowed_mechs,
+                                    _dbus_string_get_const_data (name)))
+    return NULL;
+  
   i = 0;
   while (all_mechanisms[i].mechanism != NULL)
-    {
+    {      
       if (_dbus_string_equal_c_str (name,
                                     all_mechanisms[i].mechanism))
 
@@ -1259,7 +1269,7 @@ process_auth (DBusAuth         *auth,
                                        &decoded_response, 0))
         goto failed;
       
-      auth->mech = find_mech (&mech);
+      auth->mech = find_mech (&mech, auth->allowed_mechs);
       if (auth->mech != NULL)
         {
           _dbus_verbose ("Trying mechanism %s with initial response of %d bytes\n",
@@ -1418,7 +1428,7 @@ record_mechanisms (DBusAuth         *auth,
       if (!get_word (args, &next, &m))
         goto nomem;
 
-      mech = find_mech (&m);
+      mech = find_mech (&m, auth->allowed_mechs);
 
       if (mech != NULL)
         {
@@ -1462,11 +1472,32 @@ client_try_next_mechanism (DBusAuth *auth)
 {
   const DBusAuthMechanismHandler *mech;
   DBusString auth_command;
+  DBusAuthClient *client;
 
-  if (DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
-    return FALSE;
+  client = DBUS_AUTH_CLIENT (auth);
+  
+  /* Pop any mechs not in the list of allowed mechanisms */
+  mech = NULL;
+  while (client->mechs_to_try != NULL)
+    {
+      mech = client->mechs_to_try->data;
 
-  mech = DBUS_AUTH_CLIENT (auth)->mechs_to_try->data;
+      if (auth->allowed_mechs != NULL && 
+          !_dbus_string_array_contains ((const char**) auth->allowed_mechs,
+                                        mech->mechanism))
+        {
+          /* don't try this one after all */
+          _dbus_verbose ("Mechanism %s isn't in the list of allowed mechanisms\n",
+                         mech->mechanism);
+          mech = NULL;
+          _dbus_list_pop_first (& client->mechs_to_try);
+        }
+      else
+        break; /* we'll try this one */
+    }
+  
+  if (mech == NULL)
+    return FALSE;
 
   if (!_dbus_string_init (&auth_command))
     return FALSE;
@@ -1859,11 +1890,44 @@ _dbus_auth_unref (DBusAuth *auth)
       _dbus_string_free (&auth->identity);
       _dbus_string_free (&auth->incoming);
       _dbus_string_free (&auth->outgoing);
+
+      dbus_free_string_array (auth->allowed_mechs);
+      
       dbus_free (auth);
     }
 }
 
 /**
+ * Sets an array of authentication mechanism names
+ * that we are willing to use.
+ *
+ * @param auth the auth conversation
+ * @param mechanisms #NULL-terminated array of mechanism names
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_auth_set_mechanisms (DBusAuth    *auth,
+                           const char **mechanisms)
+{
+  char **copy;
+
+  if (mechanisms != NULL)
+    {
+      copy = _dbus_dup_string_array (mechanisms);
+      if (copy == NULL)
+        return FALSE;
+    }
+  else
+    copy = NULL;
+  
+  dbus_free_string_array (auth->allowed_mechs);
+
+  auth->allowed_mechs = copy;
+
+  return TRUE;
+}
+
+/**
  * @param auth the auth conversation object
  * @returns #TRUE if we're in a final state
  */
index 8309fe3..98e4369 100644 (file)
@@ -46,6 +46,8 @@ DBusAuth*     _dbus_auth_server_new          (void);
 DBusAuth*     _dbus_auth_client_new          (void);
 void          _dbus_auth_ref                 (DBusAuth               *auth);
 void          _dbus_auth_unref               (DBusAuth               *auth);
+dbus_bool_t   _dbus_auth_set_mechanisms      (DBusAuth               *auth,
+                                              const char            **mechanisms);
 DBusAuthState _dbus_auth_do_work             (DBusAuth               *auth);
 dbus_bool_t   _dbus_auth_get_bytes_to_send   (DBusAuth               *auth,
                                               const DBusString      **str);
index 7c11b9f..f1fbf96 100644 (file)
  *
  * Maximum value of type "int"
  */
-/**
- * @def _DBUS_MAX_SUN_PATH_LENGTH
- *
- * Maximum length of the path to a UNIX domain socket,
- * sockaddr_un::sun_path member. POSIX requires that all systems
- * support at least 100 bytes here, including the nul termination.
- * We use 99 for the max value to allow for the nul.
- *
- * We could probably also do sizeof (addr.sun_path)
- * but this way we are the same on all platforms
- * which is probably a good idea.
- */
 
 /**
  * @typedef DBusForeachFunction
@@ -251,6 +239,71 @@ _dbus_strdup (const char *str)
 }
 
 /**
+ * Duplicates a string array. Result may be freed with
+ * dbus_free_string_array(). Returns #NULL if memory allocation fails.
+ * If the array to be duplicated is #NULL, returns #NULL.
+ * 
+ * @param array array to duplicate.
+ * @returns newly-allocated copy.
+ */
+char**
+_dbus_dup_string_array (const char **array)
+{
+  int len;
+  int i;
+  char **copy;
+  
+  if (array == NULL)
+    return NULL;
+
+  for (len = 0; array[len] != NULL; ++len)
+    ;
+
+  copy = dbus_new0 (char*, len + 1);
+  if (copy == NULL)
+    return NULL;
+
+  i = 0;
+  while (i < len)
+    {
+      copy[i] = _dbus_strdup (array[i]);
+      if (copy[i] == NULL)
+        {
+          dbus_free_string_array (copy);
+          return NULL;
+        }
+
+      ++i;
+    }
+
+  return copy;
+}
+
+/**
+ * Checks whether a string array contains the given string.
+ * 
+ * @param array array to search.
+ * @param str string to look for
+ * @returns #TRUE if array contains string
+ */
+dbus_bool_t
+_dbus_string_array_contains (const char **array,
+                             const char  *str)
+{
+  int i;
+
+  i = 0;
+  while (array[i] != NULL)
+    {
+      if (strcmp (array[i], str) == 0)
+        return TRUE;
+      ++i;
+    }
+
+  return FALSE;
+}
+
+/**
  * Returns a string describing the given type.
  *
  * @param type the type to describe
index dcf01e4..7e4138c 100644 (file)
@@ -128,12 +128,15 @@ do {
 #define _DBUS_ALIGN_ADDRESS(this, boundary) \
   ((void*)_DBUS_ALIGN_VALUE(this, boundary))
 
-char* _dbus_strdup (const char *str);
+char*       _dbus_strdup                (const char  *str);
+dbus_bool_t _dbus_string_array_contains (const char **array,
+                                         const char  *str);
+char**      _dbus_dup_string_array      (const char **array);
+
 
 #define _DBUS_INT_MIN  (-_DBUS_INT_MAX - 1)
 #define _DBUS_INT_MAX  2147483647
 #define _DBUS_UINT_MAX 0xffffffff
-#define _DBUS_MAX_SUN_PATH_LENGTH 99
 #define _DBUS_ONE_KILOBYTE 1024
 #define _DBUS_ONE_MEGABYTE 1024 * _DBUS_ONE_KILOBYTE
 #define _DBUS_ONE_HOUR_IN_MILLISECONDS (1000 * 60 * 60)
index 76f734b..c606322 100644 (file)
@@ -283,6 +283,15 @@ _dbus_transport_debug_pipe_new (const char     *server_name,
 
   server_fd = -1;
 
+  if (!_dbus_transport_set_auth_mechanisms (server_transport,
+                                            (const char**) server->auth_mechanisms))
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      _dbus_transport_unref (server_transport);
+      _dbus_transport_unref (client_transport);
+      return FALSE;
+    }
+  
   connection = _dbus_connection_new_for_transport (server_transport);
   _dbus_transport_unref (server_transport);
   server_transport = NULL;
index 475bf3a..7887229 100644 (file)
@@ -75,6 +75,8 @@ struct DBusServer
   /**< Callback to invoke to free new_connection_data
    * when server is finalized or data is replaced.
    */
+
+  char **auth_mechanisms; /**< Array of allowed authentication mechanisms */
   
   unsigned int disconnected : 1;              /**< TRUE if we are disconnected. */
 };
index e5e6d70..c718923 100644 (file)
@@ -90,6 +90,13 @@ handle_new_client_fd (DBusServer *server,
       return FALSE;
     }
 
+  if (!_dbus_transport_set_auth_mechanisms (transport,
+                                            (const char **) server->auth_mechanisms))
+    {
+      _dbus_transport_unref (transport);
+      return FALSE;
+    }
+  
   /* note that client_fd is now owned by the transport, and will be
    * closed on transport disconnection/finalization
    */
index 9f70649..be74ead 100644 (file)
@@ -143,6 +143,8 @@ _dbus_server_finalize_base (DBusServer *server)
   _dbus_counter_unref (server->connection_counter);
 
   dbus_free (server->address);
+
+  dbus_free_string_array (server->auth_mechanisms);
 }
 
 /**
@@ -600,6 +602,37 @@ dbus_server_handle_watch (DBusServer              *server,
 }
 
 /**
+ * Sets the authentication mechanisms that this server offers
+ * to clients, as a list of SASL mechanisms. This function
+ * only affects connections created *after* it is called.
+ * Pass #NULL instead of an array to use all available mechanisms.
+ *
+ * @param server the server
+ * @param mechanisms #NULL-terminated array of mechanisms
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+dbus_server_set_auth_mechanisms (DBusServer  *server,
+                                 const char **mechanisms)
+{
+  char **copy;
+
+  if (mechanisms != NULL)
+    {
+      copy = _dbus_dup_string_array (mechanisms);
+      if (copy == NULL)
+        return FALSE;
+    }
+  else
+    copy = NULL;
+
+  dbus_free_string_array (server->auth_mechanisms);
+  server->auth_mechanisms = copy;
+
+  return TRUE;
+}
+
+/**
  * Sets the maximum number of connections that can be open at one
  * time for this server. If the maximum is reached, and another
  * client tries to connect, then the oldest unauthenticated client
index e36ed86..152c7f9 100644 (file)
@@ -70,6 +70,8 @@ void        dbus_server_set_max_connections         (DBusServer                *
 int         dbus_server_get_max_connections         (DBusServer                *server);
 int         dbus_server_get_n_connections           (DBusServer                *server);
 
+dbus_bool_t dbus_server_set_auth_mechanisms         (DBusServer                *server,
+                                                     const char               **mechanisms);
 
 int         dbus_server_allocate_data_slot (void);
 void        dbus_server_free_data_slot     (int               slot);
index cab970a..71863ef 100644 (file)
@@ -313,6 +313,21 @@ _dbus_write_two (int               fd,
 #endif /* !HAVE_WRITEV */   
 }
 
+#define _DBUS_MAX_SUN_PATH_LENGTH 99
+
+/**
+ * @def _DBUS_MAX_SUN_PATH_LENGTH
+ *
+ * Maximum length of the path to a UNIX domain socket,
+ * sockaddr_un::sun_path member. POSIX requires that all systems
+ * support at least 100 bytes here, including the nul termination.
+ * We use 99 for the max value to allow for the nul.
+ *
+ * We could probably also do sizeof (addr.sun_path)
+ * but this way we are the same on all platforms
+ * which is probably a good idea.
+ */
+
 /**
  * Creates a socket and connects it to the UNIX domain socket at the
  * given path.  The connection fd is returned, and is set up as
@@ -345,8 +360,7 @@ _dbus_connect_unix_socket (const char     *path,
 
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
-  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
-  addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0';
+  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
   
   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
     {      
@@ -377,7 +391,13 @@ _dbus_connect_unix_socket (const char     *path,
 /**
  * Creates a socket and binds it to the given path,
  * then listens on the socket. The socket is
- * set to be nonblocking. 
+ * set to be nonblocking.
+ *
+ * @todo we'd like to be able to use the abstract namespace on linux
+ * (see "man 7 unix"). The question is whether to silently move all
+ * paths into that namespace if we can (I think that's best) or to
+ * require it to be specified explicitly in the dbus address.  Also,
+ * need to sort out how to check for abstract namespace support.
  *
  * @param path the socket name
  * @param error return location for errors
@@ -402,10 +422,27 @@ _dbus_listen_unix_socket (const char     *path,
       return -1;
     }
 
+  /* FIXME discussed security implications of this with Nalin,
+   * and we couldn't think of where it would kick our ass, but
+   * it still seems a bit sucky. It also has non-security suckage;
+   * really we'd prefer to exit if the socket is already in use.
+   * But there doesn't seem to be a good way to do this.
+   *
+   * Just to be extra careful, I threw in the stat() - clearly
+   * the stat() can't *fix* any security issue, but it probably
+   * makes it harder to exploit.
+   */
+  {
+    struct stat sb;
+
+    if (stat (path, &sb) == 0 &&
+        S_ISSOCK (sb.st_mode))
+      unlink (path);
+  }
+  
   _DBUS_ZERO (addr);
   addr.sun_family = AF_UNIX;
-  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
-  addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH-1] = '\0';
+  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
   
   if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
     {
@@ -431,6 +468,13 @@ _dbus_listen_unix_socket (const char     *path,
       close (listen_fd);
       return -1;
     }
+
+  /* Try opening up the permissions, but if we can't, just go ahead
+   * and continue, maybe it will be good enough.
+   */
+  if (chmod (path, 0777) < 0)
+    _dbus_warn ("Could not set mode 0777 on socket %s\n",
+                path);
   
   return listen_fd;
 }
@@ -3063,4 +3107,101 @@ _dbus_print_backtrace (void)
 #endif
 }
 
+/**
+ * Does the chdir, fork, setsid, etc. to become a daemon process.
+ *
+ * @param error return location for errors
+ * @returns #FALSE on failure
+ */
+dbus_bool_t
+_dbus_become_daemon (DBusError *error)
+{
+  const char *s;
+
+  /* This is so we don't prevent unmounting of devices. We divert
+   * all messages to syslog
+   */
+  if (chdir ("/") < 0)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Could not chdir() to root directory");
+      return FALSE;
+    }
+
+  s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
+  if (s == NULL || *s == '\0')
+    {
+      int dev_null_fd;
+
+      /* silently ignore failures here, if someone
+       * doesn't have /dev/null we may as well try
+       * to continue anyhow
+       */
+
+      dev_null_fd = open ("/dev/null", O_RDWR);
+      if (dev_null_fd >= 0)
+        {
+         dup2 (dev_null_fd, 0);
+         dup2 (dev_null_fd, 1);
+         dup2 (dev_null_fd, 2);
+       }
+    }
+
+  /* Get a predictable umask */
+  umask (022);
+
+  switch (fork ())
+    {
+    case -1:
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Failed to fork daemon: %s", _dbus_strerror (errno));
+      return FALSE;
+      break;
+
+    case 0:      
+      break;
+
+    default:
+      _exit (0);
+      break;
+    }
+
+  if (setsid () == -1)
+    _dbus_assert_not_reached ("setsid() failed");
+  
+  return TRUE;
+}
+
+/**
+ * Changes the user and group the bus is running as.
+ *
+ * @param uid the new user ID
+ * @param gid the new group ID
+ * @param error return location for errors
+ * @returns #FALSE on failure
+ */
+dbus_bool_t
+_dbus_change_identity  (unsigned long  uid,
+                        unsigned long  gid,
+                        DBusError     *error)
+{
+  if (setuid (uid) < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Failed to set UID to %lu: %s", uid,
+                      _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  if (setgid (gid) < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "Failed to set GID to %lu: %s", gid,
+                      _dbus_strerror (errno));
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
 /** @} end of sysdeps */
index ac4e828..6a6a965 100644 (file)
@@ -217,6 +217,12 @@ dbus_bool_t _dbus_close            (int               fd,
 
 void        _dbus_print_backtrace  (void);
 
+dbus_bool_t _dbus_become_daemon    (DBusError *error);
+
+dbus_bool_t _dbus_change_identity  (unsigned long  uid,
+                                    unsigned long  gid,
+                                    DBusError     *error);
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_SYSDEPS_H */
index 96bc6b6..e56c8b0 100644 (file)
@@ -907,4 +907,20 @@ _dbus_transport_set_unix_user_function (DBusTransport             *transport,
   transport->free_unix_user_data = free_data_function;
 }
 
+/**
+ * Sets the SASL authentication mechanisms supported by this transport.
+ *
+ * @param transport the transport
+ * @param mechanisms the #NULL-terminated array of mechanisms
+ *
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
+                                     const char    **mechanisms)
+{
+  return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
+}
+
+
 /** @} */
index 128f0fe..910642b 100644 (file)
@@ -64,7 +64,8 @@ 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_set_auth_mechanisms        (DBusTransport             *transport,
+                                                               const char               **mechanisms);
 
 
 
index 5502c82..b8230aa 100644 (file)
@@ -53,6 +53,15 @@ Elements:
  
     The last <user> entry in the file "wins", the others are ignored.
 
+    The user is changed after the bus has completed initialization. 
+    So sockets etc. will be created before changing user, but no 
+    data will be read from clients before changing user.
+
+ <fork>
+    
+    If present, the bus daemon becomes a real daemon (forks 
+    into the background, etc.)
+
  <listen>
 
     Add an address that the bus should listen on. The 
@@ -72,6 +81,7 @@ Elements:
     Lists permitted authorization mechanisms. If this element doesn't
     exist, then all known mechanisms are allowed.  If there are
     multiple <auth> elements, the last one wins (they are not merged).
+    The order in which mechanisms are listed is not meaningful.
     
     Example: <auth>EXTERNAL</auth>
     Example: <auth>DBUS_COOKIE_SHA1</auth>