diff options
| author | Colin Walters <walters@verbum.org> | 2008-07-24 16:19:34 -0400 | 
|---|---|---|
| committer | Colin Walters <walters@verbum.org> | 2008-07-24 16:19:34 -0400 | 
| commit | d86df0220e37b9bf10878625664b44b5d79ee488 (patch) | |
| tree | 0f7d2cd535d35823499ecf262b5d24870522483c | |
| parent | 4cbc30465e4fba8026240945cac7a651fda5dca3 (diff) | |
| parent | 3bc6840b04108d895ec3962ed5933bb0edb20cf4 (diff) | |
Merge branch 'master' of ssh://walters@git.freedesktop.org/git/dbus/dbus
| -rw-r--r-- | bus/activation.c | 233 | ||||
| -rw-r--r-- | bus/activation.h | 5 | ||||
| -rw-r--r-- | bus/dbus-daemon.1.in | 16 | ||||
| -rw-r--r-- | bus/driver.c | 131 | ||||
| -rw-r--r-- | bus/system.conf.in | 4 | ||||
| -rw-r--r-- | dbus/dbus-spawn.c | 15 | ||||
| -rw-r--r-- | dbus/dbus-string-util.c | 25 | ||||
| -rw-r--r-- | dbus/dbus-string.c | 42 | ||||
| -rw-r--r-- | dbus/dbus-string.h | 3 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 42 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 1 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 34 | 
12 files changed, 531 insertions, 20 deletions
diff --git a/bus/activation.c b/bus/activation.c index d087d6bd..18630958 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -51,6 +51,7 @@ struct BusActivation                                * activations per se                                */    DBusHashTable *directories; +  DBusHashTable *environment;  };  typedef struct @@ -671,6 +672,69 @@ update_directory (BusActivation       *activation,    return retval;  } +static dbus_bool_t +populate_environment (BusActivation *activation) +{ +  DBusString   key; +  DBusString   value; +  int          i; +  char       **environment; +  dbus_bool_t  retval; + +  environment = _dbus_get_environment (); + +  if (environment == NULL) +    return FALSE; + +  if (!_dbus_string_init (&key)) +    { +        dbus_free_string_array (environment); +        return FALSE; +    } + +  if (!_dbus_string_init (&value)) +    { +      _dbus_string_free (&key); +      dbus_free_string_array (environment); +      return FALSE; +    } + +  for (i = 0; environment[i] != NULL; i++) +    { +      if (!_dbus_string_append (&key, environment[i])) +        break; + +      if (_dbus_string_split_on_byte (&key, '=', &value)) +        { +          char *hash_key, *hash_value; + +          if (!_dbus_string_steal_data (&key, &hash_key)) +            break; + +          if (!_dbus_string_steal_data (&value, &hash_value)) +            break; + +          if (!_dbus_hash_table_insert_string (activation->environment, +                                               hash_key, hash_value)) +            break; +        } +      _dbus_string_set_length (&key, 0); +      _dbus_string_set_length (&value, 0); +    } + +  if (environment[i] != NULL) +    goto out; + +  retval = TRUE; +out: + +  _dbus_string_free (&key); +  _dbus_string_free (&value); +  dbus_free_string_array (environment); + +  return retval; +} +  BusActivation*  bus_activation_new (BusContext        *context,                      const DBusString  *address, @@ -779,6 +843,22 @@ bus_activation_new (BusContext        *context,        link = _dbus_list_get_next_link (directories, link);      } +  activation->environment = _dbus_hash_table_new (DBUS_HASH_STRING, +                                                  (DBusFreeFunction) dbus_free, +                                                  (DBusFreeFunction) dbus_free); +   +  if (activation->environment == NULL)  +    { +      BUS_SET_OOM (error); +      goto failed; +    } + +  if (!populate_environment (activation)) +    { +      BUS_SET_OOM (error); +      goto failed; +    } +    return activation;   failed: @@ -813,41 +893,51 @@ bus_activation_unref (BusActivation *activation)      _dbus_hash_table_unref (activation->pending_activations);    if (activation->directories)        _dbus_hash_table_unref (activation->directories); -   +  if (activation->environment) +    _dbus_hash_table_unref (activation->environment); +    dbus_free (activation);  } -static void -child_setup (void *data) +static dbus_bool_t +add_bus_environment (BusActivation *activation, +                     DBusError     *error)  { -  BusActivation *activation = data;    const char *type; -  /* If no memory, we simply have the child exit, so it won't try -   * to connect to the wrong thing. -   */ -  if (!_dbus_setenv ("DBUS_STARTER_ADDRESS", activation->server_address)) -    _dbus_exit (1); +  if (!bus_activation_set_environment_variable (activation, +                                                "DBUS_STARTER_ADDRESS", +                                                activation->server_address, +                                                error)) +    return FALSE;    type = bus_context_get_type (activation->context);    if (type != NULL)      { -      if (!_dbus_setenv ("DBUS_STARTER_BUS_TYPE", type)) -        _dbus_exit (1); +      if (!bus_activation_set_environment_variable (activation, +                                                    "DBUS_STARTER_BUS_TYPE", type, +                                                    error)) +        return FALSE;        if (strcmp (type, "session") == 0)          { -          if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", -                             activation->server_address)) -            _dbus_exit (1); +          if (!bus_activation_set_environment_variable (activation, +                                                        "DBUS_SESSION_BUS_ADDRESS", +                                                        activation->server_address, +                                                        error)) +            return FALSE;          }        else if (strcmp (type, "system") == 0)          { -          if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS", -                             activation->server_address)) -            _dbus_exit (1); +          if (!bus_activation_set_environment_variable (activation, +                                                        "DBUS_SYSTEM_BUS_ADDRESS", +                                                        activation->server_address, +                                                        error)) +            return FALSE;          }      } + +  return TRUE;  }  typedef struct @@ -1389,6 +1479,95 @@ activation_find_entry (BusActivation *activation,    return entry;  } +static char ** +bus_activation_get_environment (BusActivation *activation) +{ +  char **environment; +  int i, length; +  DBusString entry; +  DBusHashIter iter; + +  length = _dbus_hash_table_get_n_entries (activation->environment); + +  environment = dbus_new0 (char *, length + 1); + +  if (environment == NULL) +    return NULL; + +  i = 0; +  _dbus_hash_iter_init (activation->environment, &iter); + +  if (!_dbus_string_init (&entry)) +    { +      dbus_free_string_array (environment); +      return NULL; +    } + +  while (_dbus_hash_iter_next (&iter)) +    { +      const char *key, *value; + +      key = (const char *) _dbus_hash_iter_get_string_key (&iter); +      value = (const char *) _dbus_hash_iter_get_value (&iter); + +      if (!_dbus_string_append_printf (&entry, "%s=%s", key, value)) +        break; + +      if (!_dbus_string_steal_data (&entry, environment + i)) +        break; +      i++; +    } + +  _dbus_string_free (&entry); + +  if (i != length) +    { +      dbus_free_string_array (environment); +      environment = NULL; +    } + +  return environment; +} + +dbus_bool_t +bus_activation_set_environment_variable (BusActivation     *activation, +                                         const char        *key, +                                         const char        *value, +                                         DBusError         *error) +{ +  char        *hash_key; +  char        *hash_value; +  dbus_bool_t  retval; + +  retval = FALSE; +  hash_key = NULL; +  hash_value = NULL; +  hash_key = _dbus_strdup (key); + +  if (hash_key == NULL) +    goto out; + +  hash_value = _dbus_strdup (value); + +  if (hash_value == NULL) +    goto out; + +  if (!_dbus_hash_table_insert_string (activation->environment, +                                       hash_key, hash_value)) +    goto out; + +  retval = TRUE; +out: +  if (retval == FALSE) +    { +      dbus_free (hash_key); +      dbus_free (hash_value); +      BUS_SET_OOM (error); +    } + +  return retval; +} +  dbus_bool_t  bus_activation_activate_service (BusActivation  *activation,                                   DBusConnection *connection, @@ -1688,20 +1867,38 @@ bus_activation_activate_service (BusActivation  *activation,      }    _dbus_string_free (&command); +  if (!add_bus_environment (activation, error)) +    { +      _DBUS_ASSERT_ERROR_IS_SET (error); +      dbus_free_string_array (argv); +      return FALSE; +    } + +  envp = bus_activation_get_environment (activation); + +  if (envp == NULL) +    { +      BUS_SET_OOM (error); +      dbus_free_string_array (argv); +      return FALSE; +    } +    _dbus_verbose ("Spawning %s ...\n", argv[0]);    if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,                                            envp, -                                          child_setup, activation,  +                                          NULL, activation,                                             error))      {        _dbus_verbose ("Failed to spawn child\n");        _DBUS_ASSERT_ERROR_IS_SET (error);        dbus_free_string_array (argv); +      dbus_free_string_array (envp);        return FALSE;      }    dbus_free_string_array (argv); +  envp = NULL;    _dbus_assert (pending_activation->babysitter != NULL); diff --git a/bus/activation.h b/bus/activation.h index 79084185..56e22836 100644 --- a/bus/activation.h +++ b/bus/activation.h @@ -34,6 +34,11 @@ BusActivation* bus_activation_new              (BusContext        *context,  						DBusError         *error);  BusActivation* bus_activation_ref              (BusActivation     *activation);  void           bus_activation_unref            (BusActivation     *activation); + +dbus_bool_t   bus_activation_set_environment_variable (BusActivation     *activation, +						const char        *key, +						const char        *value, +						DBusError         *error);  dbus_bool_t    bus_activation_activate_service (BusActivation     *activation,  						DBusConnection    *connection,  						BusTransaction    *transaction, diff --git a/bus/dbus-daemon.1.in b/bus/dbus-daemon.1.in index e230e513..5599afe6 100644 --- a/bus/dbus-daemon.1.in +++ b/bus/dbus-daemon.1.in @@ -138,7 +138,21 @@ Root element.  The well-known type of the message bus. Currently known values are  "system" and "session"; if other values are set, they should be  either added to the D-Bus specification, or namespaced.  The last -<type> element "wins" (previous values are ignored). +<type> element "wins" (previous values are ignored). This element +only controls which message bus specific environment variables are +set in activated clients.  Most of the policy that distinguishes a +session bus from the system bus is controlled from the other elements +in the configuration file. + +.PP +If the well-known type of the message bus is "session", then the +DBUS_STARTER_BUS_TYPE environment variable will be set to "session" +and the DBUS_SESSION_BUS_ADDRESS environment variable will be set +to the address of the session bus.  Likewise, if the type of the +message bus is "system", then the DBUS_STARTER_BUS_TYPE environment +variable will be set to "system" and the DBUS_SESSION_BUS_ADDRESS +environment variable will be set to the address of the system bus +(which is normally well known anyway).  .PP  Example: <type>session</type> diff --git a/bus/driver.c b/bus/driver.c index bdf5afbe..05ecd56c 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -811,6 +811,133 @@ send_ack_reply (DBusConnection *connection,  }  static dbus_bool_t +bus_driver_handle_update_activation_environment (DBusConnection *connection, +                                                 BusTransaction *transaction, +                                                 DBusMessage    *message, +                                                 DBusError      *error) +{ +  dbus_bool_t retval; +  BusActivation *activation; +  DBusMessageIter iter; +  DBusMessageIter dict_iter; +  DBusMessageIter dict_entry_iter; +  int msg_type; +  int array_type; +  int key_type; +  DBusList *keys, *key_link; +  DBusList *values, *value_link; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  activation = bus_connection_get_activation (connection); + +  dbus_message_iter_init (message, &iter); + +  /* The message signature has already been checked for us, +   * so let's just assert it's right. +   */ +  msg_type = dbus_message_iter_get_arg_type (&iter); + +  _dbus_assert (msg_type == DBUS_TYPE_ARRAY); + +  dbus_message_iter_recurse (&iter, &dict_iter); + +  retval = FALSE; + +  /* Then loop through the sent dictionary, add the location of +   * the environment keys and values to lists. The result will +   * be in reverse order, so we don't have to constantly search +   * for the end of the list in a loop. +   */ +  keys = NULL; +  values = NULL; +  while ((array_type = dbus_message_iter_get_arg_type (&dict_iter)) == DBUS_TYPE_DICT_ENTRY) +    { +      dbus_message_iter_recurse (&dict_iter, &dict_entry_iter); + +      while ((key_type = dbus_message_iter_get_arg_type (&dict_entry_iter)) == DBUS_TYPE_STRING) +        { +          char *key; +          char *value; +          int value_type; + +          dbus_message_iter_get_basic (&dict_entry_iter, &key); +          dbus_message_iter_next (&dict_entry_iter); + +          value_type = dbus_message_iter_get_arg_type (&dict_entry_iter); + +          if (value_type != DBUS_TYPE_STRING) +            break; + +          dbus_message_iter_get_basic (&dict_entry_iter, &value); + +          if (!_dbus_list_append (&keys, key)) +            { +              BUS_SET_OOM (error); +              break; +            } + +          if (!_dbus_list_append (&values, value)) +            { +              BUS_SET_OOM (error); +              break; +            } + +          dbus_message_iter_next (&dict_entry_iter); +        } + +      if (key_type != DBUS_TYPE_INVALID) +        break; + +      dbus_message_iter_next (&dict_iter); +    } + +  if (array_type != DBUS_TYPE_INVALID) +    goto out; + +  _dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values)); + +  key_link = keys; +  value_link = values; +  while (key_link != NULL) +  { +      const char *key; +      const char *value; + +      key = key_link->data; +      value = value_link->data; + +      if (!bus_activation_set_environment_variable (activation, +                                                    key, value, error)) +      { +          _DBUS_ASSERT_ERROR_IS_SET (error); +          _dbus_verbose ("bus_activation_set_environment_variable() failed\n"); +          break; +      } +      key_link = _dbus_list_get_next_link (&keys, key_link); +      value_link = _dbus_list_get_next_link (&values, value_link); +  } + +  /* FIXME: We can fail early having set only some of the environment variables, +   * (because of OOM failure).  It's sort of hard to fix and it doesn't really +   * matter, so we're punting for now. +   */ +  if (key_link != NULL) +    goto out; + +  if (!send_ack_reply (connection, transaction, +                       message, error)) +    goto out; + +  retval = TRUE; + + out: +  _dbus_list_clear (&keys); +  _dbus_list_clear (&values); +  return retval; +} + +static dbus_bool_t  bus_driver_handle_add_match (DBusConnection *connection,                               BusTransaction *transaction,                               DBusMessage    *message, @@ -1542,6 +1669,10 @@ struct      DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,      DBUS_TYPE_UINT32_AS_STRING,      bus_driver_handle_activate_service }, +  { "UpdateActivationEnvironment", +    DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, +    "", +    bus_driver_handle_update_activation_environment },    { "NameHasOwner",      DBUS_TYPE_STRING_AS_STRING,      DBUS_TYPE_BOOLEAN_AS_STRING, diff --git a/bus/system.conf.in b/bus/system.conf.in index bb468bb9..6a71926e 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -53,6 +53,10 @@      <!-- valid replies are always allowed -->      <allow send_requested_reply="true"/>      <allow receive_requested_reply="true"/> +    <!-- disallow changing the activation environment of system services --> +    <deny send_destination="org.freedesktop.DBus" +          send_interface="org.freedesktop.DBus" +          send_member="UpdateActivationEnvironment"/>    </policy>    <!-- Config files are placed here that among other things, punch  diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c index d74b3265..35ccba6c 100644 --- a/dbus/dbus-spawn.c +++ b/dbus/dbus-spawn.c @@ -880,6 +880,7 @@ write_status_and_exit (int fd, int status)  static void  do_exec (int                       child_err_report_fd,  	 char                    **argv, +	 char                    **envp,  	 DBusSpawnChildSetupFunc   child_setup,  	 void                     *user_data)  { @@ -910,8 +911,17 @@ do_exec (int                       child_err_report_fd,  	_dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);      }  #endif + +  if (envp == NULL) +    { +      extern char **environ; + +      _dbus_assert (environ != NULL); + +      envp = environ; +    } -  execv (argv[0], argv); +  execve (argv[0], argv, envp);    /* Exec failed */    write_err_and_exit (child_err_report_fd, @@ -1190,6 +1200,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,  	{  	  do_exec (child_err_report_pipe[WRITE_END],  		   argv, +		   env,  		   child_setup, user_data);            _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");  	} @@ -1218,6 +1229,8 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,        else          _dbus_babysitter_unref (sitter); +      dbus_free_string_array (env); +        _DBUS_ASSERT_ERROR_IS_CLEAR (error);        return TRUE; diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c index 492c5289..aed94878 100644 --- a/dbus/dbus-string-util.c +++ b/dbus/dbus-string-util.c @@ -846,6 +846,31 @@ _dbus_string_test (void)      _dbus_string_free (&str);    } + +  { +    const char two_strings[] = "one\ttwo"; + +    if (!_dbus_string_init (&str)) +      _dbus_assert_not_reached ("no memory"); + +    if (!_dbus_string_init (&other)) +      _dbus_assert_not_reached ("no memory"); + +    if (!_dbus_string_append (&str, two_strings)) +      _dbus_assert_not_reached ("no memory"); + +    if (!_dbus_string_split_on_byte (&str, '\t', &other)) +      _dbus_assert_not_reached ("no memory or delimiter not found"); + +    if (strcmp (_dbus_string_get_data (&str), "one") != 0) +      _dbus_assert_not_reached ("left side after split on tab is wrong"); + +    if (strcmp (_dbus_string_get_data (&other), "two") != 0) +      _dbus_assert_not_reached ("right side after split on tab is wrong"); + +    _dbus_string_free (&str); +    _dbus_string_free (&other); +  }    return TRUE;  } diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index cb108a8d..6b9b2bfe 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -1677,6 +1677,48 @@ _dbus_string_replace_len (const DBusString *source,    return TRUE;  } +/** + * Looks for the first occurance of a byte, deletes that byte, + * and moves everything after the byte to the beginning of a + * separate string.  Both strings must be initialized, valid + * strings. + * + * @param source the source string + * @param byte the byte to remove and split the string at + * @param tail the split off string + * @returns #FALSE if not enough memory or if byte could not be found + * + */ +dbus_bool_t +_dbus_string_split_on_byte (DBusString        *source, +                            unsigned char      byte, +                            DBusString        *tail) +{ +  int byte_position; +  char byte_string[2] = ""; +  int head_length; +  int tail_length; + +  byte_string[0] = (char) byte; + +  if (!_dbus_string_find (source, 0, byte_string, &byte_position)) +    return FALSE; + +  head_length = byte_position; +  tail_length = _dbus_string_get_length (source) - head_length - 1; + +  if (!_dbus_string_move_len (source, byte_position + 1, tail_length, +                              tail, 0)) +    return FALSE; + +  /* remove the trailing delimiter byte from the head now. +   */ +  if (!_dbus_string_set_length (source, head_length)) +    return FALSE; + +  return TRUE; +} +  /* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc   * Pennington, and Tom Tromey are the authors and authorized relicense.   */ diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index d88d67ed..374f0a86 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -201,6 +201,9 @@ dbus_bool_t   _dbus_string_replace_len           (const DBusString  *source,                                                    DBusString        *dest,                                                    int                replace_at,                                                    int                replace_len); +dbus_bool_t   _dbus_string_split_on_byte         (DBusString        *source, +                                                  unsigned char      byte, +                                                  DBusString        *tail);  void          _dbus_string_get_unichar           (const DBusString  *str,                                                    int                start,                                                    dbus_unichar_t    *ch_return, diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 1a736e42..d740f875 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -200,6 +200,48 @@ _dbus_clearenv (void)    return rc;  } +/** + * Gets a #NULL-terminated list of key=value pairs from the + * environment. Use dbus_free_string_array to free it. + * + * @returns the environment or #NULL on OOM + */ +char ** +_dbus_get_environment (void) +{ +  int i, length; +  extern char **environ; +  char **environment; + +  _dbus_assert (environ != NULL); + +  for (length = 0; environ[length] != NULL; length++); + +  /* Add one for NULL */ +  length++; + +  environment = dbus_new0 (char *, length); + +  if (environment == NULL) +    return NULL; + +  for (i = 0; environ[i] != NULL; i++) +    { +      environment[i] = _dbus_strdup (environ[i]); + +      if (environment[i] == NULL) +        break; +    } + +  if (environ[i] != NULL) +    { +      dbus_free_string_array (environment); +      environment = NULL; +    } + +  return environment; +} +  /*   * init a pipe instance.   * diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 5ff13884..80236f05 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -101,6 +101,7 @@ const char* _dbus_getenv (const char *varname);  dbus_bool_t _dbus_setenv (const char *varname,  			  const char *value);  dbus_bool_t _dbus_clearenv (void); +char **     _dbus_get_environment (void);  /** A process ID */  typedef unsigned long dbus_pid_t; diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 932ba0a3..9b22c84a 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3678,6 +3678,40 @@        </sect3> +      <sect3 id="bus-messages-update-activation-environment"> +        <title><literal>org.freedesktop.DBus.UpdateActivationEnvironment</literal></title> +        <para> +          As a method: +          <programlisting> +            UpdateActivationEnvironment (in ARRAY of DICT<STRING,STRING> environment) +          </programlisting> +          Message arguments: +          <informaltable> +            <tgroup cols="3"> +              <thead> +                <row> +                  <entry>Argument</entry> +                  <entry>Type</entry> +                  <entry>Description</entry> +                </row> +              </thead> +              <tbody> +                <row> +                  <entry>0</entry> +                  <entry>ARRAY of DICT<STRING,STRING></entry> +                  <entry>Environment to add or update</entry> +                </row> +              </tbody> +            </tgroup> +            </informaltable> +            Normally, session bus activated services inherit the environment of the bus daemon.  This method adds to or modifies that environment when activating services. +        </para> +        <para> +          Some bus instances, such as the standard system bus, may disable access to this method for some or all callers. +        </para> + +      </sect3> +        <sect3 id="bus-messages-get-name-owner">          <title><literal>org.freedesktop.DBus.GetNameOwner</literal></title>          <para>  | 
