diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-04-01 05:33:01 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-04-01 05:33:01 +0000 | 
| commit | 44ed933284589134603913b05f55ca55e8c5a566 (patch) | |
| tree | 7091c28eba6a2d93cd02ca80c39b3175ccca06f5 | |
| parent | 8dfe82beb530aefce505a9bf915a749647e7183f (diff) | |
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
| -rw-r--r-- | ChangeLog | 27 | ||||
| -rw-r--r-- | bus/bus.c | 84 | ||||
| -rw-r--r-- | bus/config-parser.c | 70 | ||||
| -rw-r--r-- | bus/config-parser.h | 6 | ||||
| -rw-r--r-- | bus/system.conf.in | 20 | ||||
| -rw-r--r-- | dbus/dbus-auth.c | 78 | ||||
| -rw-r--r-- | dbus/dbus-auth.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-internals.c | 77 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 7 | ||||
| -rw-r--r-- | dbus/dbus-server-debug-pipe.c | 9 | ||||
| -rw-r--r-- | dbus/dbus-server-protected.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-server-unix.c | 7 | ||||
| -rw-r--r-- | dbus/dbus-server.c | 33 | ||||
| -rw-r--r-- | dbus/dbus-server.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 151 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 6 | ||||
| -rw-r--r-- | dbus/dbus-transport.c | 16 | ||||
| -rw-r--r-- | dbus/dbus-transport.h | 3 | ||||
| -rw-r--r-- | doc/config-file.txt | 10 | 
19 files changed, 574 insertions, 36 deletions
| @@ -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)  @@ -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;  } diff --git a/bus/config-parser.c b/bus/config-parser.c index 39239888..dc3cb4d6 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -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> diff --git a/bus/config-parser.h b/bus/config-parser.h index 8c66fa63..101b4c6f 100644 --- a/bus/config-parser.h +++ b/bus/config-parser.h @@ -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. diff --git a/bus/system.conf.in b/bus/system.conf.in index fe4e049a..7752b576 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -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="*"/> diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index fd4f60dc..e687dd66 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -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   */ diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h index 8309fe33..98e4369d 100644 --- a/dbus/dbus-auth.h +++ b/dbus/dbus-auth.h @@ -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); diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 7c11b9f5..f1fbf963 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -107,18 +107,6 @@   *   * 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 diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index dcf01e48..7e4138c9 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -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) diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c index 76f734b4..c6063220 100644 --- a/dbus/dbus-server-debug-pipe.c +++ b/dbus/dbus-server-debug-pipe.c @@ -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; diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index 475bf3a2..78872291 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -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. */  }; diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index e5e6d70e..c718923f 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -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     */ diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 9f70649b..be74ead0 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -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 diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h index e36ed86e..152c7f97 100644 --- a/dbus/dbus-server.h +++ b/dbus/dbus-server.h @@ -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); diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index cab970a0..71863ef6 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -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 */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index ac4e828a..6a6a965b 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -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 */ diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 96bc6b64..e56c8b0c 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -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); +} + +  /** @} */ diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 128f0fe3..910642b7 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -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); diff --git a/doc/config-file.txt b/doc/config-file.txt index 5502c82b..b8230aab 100644 --- a/doc/config-file.txt +++ b/doc/config-file.txt @@ -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> | 
