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> |