diff options
author | Adrian Szyndela <adrian.s@samsung.com> | 2020-04-07 08:00:23 +0200 |
---|---|---|
committer | Adrian Szyndela <adrian.s@samsung.com> | 2020-04-16 12:29:39 +0200 |
commit | 931a8fa172e295be9b14ee5c5ed7658f3f0d86dd (patch) | |
tree | 2694374a1fea462046be21e0773567ac9d8992c1 /bus | |
parent | 4255f571aea9dbd7eba3accd1144c7df53958a7d (diff) | |
parent | 23cc709db8fab94f11fa48772bff396b20aea8b0 (diff) | |
download | dbus-931a8fa172e295be9b14ee5c5ed7658f3f0d86dd.tar.gz dbus-931a8fa172e295be9b14ee5c5ed7658f3f0d86dd.tar.bz2 dbus-931a8fa172e295be9b14ee5c5ed7658f3f0d86dd.zip |
Merge dbus-1.12.16 into tizen
dbus 1.12.16
Diffstat (limited to 'bus')
45 files changed, 2528 insertions, 1520 deletions
diff --git a/bus/Makefile.am b/bus/Makefile.am index 5f28a25f..a82db939 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -1,9 +1,13 @@ dbusdatadir=$(datadir)/dbus-1 legacydbusdatadir=$(sysconfdir)/dbus-1 dbus_daemon_execdir = $(DBUS_DAEMONDIR) +# Always lib, even if ${libdir} is lib64 or lib/x86_64-linux-gnu +systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +systemdsysusersdir = $(prefix)/lib/sysusers.d DBUS_BUS_LIBS = \ - $(XML_LIBS) \ + $(CODE_COVERAGE_LIBS) \ + $(EXPAT_LIBS) \ $(SELINUX_LIBS) \ $(APPARMOR_LIBS) \ $(THREAD_LIBS) \ @@ -13,15 +17,17 @@ DBUS_BUS_LIBS = \ $(NULL) DBUS_LAUNCHER_LIBS = \ - $(XML_LIBS) \ + $(CODE_COVERAGE_LIBS) \ + $(EXPAT_LIBS) \ $(THREAD_LIBS) \ $(NETWORK_libs) \ $(NULL) AM_CPPFLAGS = \ + $(CODE_COVERAGE_CPPFLAGS) \ -I$(top_srcdir) \ $(DBUS_STATIC_BUILD_CPPFLAGS) \ - $(XML_CFLAGS) \ + $(EXPAT_CFLAGS) \ $(APPARMOR_CFLAGS) \ -DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \ -DDBUS_COMPILATION \ @@ -31,9 +37,13 @@ AM_CPPFLAGS = \ # if assertions are enabled, improve backtraces AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ -Wl,-z,relro,-z,now +AM_CFLAGS = \ + $(CODE_COVERAGE_CFLAGS) \ + $(NULL) + EFENCE= -CONFIG_IN_FILES= \ +EXTRA_DIST = \ session.conf.in \ system.conf.in \ legacy-config/session.conf.in \ @@ -62,8 +72,6 @@ agentdir=$(LAUNCHD_AGENT_DIR) agent_DATA=org.freedesktop.dbus-session.plist endif -XML_SOURCES=config-loader-expat.c - if DBUS_BUS_ENABLE_KQUEUE DIR_WATCH_SOURCE=dir-watch-kqueue.c else @@ -86,6 +94,7 @@ BUS_SOURCES= \ bus.h \ check.c \ check.h \ + config-loader-expat.c \ config-parser.c \ config-parser.h \ config-parser-common.c \ @@ -118,7 +127,7 @@ BUS_SOURCES= \ test.h \ utils.c \ utils.h \ - $(XML_SOURCES) + $(NULL) dbus_daemon_SOURCES= \ $(BUS_SOURCES) \ @@ -131,7 +140,7 @@ dbus_daemon_LDADD= \ $(DBUS_BUS_LIBS) LAUNCH_HELPER_SOURCES= \ - $(XML_SOURCES) \ + config-loader-expat.c \ config-parser-common.c \ config-parser-common.h \ config-parser-trivial.c \ @@ -214,7 +223,7 @@ endif DBUS_UNIX endif DBUS_ENABLE_EMBEDDED_TESTS test_bus_system_SOURCES= \ - $(XML_SOURCES) \ + config-loader-expat.c \ config-parser-common.c \ config-parser-common.h \ config-parser-trivial.c \ @@ -239,10 +248,6 @@ test_bus_LDADD = \ $(DBUS_BUS_LIBS) \ $(NULL) -## mop up the gcov files -clean-local: - /bin/rm *.bb *.bbg *.da *.gcov || true - install-data-hook: $(mkinstalldirs) $(DESTDIR)$(dbusdatadir)/session.d $(mkinstalldirs) $(DESTDIR)$(dbusdatadir)/services @@ -255,8 +260,6 @@ if HAVE_SYSTEMD # Install dbus.socket as default implementation of a D-Bus stack. # Deliberately not using $(LN_S) here: ln -fs is not universally portable, # but neither is systemd, so it's OK to assume here that ln complies with SUS. - $(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants - ln -fs ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants/dbus.socket # Unconditionally enable D-Bus on systemd installations $(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants ln -fs ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/dbus.socket @@ -277,53 +280,26 @@ install-exec-hook: fi endif -#### Init scripts fun -SCRIPT_IN_FILES=messagebus.in \ - messagebus-config.in \ - rc.messagebus.in - -## Red Hat start -if DBUS_INIT_SCRIPTS_RED_HAT - -initddir=$(sysconfdir)/rc.d/init.d - -initd_SCRIPTS= \ - messagebus - -endif - ## Red Hat end - -## Slackware start -if DBUS_INIT_SCRIPTS_SLACKWARE - -initddir=$(sysconfdir)/rc.d/ - -initd_SCRIPTS= \ - rc.messagebus - -endif -## Slackware end - -## Cygwin start -if DBUS_INIT_SCRIPTS_CYGWIN - -bin_SCRIPTS= \ - messagebus-config - -endif -## Cygwin end - -if HAVE_SYSTEMD -SCRIPT_IN_FILES += \ +EXTRA_DIST += \ dbus.service.in \ dbus.socket.in \ systemd-user/dbus.service.in \ systemd-user/dbus.socket.in \ + sysusers.d/dbus.conf.in \ + tmpfiles.d/dbus.conf.in \ $(NULL) +if HAVE_SYSTEMD systemdsystemunit_DATA = \ dbus.service \ dbus.socket + +nodist_systemdsysusers_DATA = \ + sysusers.d/dbus.conf + +nodist_systemdtmpfiles_DATA = \ + tmpfiles.d/dbus.conf \ + $(NULL) endif if DBUS_ENABLE_USER_SESSION @@ -333,6 +309,5 @@ systemduserunit_DATA = \ $(NULL) endif -#### Extra dist - -EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) +# Add rules for code-coverage testing, as defined by AX_CODE_COVERAGE +include $(top_srcdir)/aminclude_static.am diff --git a/bus/activation-helper.c b/bus/activation-helper.c index 394f3938..5b6a0908 100644 --- a/bus/activation-helper.c +++ b/bus/activation-helper.c @@ -80,7 +80,7 @@ desktop_file_for_name (BusConfigParser *parser, goto out; } - service_dirs = bus_config_parser_get_service_dirs (parser); + service_dirs = bus_config_parser_get_service_paths (parser); for (link = _dbus_list_get_first_link (service_dirs); link != NULL; link = _dbus_list_get_next_link (service_dirs, link)) diff --git a/bus/activation-helper.h b/bus/activation-helper.h index 361a4c6a..43e7b150 100644 --- a/bus/activation-helper.h +++ b/bus/activation-helper.h @@ -25,6 +25,8 @@ #ifndef BUS_ACTIVATION_HELPER_H #define BUS_ACTIVATION_HELPER_H +#include <dbus/dbus.h> + dbus_bool_t run_launch_helper (const char *bus_name, DBusError *error); diff --git a/bus/activation.c b/bus/activation.c index 99b3554a..9031e60e 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -26,6 +26,7 @@ #include <config.h> #include "activation.h" #include "activation-exit-codes.h" +#include "config-parser.h" #include "desktop-file.h" #include "dispatch.h" #include "services.h" @@ -54,7 +55,7 @@ struct BusActivation * i.e. number of pending activation requests, not pending * activations per se */ - DBusHashTable *directories; + DBusList *directories; DBusHashTable *environment; }; @@ -62,6 +63,7 @@ typedef struct { int refcount; char *dir_c; + BusServiceDirFlags flags; DBusHashTable *entries; } BusServiceDirectory; @@ -72,6 +74,7 @@ struct BusActivationEntry char *exec; char *user; char *systemd_service; + char *assumed_apparmor_label; unsigned long mtime; BusServiceDirectory *s_dir; char *filename; @@ -247,6 +250,7 @@ bus_activation_entry_unref (BusActivationEntry *entry) dbus_free (entry->user); dbus_free (entry->filename); dbus_free (entry->systemd_service); + dbus_free (entry->assumed_apparmor_label); dbus_free (entry); } @@ -259,11 +263,13 @@ update_desktop_file_entry (BusActivation *activation, DBusError *error) { char *name, *exec, *user, *exec_tmp, *systemd_service; + char *assumed_apparmor_label; BusActivationEntry *entry; DBusStat stat_buf; DBusString file_path; DBusError tmp_error; dbus_bool_t retval; + DBusString str; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -274,6 +280,7 @@ update_desktop_file_entry (BusActivation *activation, exec_tmp = NULL; entry = NULL; systemd_service = NULL; + assumed_apparmor_label = NULL; dbus_error_init (&tmp_error); @@ -311,9 +318,18 @@ update_desktop_file_entry (BusActivation *activation, error)) goto out; - exec = _dbus_strdup (_dbus_replace_install_prefix (exec_tmp)); - dbus_free (exec_tmp); - exec_tmp = NULL; + if (!_dbus_string_init (&str)) + goto out; + + if (!_dbus_string_append (&str, exec_tmp) || + !_dbus_replace_install_prefix (&str) || + !_dbus_string_steal_data (&str, &exec)) + { + _dbus_string_free (&str); + goto out; + } + + _dbus_string_free (&str); /* user is not _required_ unless we are using system activation */ if (!bus_desktop_file_get_string (desktop_file, @@ -360,6 +376,28 @@ update_desktop_file_entry (BusActivation *activation, } } + /* assumed AppArmor label is never required */ + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_ASSUMED_APPARMOR_LABEL, + &assumed_apparmor_label, &tmp_error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + /* if we got OOM, then exit */ + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto out; + } + else + { + /* if we have error because we didn't find anything then continue */ + dbus_error_free (&tmp_error); + dbus_free (assumed_apparmor_label); + assumed_apparmor_label = NULL; + } + } + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); entry = _dbus_hash_table_lookup_string (s_dir->entries, @@ -367,8 +405,69 @@ update_desktop_file_entry (BusActivation *activation, if (entry == NULL) /* New file */ { + DBusString expected_name; + + if (!_dbus_string_init (&expected_name)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!_dbus_string_append (&expected_name, name) || + !_dbus_string_append (&expected_name, ".service")) + { + _dbus_string_free (&expected_name); + BUS_SET_OOM (error); + goto out; + } + + if (_dbus_string_equal (&expected_name, filename)) + { + _dbus_verbose ("Name of \"%s\" is as expected\n", + _dbus_string_get_const_data (&file_path)); + } + else if (s_dir->flags & BUS_SERVICE_DIR_FLAGS_STRICT_NAMING) + { + bus_context_log_and_set_error (activation->context, + DBUS_SYSTEM_LOG_WARNING, error, + DBUS_ERROR_FAILED, + "Service file \"%s\" should have " + "been named \"%s\": not loading it", + _dbus_string_get_const_data (&file_path), + _dbus_string_get_const_data (&expected_name)); + _dbus_string_free (&expected_name); + goto out; + } + else if (bus_context_get_servicehelper (activation->context) != NULL) + { + bus_context_log (activation->context, DBUS_SYSTEM_LOG_WARNING, + "Service file \"%s\" should have been named \"%s\" " + "and will not work with system bus activation", + _dbus_string_get_const_data (&file_path), + _dbus_string_get_const_data (&expected_name)); + /* We don't actually error out here, because *technically* it could + * still work on systemd systems, where we tell systemd to start the + * SystemdService instead of launching dbus-daemon-launch-helper + * ourselves. But maybe we should: + * https://bugs.freedesktop.org/show_bug.cgi?id=99874 */ + } + else + { + /* We could maybe log mismatched names for session services in + * a user-visible way too, but not until + * https://lintian.debian.org/tags/dbus-session-service-wrong-name.html + * is a bit shorter. + * https://bugs.freedesktop.org/show_bug.cgi?id=99873 */ + _dbus_verbose ("Name of \"%s\" should canonically be \"%s\"\n", + _dbus_string_get_const_data (&file_path), + _dbus_string_get_const_data (&expected_name)); + } + + _dbus_string_free (&expected_name); + /* FIXME we need a better-defined algorithm for which service file to * pick than "whichever one is first in the directory listing" + * See also https://bugs.freedesktop.org/show_bug.cgi?id=99874 */ if (_dbus_hash_table_lookup_string (activation->entries, name)) { @@ -388,6 +487,7 @@ update_desktop_file_entry (BusActivation *activation, entry->exec = exec; entry->user = user; entry->systemd_service = systemd_service; + entry->assumed_apparmor_label = assumed_apparmor_label; entry->refcount = 1; /* ownership has been transferred to entry, do not free separately */ @@ -395,6 +495,7 @@ update_desktop_file_entry (BusActivation *activation, exec = NULL; user = NULL; systemd_service = NULL; + assumed_apparmor_label = NULL; entry->s_dir = s_dir; entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename)); @@ -452,6 +553,10 @@ update_desktop_file_entry (BusActivation *activation, entry->systemd_service = systemd_service; systemd_service = NULL; + dbus_free (entry->assumed_apparmor_label); + entry->assumed_apparmor_label = assumed_apparmor_label; + assumed_apparmor_label = NULL; + if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref(entry))) { @@ -469,10 +574,12 @@ update_desktop_file_entry (BusActivation *activation, out: /* if these have been transferred into entry, the variables will be NULL */ + dbus_free (exec_tmp); dbus_free (name); dbus_free (exec); dbus_free (user); dbus_free (systemd_service); + dbus_free (assumed_apparmor_label); _dbus_string_free (&file_path); if (entry) @@ -732,9 +839,6 @@ update_directory (BusActivation *activation, static dbus_bool_t populate_environment (BusActivation *activation) { - DBusString key; - DBusString value; - int i; char **environment; dbus_bool_t retval = FALSE; @@ -743,50 +847,7 @@ populate_environment (BusActivation *activation) 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); + retval = _dbus_hash_table_from_array (activation->environment, environment, '='); dbus_free_string_array (environment); return retval; @@ -819,23 +880,19 @@ bus_activation_reload (BusActivation *activation, goto failed; } - if (activation->directories != NULL) - _dbus_hash_table_unref (activation->directories); - activation->directories = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, - (DBusFreeFunction)bus_service_directory_unref); - - if (activation->directories == NULL) - { - BUS_SET_OOM (error); - goto failed; - } + _dbus_list_foreach (&activation->directories, + (DBusForeachFunction) bus_service_directory_unref, NULL); + _dbus_list_clear (&activation->directories); link = _dbus_list_get_first_link (directories); while (link != NULL) { + BusConfigServiceDir *config = link->data; BusServiceDirectory *s_dir; - dir = _dbus_strdup ((const char *) link->data); + _dbus_assert (config->path != NULL); + + dir = _dbus_strdup (config->path); if (!dir) { BUS_SET_OOM (error); @@ -852,6 +909,7 @@ bus_activation_reload (BusActivation *activation, s_dir->refcount = 1; s_dir->dir_c = dir; + s_dir->flags = config->flags; s_dir->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, (DBusFreeFunction)bus_activation_entry_unref); @@ -863,7 +921,7 @@ bus_activation_reload (BusActivation *activation, goto failed; } - if (!_dbus_hash_table_insert_string (activation->directories, s_dir->dir_c, s_dir)) + if (!_dbus_list_append (&activation->directories, s_dir)) { bus_service_directory_unref (s_dir); BUS_SET_OOM (error); @@ -970,8 +1028,11 @@ bus_activation_unref (BusActivation *activation) _dbus_hash_table_unref (activation->entries); if (activation->pending_activations) _dbus_hash_table_unref (activation->pending_activations); - if (activation->directories) - _dbus_hash_table_unref (activation->directories); + + _dbus_list_foreach (&activation->directories, + (DBusForeachFunction) bus_service_directory_unref, NULL); + _dbus_list_clear (&activation->directories); + if (activation->environment) _dbus_hash_table_unref (activation->environment); @@ -1213,6 +1274,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation entry->activation_message); } + dbus_error_free (&error); link = next; continue; case BUS_RESULT_LATER: @@ -1473,7 +1535,8 @@ pending_activation_finished_cb (DBusBabysitter *babysitter, { BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); - if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0) + if (p != pending_activation && p->exec != NULL && + strcmp (p->exec, pending_activation->exec) == 0) pending_activation_failed (p, &error); } @@ -1522,7 +1585,12 @@ static dbus_bool_t pending_activation_timed_out (void *data) { BusPendingActivation *pending_activation = data; + BusContext *context; DBusError error; + int timeout; + + context = pending_activation->activation->context; + timeout = bus_context_get_activation_timeout (context); /* Kill the spawned process, since it sucks * (not sure this is what we want to do, but @@ -1533,10 +1601,11 @@ pending_activation_timed_out (void *data) dbus_error_init (&error); - bus_context_log_and_set_error (pending_activation->activation->context, - DBUS_SYSTEM_LOG_INFO, &error, DBUS_ERROR_TIMED_OUT, - "Failed to activate service '%s': timed out", - pending_activation->service_name); + bus_context_log_and_set_error (context, DBUS_SYSTEM_LOG_WARNING, &error, + DBUS_ERROR_TIMED_OUT, + "Failed to activate service '%s': timed out " + "(service_start_timeout=%dms)", + pending_activation->service_name, timeout); pending_activation_failed (pending_activation, &error); @@ -1587,15 +1656,14 @@ add_cancel_pending_to_transaction (BusTransaction *transaction, static dbus_bool_t update_service_cache (BusActivation *activation, DBusError *error) { - DBusHashIter iter; + DBusList *iter; - _dbus_hash_iter_init (activation->directories, &iter); - while (_dbus_hash_iter_next (&iter)) + for (iter = _dbus_list_get_first_link (&activation->directories); + iter != NULL; + iter = _dbus_list_get_next_link (&activation->directories, iter)) { DBusError tmp_error; - BusServiceDirectory *s_dir; - - s_dir = _dbus_hash_iter_get_value (&iter); + BusServiceDirectory *s_dir = iter->data; dbus_error_init (&tmp_error); if (!update_directory (activation, s_dir, &tmp_error)) @@ -1654,51 +1722,7 @@ activation_find_entry (BusActivation *activation, 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; + return _dbus_hash_table_to_array (activation->environment, '='); } dbus_bool_t @@ -1788,21 +1812,36 @@ bus_activation_activate_service (BusActivation *activation, BusResult retval = BUS_RESULT_FALSE; dbus_bool_t was_pending_activation; DBusString command; + int limit; + DBusSpawnFlags flags = DBUS_SPAWN_NONE; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (activation->n_pending_activations >= - bus_context_get_max_pending_activations (activation->context)) + limit = bus_context_get_max_pending_activations (activation->context); + + if (activation->n_pending_activations >= limit) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, - "The maximum number of pending activations has been reached, activation of %s failed", - service_name); + "The maximum number of pending activations has been " + "reached, activation of %s failed " + "(max_pending_service_starts=%d)", + service_name, limit); return BUS_RESULT_FALSE; } - entry = activation_find_entry (activation, service_name, error); - if (!entry) - return BUS_RESULT_FALSE; + if (bus_context_get_systemd_activation (activation->context) && + strcmp (service_name, "org.freedesktop.systemd1") == 0) + { + /* if we're doing systemd activation, we assume systemd will connect + * eventually, and it does not need a .service file */ + entry = NULL; + } + else + { + entry = activation_find_entry (activation, service_name, error); + if (!entry) + return BUS_RESULT_FALSE; + } if (auto_activation && entry != NULL) { @@ -1936,17 +1975,20 @@ bus_activation_activate_service (BusActivation *activation, return BUS_RESULT_FALSE; } - pending_activation->exec = _dbus_strdup (entry->exec); - if (!pending_activation->exec) + if (entry != NULL) { - _dbus_verbose ("Failed to copy service exec for pending activation\n"); - BUS_SET_OOM (error); - bus_pending_activation_unref (pending_activation); - bus_pending_activation_entry_free (pending_activation_entry); - return FALSE; + pending_activation->exec = _dbus_strdup (entry->exec); + if (!pending_activation->exec) + { + _dbus_verbose ("Failed to copy service exec for pending activation\n"); + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } } - if (entry->systemd_service) + if (entry != NULL && entry->systemd_service != NULL) { pending_activation->systemd_service = _dbus_strdup (entry->systemd_service); if (!pending_activation->systemd_service) @@ -2036,6 +2078,7 @@ bus_activation_activate_service (BusActivation *activation, DBusString service_string; BusService *service; BusRegistry *registry; + DBusConnection *systemd = NULL; /* OK, we have a systemd service configured for this entry, hence let's enqueue an activation request message. This @@ -2084,11 +2127,14 @@ bus_activation_activate_service (BusActivation *activation, _dbus_string_init_const (&service_string, "org.freedesktop.systemd1"); service = bus_registry_lookup (registry, &service_string); + if (service) + systemd = bus_service_get_primary_owners_connection (service); + /* Following the general principle of "log early and often", * we capture that we *want* to send the activation message, even if * systemd is not actually there to receive it yet */ if (!bus_transaction_capture (activation_transaction, - NULL, message)) + NULL, systemd, message)) { dbus_message_unref (message); BUS_SET_OOM (error); @@ -2098,22 +2144,25 @@ bus_activation_activate_service (BusActivation *activation, if (service != NULL) { bus_context_log (activation->context, - DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s'", + DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s' requested by '%s' (%s)", service_name, - entry->systemd_service); + entry->systemd_service, + bus_connection_get_name (connection), + bus_connection_get_loginfo (connection)); /* Wonderful, systemd is connected, let's just send the msg */ retval = bus_dispatch_matches (activation_transaction, NULL, - bus_service_get_primary_owners_connection (service), - message, NULL, error); + systemd, message, NULL, error); if (BUS_RESULT_LATER == retval) _dbus_verbose("Unexpectedly need time to check message from bus driver to systemd - dropping the message.\n"); } else { bus_context_log (activation->context, - DBUS_SYSTEM_LOG_INFO, "Activating systemd to hand-off: service name='%s' unit='%s'", + DBUS_SYSTEM_LOG_INFO, "Activating systemd to hand-off: service name='%s' unit='%s' requested by '%s' (%s)", service_name, - entry->systemd_service); + entry->systemd_service, + bus_connection_get_name (connection), + bus_connection_get_loginfo (connection)); /* systemd is not around, let's "activate" it. */ retval = bus_activation_activate_service (activation, NULL, activation_transaction, TRUE, message, "org.freedesktop.systemd1", error, deferred_message); @@ -2141,6 +2190,11 @@ bus_activation_activate_service (BusActivation *activation, proceed with traditional activation. */ } + /* If entry was NULL, it would be because we were doing systemd activation + * and activating systemd itself; but we already handled that case with + * an early-return */ + _dbus_assert (entry != NULL); + /* use command as system and session different */ if (!_dbus_string_init (&command)) { @@ -2220,19 +2274,27 @@ bus_activation_activate_service (BusActivation *activation, _dbus_verbose ("Spawning %s ...\n", argv[0]); if (servicehelper != NULL) bus_context_log (activation->context, - DBUS_SYSTEM_LOG_INFO, "Activating service name='%s' (using servicehelper)", - service_name); + DBUS_SYSTEM_LOG_INFO, "Activating service name='%s' requested by '%s' (%s) (using servicehelper)", + service_name, + bus_connection_get_name (connection), + bus_connection_get_loginfo (connection)); else bus_context_log (activation->context, - DBUS_SYSTEM_LOG_INFO, "Activating service name='%s'", - service_name); + DBUS_SYSTEM_LOG_INFO, "Activating service name='%s' requested by '%s' (%s)", + service_name, + bus_connection_get_name (connection), + bus_connection_get_loginfo (connection)); dbus_error_init (&tmp_error); + if (bus_context_get_using_syslog (activation->context)) + flags |= DBUS_SPAWN_REDIRECT_OUTPUT; + if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, service_name, argv, envp, + flags, child_setup, activation, &tmp_error)) @@ -2341,7 +2403,7 @@ dbus_activation_systemd_failure (BusActivation *activation, DBUS_TYPE_STRING, &code, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) - dbus_set_error(&error, code, str); + dbus_set_error (&error, code, "%s", str); if (unit) @@ -2370,13 +2432,19 @@ dbus_activation_systemd_failure (BusActivation *activation, return TRUE; } +const char * +bus_activation_entry_get_assumed_apparmor_label (BusActivationEntry *entry) +{ + return entry->assumed_apparmor_label; +} + #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include <stdio.h> -#define SERVICE_NAME_1 "MyService1" -#define SERVICE_NAME_2 "MyService2" -#define SERVICE_NAME_3 "MyService3" +#define SERVICE_NAME_1 "com.example.MyService1" +#define SERVICE_NAME_2 "org.example.MyService2" +#define SERVICE_NAME_3 "net.example.MyService3" #define SERVICE_FILE_1 "service-1.service" #define SERVICE_FILE_2 "service-2.service" @@ -2503,21 +2571,8 @@ out: static dbus_bool_t init_service_reload_test (DBusString *dir) { - DBusStat stat_buf; - - if (!_dbus_stat (dir, &stat_buf, NULL)) - { - if (!_dbus_create_directory (dir, NULL)) - return FALSE; - } - else - { - if (!test_remove_directory (dir)) - return FALSE; - - if (!_dbus_create_directory (dir, NULL)) - return FALSE; - } + if (!_dbus_create_directory (dir, NULL)) + return FALSE; /* Create one initial file */ if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1")) @@ -2596,9 +2651,13 @@ do_test (const char *description, dbus_bool_t oom_test, CheckData *data) } static dbus_bool_t -do_service_reload_test (DBusString *dir, dbus_bool_t oom_test) +do_service_reload_test (const DBusString *test_data_dir, + DBusString *dir, + dbus_bool_t oom_test) { BusActivation *activation; + BusConfigServiceDir config; + BusContext *context; DBusString address; DBusList *directories; CheckData d; @@ -2606,10 +2665,18 @@ do_service_reload_test (DBusString *dir, dbus_bool_t oom_test) directories = NULL; _dbus_string_init_const (&address, ""); - if (!_dbus_list_append (&directories, _dbus_string_get_data (dir))) + config.path = _dbus_string_get_data (dir); + config.flags = BUS_SERVICE_DIR_FLAGS_NONE; + + if (!_dbus_list_append (&directories, &config)) return FALSE; - activation = bus_activation_new (NULL, &address, &directories, NULL); + context = bus_context_new_test (test_data_dir, + "valid-config-files/debug-allow-all.conf"); + if (context == NULL) + return FALSE; + + activation = bus_activation_new (context, &address, &directories, NULL); if (!activation) return FALSE; @@ -2670,6 +2737,7 @@ do_service_reload_test (DBusString *dir, dbus_bool_t oom_test) bus_activation_unref (activation); _dbus_list_clear (&directories); + bus_context_unref (context); return TRUE; } @@ -2700,16 +2768,19 @@ bus_activation_service_reload_test (const DBusString *test_data_dir) if (!init_service_reload_test (&directory)) _dbus_assert_not_reached ("could not initiate service reload test"); - if (!do_service_reload_test (&directory, FALSE)) + if (!do_service_reload_test (test_data_dir, &directory, FALSE)) { /* Do nothing? */ } + if (!cleanup_service_reload_test (&directory)) + goto out; + /* Do OOM tests */ if (!init_service_reload_test (&directory)) _dbus_assert_not_reached ("could not initiate service reload test"); - if (!do_service_reload_test (&directory, TRUE)) + if (!do_service_reload_test (test_data_dir, &directory, TRUE)) { /* Do nothing? */ } diff --git a/bus/activation.h b/bus/activation.h index c24f85d3..bd91954f 100644 --- a/bus/activation.h +++ b/bus/activation.h @@ -65,5 +65,6 @@ dbus_bool_t bus_activation_send_pending_auto_activation_messages (BusActivati BusService *service, BusTransaction *transaction); +const char *bus_activation_entry_get_assumed_apparmor_label (BusActivationEntry *entry); #endif /* BUS_ACTIVATION_H */ diff --git a/bus/apparmor.c b/bus/apparmor.c index 46725dbf..471fb551 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -46,6 +46,7 @@ #include <libaudit.h> #endif /* HAVE_LIBAUDIT */ +#include "activation.h" #include "audit.h" #include "connection.h" #include "utils.h" @@ -606,7 +607,9 @@ bus_apparmor_allows_acquire_service (DBusConnection *connection, BusAppArmorConfinement *con = NULL; DBusString qstr, auxdata; dbus_bool_t free_auxdata = FALSE; - dbus_bool_t allow = FALSE, audit = TRUE; + /* the AppArmor API uses pointers to int for pointers to boolean, and + * int is not strictly guaranteed to be the same as dbus_bool_t */ + int allow = FALSE, audit = TRUE; unsigned long pid; int res, serrno = 0; @@ -743,13 +746,15 @@ bus_apparmor_allows_send (DBusConnection *sender, #ifdef HAVE_APPARMOR BusAppArmorConfinement *src_con = NULL, *dst_con = NULL; DBusString qstr, auxdata; - dbus_bool_t src_allow = FALSE, dst_allow = FALSE; - dbus_bool_t src_audit = TRUE, dst_audit = TRUE; + int src_allow = FALSE, dst_allow = FALSE; + int src_audit = TRUE, dst_audit = TRUE; dbus_bool_t free_auxdata = FALSE; unsigned long pid; int len, res, src_errno = 0, dst_errno = 0; uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE; const char *msgtypestr = dbus_message_type_to_string(msgtype); + const char *dst_label = NULL; + const char *dst_mode = NULL; if (!apparmor_enabled) return TRUE; @@ -766,12 +771,22 @@ bus_apparmor_allows_send (DBusConnection *sender, { dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient); } + else if (activation_entry != NULL) + { + dst_label = bus_activation_entry_get_assumed_apparmor_label (activation_entry); + } else { dst_con = bus_con; bus_apparmor_confinement_ref (dst_con); } + if (dst_con != NULL) + { + dst_label = dst_con->label; + dst_mode = dst_con->mode; + } + /* map reply messages to initial send and receive permission. That is * permission to receive a message from X grants permission to reply to X. * And permission to send a message to Y grants permission to receive a reply @@ -799,7 +814,7 @@ bus_apparmor_allows_send (DBusConnection *sender, goto oom; if (!build_message_query (&qstr, src_con->label, bustype, destination, - dst_con->label, path, interface, member)) + dst_label, path, interface, member)) { _dbus_string_free (&qstr); goto oom; @@ -818,7 +833,11 @@ bus_apparmor_allows_send (DBusConnection *sender, } } - if (is_unconfined (dst_con->label, dst_con->mode)) + /* When deciding whether we can activate a service, we only check that + * we are allowed to send a message to it, not that it is allowed to + * receive that message from us. + */ + if (activation_entry != NULL || is_unconfined (dst_label, dst_mode)) { dst_allow = TRUE; dst_audit = FALSE; @@ -828,7 +847,7 @@ bus_apparmor_allows_send (DBusConnection *sender, if (!_dbus_string_init (&qstr)) goto oom; - if (!build_message_query (&qstr, dst_con->label, bustype, source, + if (!build_message_query (&qstr, dst_label, bustype, source, src_con->label, path, interface, member)) { _dbus_string_free (&qstr); @@ -851,7 +870,7 @@ bus_apparmor_allows_send (DBusConnection *sender, /* Don't fail operations on profiles in complain mode */ if (modestr_is_complain (src_con->mode)) src_allow = TRUE; - if (modestr_is_complain (dst_con->mode)) + if (modestr_is_complain (dst_mode)) dst_allow = TRUE; if (!src_allow || !dst_allow) @@ -922,8 +941,8 @@ bus_apparmor_allows_send (DBusConnection *sender, !_dbus_append_pair_uint (&auxdata, "peer_pid", pid)) goto oom; - if (dst_con->label && - !_dbus_append_pair_str (&auxdata, "peer_label", dst_con->label)) + if (dst_label && + !_dbus_append_pair_str (&auxdata, "peer_label", dst_label)) goto oom; if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno))) @@ -950,8 +969,8 @@ bus_apparmor_allows_send (DBusConnection *sender, !_dbus_append_pair_uint (&auxdata, "pid", pid)) goto oom; - if (dst_con->label && - !_dbus_append_pair_str (&auxdata, "label", dst_con->label)) + if (dst_label && + !_dbus_append_pair_str (&auxdata, "label", dst_label)) goto oom; if (sender && dbus_connection_get_unix_process_id (sender, &pid) && @@ -1011,7 +1030,7 @@ bus_apparmor_allows_eavesdropping (DBusConnection *connection, #ifdef HAVE_APPARMOR BusAppArmorConfinement *con = NULL; DBusString qstr, auxdata; - dbus_bool_t allow = FALSE, audit = TRUE; + int allow = FALSE, audit = TRUE; dbus_bool_t free_auxdata = FALSE; unsigned long pid; int res, serrno = 0; diff --git a/bus/audit.c b/bus/audit.c index 7705e425..91f2c5cf 100644 --- a/bus/audit.c +++ b/bus/audit.c @@ -166,8 +166,9 @@ _dbus_change_to_daemon_user (const char *user, _dbus_strerror (errno)); break; case -5: - _dbus_warn ("Failed to drop supplementary groups: %s\n", - _dbus_strerror (errno)); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to drop supplementary groups: %s", + _dbus_strerror (errno)); break; case -6: dbus_set_error (error, _dbus_error_from_errno (errno), @@ -25,6 +25,7 @@ #include "bus.h" #include <stdio.h> +#include <stdlib.h> #include "activation.h" #include "connection.h" @@ -38,6 +39,7 @@ #include "audit.h" #include "dir-watch.h" #include "check.h" +#include <dbus/dbus-auth.h> #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-credentials.h> @@ -92,19 +94,15 @@ server_get_context (DBusServer *server) BusContext *context; BusServerData *bd; - if (!dbus_server_allocate_data_slot (&server_data_slot)) - return NULL; + /* this data slot was allocated by the BusContext */ + _dbus_assert (server_data_slot >= 0); bd = BUS_SERVER_DATA (server); - if (bd == NULL) - { - dbus_server_free_data_slot (&server_data_slot); - return NULL; - } - context = bd->context; + /* every DBusServer in the dbus-daemon has gone through setup_server() */ + _dbus_assert (bd != NULL); - dbus_server_free_data_slot (&server_data_slot); + context = bd->context; return context; } @@ -176,10 +174,9 @@ new_connection_callback (DBusServer *server, { BusContext *context = data; + /* If this fails it logs a warning, so we don't need to do that */ if (!bus_connections_setup_connection (context->connections, new_connection)) { - _dbus_verbose ("No memory to setup new connection\n"); - /* if we don't do this, it will get unref'd without * being disconnected... kind of strange really * that we have to do this, people won't get it right @@ -287,6 +284,7 @@ process_config_first_time_only (BusContext *context, DBusList **auth_mechanisms_list; int len; dbus_bool_t retval; + DBusLogFlags log_flags = DBUS_LOG_FLAGS_STDERR; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -294,7 +292,27 @@ process_config_first_time_only (BusContext *context, auth_mechanisms = NULL; pidfile = NULL; - _dbus_init_system_log (TRUE); + if (flags & BUS_CONTEXT_FLAG_SYSLOG_ALWAYS) + { + context->syslog = TRUE; + log_flags |= DBUS_LOG_FLAGS_SYSTEM_LOG; + + if (flags & BUS_CONTEXT_FLAG_SYSLOG_ONLY) + log_flags &= ~DBUS_LOG_FLAGS_STDERR; + } + else if (flags & BUS_CONTEXT_FLAG_SYSLOG_NEVER) + { + context->syslog = FALSE; + } + else + { + context->syslog = bus_config_parser_get_syslog (parser); + + if (context->syslog) + log_flags |= DBUS_LOG_FLAGS_SYSTEM_LOG; + } + + _dbus_init_system_log ("dbus-daemon", log_flags); if (flags & BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION) context->systemd_activation = TRUE; @@ -414,6 +432,26 @@ process_config_first_time_only (BusContext *context, link = _dbus_list_get_first_link (auth_mechanisms_list); while (link != NULL) { + DBusString name; + _dbus_string_init_const (&name, link->data); + if (!_dbus_auth_is_supported_mechanism (&name)) + { + DBusString list; + if (!_dbus_string_init (&list)) + goto oom; + + if (!_dbus_auth_dump_supported_mechanisms (&list)) + { + _dbus_string_free (&list); + goto oom; + } + dbus_set_error (error, DBUS_ERROR_FAILED, + "Unsupported auth mechanism \"%s\" in bus config file detected. Supported mechanisms are \"%s\".", + (char*)link->data, + _dbus_string_get_const_data (&list)); + _dbus_string_free (&list); + goto failed; + } auth_mechanisms[i] = _dbus_strdup (link->data); if (auth_mechanisms[i] == NULL) goto oom; @@ -476,7 +514,6 @@ process_config_first_time_only (BusContext *context, } context->fork = bus_config_parser_get_fork (parser); - context->syslog = bus_config_parser_get_syslog (parser); context->keep_umask = bus_config_parser_get_keep_umask (parser); context->allow_anonymous = bus_config_parser_get_allow_anonymous (parser); @@ -635,32 +672,6 @@ process_config_every_time (BusContext *context, return retval; } -static dbus_bool_t -list_concat_new (DBusList **a, - DBusList **b, - DBusList **result) -{ - DBusList *link; - - *result = NULL; - - for (link = _dbus_list_get_first_link (a); link; link = _dbus_list_get_next_link (a, link)) - { - if (!_dbus_list_append (result, link->data)) - goto oom; - } - for (link = _dbus_list_get_first_link (b); link; link = _dbus_list_get_next_link (b, link)) - { - if (!_dbus_list_append (result, link->data)) - goto oom; - } - - return TRUE; -oom: - _dbus_list_clear (result); - return FALSE; -} - static void raise_file_descriptor_limit (BusContext *context) { @@ -684,11 +695,11 @@ raise_file_descriptor_limit (BusContext *context) /* We used to compute a suitable rlimit based on the configured number * of connections, but that breaks down as soon as we allow fd-passing, * because each connection is allowed to pass 64 fds to us, and if - * they all did, we'd hit kernel limits. We now hard-code 64k as a - * good limit, like systemd does: that's enough to avoid DoS from - * anything short of multiple uids conspiring against us. + * they all did, we'd hit kernel limits. We now hard-code a good + * limit that is enough to avoid DoS from anything short of multiple + * uids conspiring against us, much like systemd does. */ - if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error)) + if (!_dbus_rlimit_raise_fd_limit (&error)) { bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s: %s", error.name, error.message); @@ -706,8 +717,6 @@ process_config_postinit (BusContext *context, DBusHashTable *service_context_table; DBusList *watched_dirs = NULL; - raise_file_descriptor_limit (context); - service_context_table = bus_config_parser_steal_service_context_table (parser); if (!bus_registry_set_service_context_table (context->registry, service_context_table)) @@ -721,9 +730,7 @@ process_config_postinit (BusContext *context, /* We need to monitor both the configuration directories and directories * containing .service files. */ - if (!list_concat_new (bus_config_parser_get_conf_dirs (parser), - bus_config_parser_get_service_dirs (parser), - &watched_dirs)) + if (!bus_config_parser_get_watched_dirs (parser, &watched_dirs)) { BUS_SET_OOM (error); return FALSE; @@ -933,9 +940,38 @@ bus_context_new (const DBusString *config_file, !_dbus_pipe_is_stdout_or_stderr (print_pid_pipe)) _dbus_pipe_close (print_pid_pipe, NULL); + /* Raise the file descriptor limits before dropping the privileges + * required to do so. + */ + raise_file_descriptor_limit (context); + + /* Here we change our credentials if required, + * as soon as we've set up our sockets and pidfile. + * This must be done before initializing LSMs, so that the netlink + * monitoring thread started by avc_init() will not lose CAP_AUDIT_WRITE + * when the main thread calls setuid(). + * https://bugs.freedesktop.org/show_bug.cgi?id=92832 + */ + if (context->user != NULL) + { + if (!_dbus_change_to_daemon_user (context->user, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + } + + /* Auditing should be initialized before LSMs, so that the LSMs are able + * to log audit-events that happen during their initialization. + */ + bus_audit_init (context); + if (!bus_selinux_full_init ()) { - bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but D-Bus initialization failed; check system log\n"); + bus_context_log (context, DBUS_SYSTEM_LOG_ERROR, + "SELinux enabled but D-Bus initialization failed; " + "check system log"); + exit (1); } if (!bus_apparmor_full_init (error)) @@ -952,6 +988,11 @@ bus_context_new (const DBusString *config_file, "AppArmor D-Bus mediation is enabled\n"); } + /* When SELinux is used, this must happen after bus_selinux_full_init() + * so that it has access to the access vector cache, which is required + * to process <associate/> elements. + * http://lists.freedesktop.org/archives/dbus/2008-October/010491.html + */ if (!process_config_postinit (context, parser, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); @@ -964,20 +1005,6 @@ bus_context_new (const DBusString *config_file, parser = NULL; } - /* Here we change our credentials if required, - * as soon as we've set up our sockets and pidfile - */ - if (context->user != NULL) - { - if (!_dbus_change_to_daemon_user (context->user, error)) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - goto failed; - } - } - - bus_audit_init (context); - context->check = bus_check_new(context, error); if (context->check == NULL) goto failed; @@ -1356,25 +1383,17 @@ bus_context_get_initial_fd_limit (BusContext *context) return context->initial_fd_limit; } +dbus_bool_t +bus_context_get_using_syslog (BusContext *context) +{ + return context->syslog; +} + void bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) { va_list args; - if (!context->syslog) - { - /* we're not syslogging; just output to stderr */ - va_start (args, msg); - vfprintf (stderr, msg, args); - fprintf (stderr, "\n"); - va_end (args); - - if (severity == DBUS_SYSTEM_LOG_FATAL) - _dbus_exit (1); - - return; - } - va_start (args, msg); if (context->log_prefix) @@ -1388,12 +1407,12 @@ bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char if (!_dbus_string_append_printf_valist (&full_msg, msg, args)) goto oom_out; - _dbus_system_log (severity, "%s", _dbus_string_get_const_data (&full_msg)); + _dbus_log (severity, "%s", _dbus_string_get_const_data (&full_msg)); oom_out: _dbus_string_free (&full_msg); } else - _dbus_system_logv (severity, msg, args); + _dbus_logv (severity, msg, args); out: va_end (args); @@ -1411,19 +1430,7 @@ bus_context_log_literal (BusContext *context, DBusSystemLogSeverity severity, const char *msg) { - if (!context->syslog) - { - fputs (msg, stderr); - fputc ('\n', stderr); - - if (severity == DBUS_SYSTEM_LOG_FATAL) - _dbus_exit (1); - } - else - { - _dbus_system_log (severity, "%s%s", nonnull (context->log_prefix, ""), - msg); - } + _dbus_log (severity, "%s%s", nonnull (context->log_prefix, ""), msg); } void @@ -1728,7 +1735,7 @@ bus_context_check_security_policy (BusContext *context, } else { - _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus\n"); + _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus"); recipient_policy = NULL; } } @@ -92,7 +92,10 @@ typedef enum BUS_CONTEXT_FLAG_FORK_ALWAYS = (1 << 1), BUS_CONTEXT_FLAG_FORK_NEVER = (1 << 2), BUS_CONTEXT_FLAG_WRITE_PID_FILE = (1 << 3), - BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION = (1 << 4) + BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION = (1 << 4), + BUS_CONTEXT_FLAG_SYSLOG_ALWAYS = (1 << 5), + BUS_CONTEXT_FLAG_SYSLOG_NEVER = (1 << 6), + BUS_CONTEXT_FLAG_SYSLOG_ONLY = (1 << 7) } BusContextFlags; BusContext* bus_context_new (const DBusString *config_file, @@ -139,6 +142,7 @@ int bus_context_get_max_match_rules_per_connection (BusContext int bus_context_get_max_replies_per_connection (BusContext *context); int bus_context_get_reply_timeout (BusContext *context); DBusRLimit * bus_context_get_initial_fd_limit (BusContext *context); +dbus_bool_t bus_context_get_using_syslog (BusContext *context); void bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, @@ -152,7 +156,6 @@ void bus_context_log_and_set_error (BusContext const char *name, const char *msg, ...) _DBUS_GNUC_PRINTF (5, 6); -void bus_context_check_all_watches (BusContext *context); BusResult bus_context_check_security_policy (BusContext *context, BusTransaction *transaction, DBusConnection *sender, @@ -162,6 +165,7 @@ BusResult bus_context_check_security_policy (BusContext BusActivationEntry *activation_entry, DBusError *error, BusDeferredMessage **deferred_message); +void bus_context_check_all_watches (BusContext *context); dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context, DBusConnection *recipient, diff --git a/bus/config-loader-expat.c b/bus/config-loader-expat.c index b571fda3..6cbd37eb 100644 --- a/bus/config-loader-expat.c +++ b/bus/config-loader-expat.c @@ -203,6 +203,20 @@ bus_config_load (const DBusString *file, goto failed; } + /* We do not need protection against hash collisions (CVE-2012-0876) + * because we are only parsing trusted XML; and if we let Expat block + * waiting for the CSPRNG to be initialized, as it does by default to + * defeat CVE-2012-0876, it can cause timeouts during early boot on + * entropy-starved embedded devices. + * + * TODO: When Expat gets a more explicit API for this than + * XML_SetHashSalt, check for that too, and use it preferentially. + * https://github.com/libexpat/libexpat/issues/91 */ +#if defined(HAVE_XML_SETHASHSALT) + /* Any nonzero number will do. https://xkcd.com/221/ */ + XML_SetHashSalt (expat, 4); +#endif + if (!_dbus_string_get_dirname (file, &dirname)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); @@ -242,7 +256,7 @@ bus_config_load (const DBusString *file, data_str = _dbus_string_get_const_data (&data); - if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE)) + if (XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE) == XML_STATUS_ERROR) { if (context.error != NULL && !dbus_error_is_set (context.error)) @@ -254,10 +268,13 @@ bus_config_load (const DBusString *file, dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); else dbus_set_error (error, DBUS_ERROR_FAILED, - "Error in file %s, line %d, column %d: %s\n", + "Error in file %s, line %lu, column %lu: %s\n", filename, - XML_GetCurrentLineNumber (expat), - XML_GetCurrentColumnNumber (expat), + /* The XML_Size type varies according to + * build options, so cast to something we can + * cope with. */ + (unsigned long) XML_GetCurrentLineNumber (expat), + (unsigned long) XML_GetCurrentColumnNumber (expat), XML_ErrorString (e)); } diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c index ea25f5e6..e2f253d8 100644 --- a/bus/config-parser-common.c +++ b/bus/config-parser-common.c @@ -193,10 +193,9 @@ bus_config_parser_element_type_to_name (ElementType type) return "allow_anonymous"; case ELEMENT_APPARMOR: return "apparmor"; + default: + _dbus_assert_not_reached ("bad element type"); + return NULL; } - - _dbus_assert_not_reached ("bad element type"); - - return NULL; } diff --git a/bus/config-parser-trivial.c b/bus/config-parser-trivial.c index 03ad8382..dd65c6d4 100644 --- a/bus/config-parser-trivial.c +++ b/bus/config-parser-trivial.c @@ -162,6 +162,7 @@ bus_config_parser_start_element (BusConfigParser *parser, switch (parser->type) { + case ELEMENT_SERVICEDIR: case ELEMENT_SERVICEHELPER: case ELEMENT_USER: case ELEMENT_CONFIGTYPE: @@ -185,6 +186,26 @@ bus_config_parser_start_element (BusConfigParser *parser, break; } + case ELEMENT_NONE: + case ELEMENT_BUSCONFIG: + case ELEMENT_INCLUDE: + case ELEMENT_LISTEN: + case ELEMENT_AUTH: + case ELEMENT_POLICY: + case ELEMENT_LIMIT: + case ELEMENT_ALLOW: + case ELEMENT_DENY: + case ELEMENT_FORK: + case ELEMENT_PIDFILE: + case ELEMENT_INCLUDEDIR: + case ELEMENT_SELINUX: + case ELEMENT_ASSOCIATE: + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + case ELEMENT_KEEP_UMASK: + case ELEMENT_SYSLOG: + case ELEMENT_ALLOW_ANONYMOUS: + case ELEMENT_APPARMOR: + /* fall through */ default: { /* we really don't care about the others... */ @@ -286,6 +307,28 @@ bus_config_parser_content (BusConfigParser *parser, } } break; + + case ELEMENT_NONE: + case ELEMENT_BUSCONFIG: + case ELEMENT_INCLUDE: + case ELEMENT_LISTEN: + case ELEMENT_AUTH: + case ELEMENT_POLICY: + case ELEMENT_LIMIT: + case ELEMENT_ALLOW: + case ELEMENT_DENY: + case ELEMENT_FORK: + case ELEMENT_PIDFILE: + case ELEMENT_INCLUDEDIR: + case ELEMENT_SELINUX: + case ELEMENT_ASSOCIATE: + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + case ELEMENT_KEEP_UMASK: + case ELEMENT_SYSLOG: + case ELEMENT_ALLOW_ANONYMOUS: + case ELEMENT_APPARMOR: + /* fall through */ default: { /* we don't care about the others... really */ @@ -324,8 +367,11 @@ bus_config_parser_get_type (BusConfigParser *parser) return _dbus_string_get_const_data (&parser->bus_type); } +/* + * @returns A list of strings, owned by the BusConfigParser + */ DBusList** -bus_config_parser_get_service_dirs (BusConfigParser *parser) +bus_config_parser_get_service_paths (BusConfigParser *parser) { return &parser->service_dirs; } @@ -370,14 +416,14 @@ check_return_values (const DBusString *full_path) user = bus_config_parser_get_user (parser); if (user == NULL) { - _dbus_warn ("User was NULL!\n"); + _dbus_warn ("User was NULL!"); goto finish; } #if 0 /* the username can be configured in configure.in so this test doesn't work */ if (strcmp (user, "dbus") != 0) { - _dbus_warn ("User was invalid; '%s'!\n", user); + _dbus_warn ("User was invalid; '%s'!", user); goto finish; } printf (" <user>dbus</user> OKAY!\n"); @@ -387,21 +433,21 @@ check_return_values (const DBusString *full_path) type = bus_config_parser_get_type (parser); if (type == NULL) { - _dbus_warn ("Type was NULL!\n"); + _dbus_warn ("Type was NULL!"); goto finish; } if (strcmp (type, "system") != 0) { - _dbus_warn ("Type was invalid; '%s'!\n", user); + _dbus_warn ("Type was invalid; '%s'!", user); goto finish; } printf (" <type>system</type> OKAY!\n"); /* check dirs return value is okay */ - dirs = bus_config_parser_get_service_dirs (parser); + dirs = bus_config_parser_get_service_paths (parser); if (dirs == NULL) { - _dbus_warn ("Service dirs are NULL!\n"); + _dbus_warn ("Service dirs are NULL!"); goto finish; } printf (" <standard_system_service_dirs/> OKAY!\n"); @@ -440,7 +486,7 @@ do_load (const DBusString *full_path, } else if (validity == VALID) { - _dbus_warn ("Failed to load valid file but still had memory: %s\n", + _dbus_warn ("Failed to load valid file but still had memory: %s", error.message); dbus_error_free (&error); @@ -460,7 +506,7 @@ do_load (const DBusString *full_path, if (validity == INVALID) { - _dbus_warn ("Accepted invalid file\n"); + _dbus_warn ("Accepted invalid file"); return FALSE; } @@ -497,7 +543,7 @@ process_test_valid_subdir (const DBusString *test_base_dir, dir = NULL; if (!_dbus_string_init (&test_directory)) - _dbus_assert_not_reached ("didn't allocate test_directory\n"); + _dbus_assert_not_reached ("didn't allocate test_directory"); _dbus_string_init_const (&filename, subdir); @@ -510,13 +556,13 @@ process_test_valid_subdir (const DBusString *test_base_dir, _dbus_string_free (&filename); if (!_dbus_string_init (&filename)) - _dbus_assert_not_reached ("didn't allocate filename string\n"); + _dbus_assert_not_reached ("didn't allocate filename string"); dbus_error_init (&error); dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { - _dbus_warn ("Could not open %s: %s\n", + _dbus_warn ("Could not open %s: %s", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); @@ -576,7 +622,7 @@ process_test_valid_subdir (const DBusString *test_base_dir, if (dbus_error_is_set (&error)) { - _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_warn ("Could not get next file in %s: %s", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); diff --git a/bus/config-parser-trivial.h b/bus/config-parser-trivial.h index 31ddef6b..abe41fdf 100644 --- a/bus/config-parser-trivial.h +++ b/bus/config-parser-trivial.h @@ -59,7 +59,7 @@ dbus_bool_t bus_config_parser_finished (BusConfigParser *parser, /* Functions for extracting the parse results */ const char* bus_config_parser_get_user (BusConfigParser *parser); const char* bus_config_parser_get_type (BusConfigParser *parser); -DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser); +DBusList** bus_config_parser_get_service_paths (BusConfigParser *parser); /* Loader functions (backended off one of the XML parsers). Returns a * finished ConfigParser. diff --git a/bus/config-parser.c b/bus/config-parser.c index 00005cc7..42218547 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -100,7 +100,7 @@ struct BusConfigParser DBusList *mechanisms; /**< Auth mechanisms */ - DBusList *service_dirs; /**< Directories to look for session services in */ + DBusList *service_dirs; /**< BusConfigServiceDirs to look for session services in */ DBusList *conf_dirs; /**< Directories to look for policy configuration in */ @@ -232,7 +232,33 @@ merge_service_context_hash (DBusHashTable *dest, return FALSE; } -static dbus_bool_t +/* + * Create a new BusConfigServiceDir. Takes ownership of path if #TRUE is returned. + * + * @returns #FALSE on OOM + */ +static BusConfigServiceDir * +bus_config_service_dir_new_take (char *path, + BusServiceDirFlags flags) +{ + BusConfigServiceDir *self = dbus_new0 (BusConfigServiceDir, 1); + + if (self == NULL) + return NULL; + + self->path = path; /* take ownership */ + self->flags = flags; + return self; +} + +static void +bus_config_service_dir_free (BusConfigServiceDir *self) +{ + dbus_free (self->path); + dbus_free (self); +} + +static BusConfigServiceDir * service_dirs_find_dir (DBusList **service_dirs, const char *dir) { @@ -242,42 +268,81 @@ service_dirs_find_dir (DBusList **service_dirs, for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link)) { - const char *link_dir; - - link_dir = (const char *)link->data; - if (strcmp (dir, link_dir) == 0) - return TRUE; - } + BusConfigServiceDir *link_dir = link->data; - return FALSE; -} - -static dbus_bool_t -service_dirs_append_unique_or_free (DBusList **service_dirs, - char *dir) -{ - if (!service_dirs_find_dir (service_dirs, dir)) - return _dbus_list_append (service_dirs, dir); + if (strcmp (dir, link_dir->path) == 0) + return link_dir; + } - dbus_free (dir); - return TRUE; + return NULL; } -static void +static void service_dirs_append_link_unique_or_free (DBusList **service_dirs, DBusList *dir_link) { - if (!service_dirs_find_dir (service_dirs, dir_link->data)) + BusConfigServiceDir *dir = dir_link->data; + BusConfigServiceDir *already = service_dirs_find_dir (service_dirs, + dir->path); + + if (already == NULL) { _dbus_list_append_link (service_dirs, dir_link); } else { - dbus_free (dir_link->data); + /* BusServiceDirFlags are chosen such that the compatible thing to do + * is to "and" the flags. For example, if a directory is explicitly + * added as a <servicedir> (which is watched with inotify) and is also + * the transient service directory (which should not be watched), + * the compatible thing to do is to watch it. */ + already->flags &= dir->flags; + bus_config_service_dir_free (dir_link->data); _dbus_list_free_link (dir_link); } } +/* + * Consume links from dirs (a list of paths), converting them into links in + * service_dirs (a list of unique BusServiceDir). + * + * On success, return TRUE. dirs will be empty, and every original entry in + * dirs will have a corresponding service_dirs entry. + * + * On OOM, return FALSE. Each original entry of dirs has either been + * appended to service_dirs or left in dirs. + */ +static dbus_bool_t +service_dirs_absorb_string_list (DBusList **service_dirs, + DBusList **dirs, + BusServiceDirFlags flags) +{ + DBusList *link; + + _dbus_assert (service_dirs != NULL); + _dbus_assert (dirs != NULL); + + while ((link = _dbus_list_pop_first_link (dirs))) + { + char *path = link->data; + BusConfigServiceDir *dir = bus_config_service_dir_new_take (path, flags); + + if (dir == NULL) + { + /* OOM - roll back (this does not need to allocate memory) */ + _dbus_list_prepend_link (service_dirs, link); + return FALSE; + } + + /* Ownership of path has been taken by dir */ + link->data = dir; + service_dirs_append_link_unique_or_free (service_dirs, link); + } + + _dbus_assert (*dirs == NULL); + return TRUE; +} + static dbus_bool_t merge_included (BusConfigParser *parser, BusConfigParser *included, @@ -515,7 +580,7 @@ bus_config_parser_unref (BusConfigParser *parser) _dbus_list_clear (&parser->listen_on); _dbus_list_foreach (&parser->service_dirs, - (DBusForeachFunction) dbus_free, + (DBusForeachFunction) bus_config_service_dir_free, NULL); _dbus_list_clear (&parser->service_dirs); @@ -583,7 +648,7 @@ locate_attributes (BusConfigParser *parser, const char *name; const char **retloc; int n_attrs; -#define MAX_ATTRS 24 +#define MAX_ATTRS 25 LocateAttr attrs[MAX_ATTRS]; dbus_bool_t retval; int i; @@ -832,9 +897,8 @@ start_busconfig_child (BusConfigParser *parser, } else if (element_type == ELEMENT_STANDARD_SESSION_SERVICEDIRS) { - DBusList *link; - DBusList *dirs; - dirs = NULL; + DBusError local_error = DBUS_ERROR_INIT; + DBusList *dirs = NULL; if (!check_no_attributes (parser, "standard_session_servicedirs", attribute_names, attribute_values, error)) return FALSE; @@ -845,20 +909,54 @@ start_busconfig_child (BusConfigParser *parser, return FALSE; } + if (_dbus_set_up_transient_session_servicedirs (&dirs, &local_error)) + { + if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs, + BUS_SERVICE_DIR_FLAGS_NO_WATCH | + BUS_SERVICE_DIR_FLAGS_STRICT_NAMING)) + { + BUS_SET_OOM (error); + _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free, + NULL); + _dbus_list_clear (&dirs); + return FALSE; + } + } + else + { + /* Failing to set these up isn't fatal */ + _dbus_warn ("Unable to set up transient service directory: %s", + local_error.message); + dbus_error_free (&local_error); + } + + _dbus_assert (dirs == NULL); + if (!_dbus_get_standard_session_servicedirs (&dirs)) { BUS_SET_OOM (error); return FALSE; } - while ((link = _dbus_list_pop_first_link (&dirs))) - service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + /* We have traditionally watched the standard session service + * directories with inotify, and allowed service files whose names do not + * match the bus name */ + if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs, + BUS_SERVICE_DIR_FLAGS_NONE)) + { + BUS_SET_OOM (error); + _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free, + NULL); + _dbus_list_clear (&dirs); + return FALSE; + } + + _dbus_assert (dirs == NULL); return TRUE; } else if (element_type == ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) { - DBusList *link; DBusList *dirs; dirs = NULL; @@ -877,8 +975,19 @@ start_busconfig_child (BusConfigParser *parser, return FALSE; } - while ((link = _dbus_list_pop_first_link (&dirs))) - service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + /* We have traditionally watched the standard system service + * directories with inotify, and allowed service files whose names do not + * match the bus name (the servicehelper won't successfully activate + * them, but we do still parse them) */ + if (!service_dirs_absorb_string_list (&parser->service_dirs, &dirs, + BUS_SERVICE_DIR_FLAGS_NONE)) + { + BUS_SET_OOM (error); + _dbus_list_foreach (&dirs, (DBusForeachFunction) dbus_free, + NULL); + _dbus_list_clear (&dirs); + return FALSE; + } return TRUE; } @@ -1049,7 +1158,7 @@ start_busconfig_child (BusConfigParser *parser, &e->d.policy.gid_uid_or_at_console)) e->d.policy.type = POLICY_USER; else - _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n", + _dbus_warn ("Unknown username \"%s\" in message bus configuration file", user); } else if (group != NULL) @@ -1061,7 +1170,7 @@ start_busconfig_child (BusConfigParser *parser, &e->d.policy.gid_uid_or_at_console)) e->d.policy.type = POLICY_GROUP; else - _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n", + _dbus_warn ("Unknown group \"%s\" in message bus configuration file", group); } else if (at_console != NULL) @@ -1167,6 +1276,43 @@ start_busconfig_child (BusConfigParser *parser, } } +/* + * Parse an attribute named name, whose content is content, or NULL if + * missing. It is meant to be a (long) integer between min and max inclusive. + * If it is missing, use def as the default value (which does not + * necessarily need to be between min and max). + */ +static dbus_bool_t +parse_int_attribute (const char *name, + const char *content, + long min, + long max, + long def, + long *value, + DBusError *error) +{ + DBusString parse_string; + + *value = def; + + if (content == NULL) + return TRUE; + + _dbus_string_init_const (&parse_string, content); + + if (!_dbus_string_parse_int (&parse_string, 0, value, NULL) || + *value < min || *value > max) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be an " + "integer in range %ld to %ld inclusive", + content, name, min, max); + return FALSE; + } + + return TRUE; +} + static dbus_bool_t append_rule_from_element (BusConfigParser *parser, const char *element_name, @@ -1176,6 +1322,8 @@ append_rule_from_element (BusConfigParser *parser, DBusError *error) { const char *log; + + /* Group: send_ attributes */ const char *send_interface; const char *send_member; const char *send_error; @@ -1183,15 +1331,32 @@ append_rule_from_element (BusConfigParser *parser, const char *send_destination_prefix; const char *send_path; const char *send_type; + const char *send_requested_reply; + const char *send_broadcast; + /* TRUE if any send_ attribute is present */ + dbus_bool_t any_send_attribute; + + /* Group: receive_ attributes */ const char *receive_interface; const char *receive_member; const char *receive_error; const char *receive_sender; const char *receive_path; const char *receive_type; - const char *eavesdrop; - const char *send_requested_reply; const char *receive_requested_reply; + /* TRUE if any receive_ attribute is present */ + dbus_bool_t any_receive_attribute; + + /* Group: message-matching modifiers that can go on send_ or receive_ */ + const char *eavesdrop; + const char *max_fds_attr; + long max_fds = DBUS_MAXIMUM_MESSAGE_UNIX_FDS; + const char *min_fds_attr; + long min_fds = 0; + /* TRUE if any message-matching modifier is present */ + dbus_bool_t any_message_attribute; + + /* Non-message-related attributes */ const char *own; const char *own_prefix; const char *user; @@ -1199,7 +1364,7 @@ append_rule_from_element (BusConfigParser *parser, const char *privilege; BusPolicyRule *rule; - + if (!locate_attributes (parser, element_name, attribute_names, attribute_values, @@ -1211,6 +1376,7 @@ append_rule_from_element (BusConfigParser *parser, "send_destination_prefix", &send_destination_prefix, "send_path", &send_path, "send_type", &send_type, + "send_broadcast", &send_broadcast, "receive_interface", &receive_interface, "receive_member", &receive_member, "receive_error", &receive_error, @@ -1218,6 +1384,8 @@ append_rule_from_element (BusConfigParser *parser, "receive_path", &receive_path, "receive_type", &receive_type, "eavesdrop", &eavesdrop, + "max_fds", &max_fds_attr, + "min_fds", &min_fds_attr, "send_requested_reply", &send_requested_reply, "receive_requested_reply", &receive_requested_reply, "own", &own, @@ -1229,12 +1397,36 @@ append_rule_from_element (BusConfigParser *parser, NULL)) return FALSE; - if (!(send_interface || send_member || send_error || - send_destination || send_destination_prefix || - send_type || send_path || - receive_interface || receive_member || receive_error || receive_sender || - receive_type || receive_path || eavesdrop || - send_requested_reply || receive_requested_reply || + any_send_attribute = (send_destination != NULL || + send_destination_prefix != NULL || + send_broadcast != NULL || + send_path != NULL || + send_type != NULL || + send_interface != NULL || + send_member != NULL || + send_error != NULL || + send_requested_reply != NULL); + any_receive_attribute = (receive_sender != NULL || + receive_path != NULL || + receive_type != NULL || + receive_interface != NULL || + receive_member != NULL || + receive_error != NULL || + receive_requested_reply != NULL || + /* <allow eavesdrop="true"/> means the same as + * <allow receive_sender="*" eavesdrop="true"/>, + * but <allow send_anything="anything"/> can also + * take the eavesdrop attribute and still counts + * as a send rule. */ + (!any_send_attribute && eavesdrop != NULL)); + any_message_attribute = (any_send_attribute || + any_receive_attribute || + eavesdrop != NULL || + max_fds_attr != NULL || + min_fds_attr != NULL); + + if (!(any_send_attribute || + any_receive_attribute || privilege || own || own_prefix || user || group)) { @@ -1284,124 +1476,57 @@ append_rule_from_element (BusConfigParser *parser, * interface + member * error * - * base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply + * base send_ can combine with send_destination, send_destination_prefix, send_path, send_type, send_requested_reply, send_broadcast, eavesdrop * send_destination must not occur with send_destination_prefix * base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop * * user, group, own, own_prefix must occur alone - * - * Pretty sure the below stuff is broken, FIXME think about it more. */ - if ((send_interface && (send_error || - receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_member && (send_error || - receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_error && (receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_destination && (send_destination_prefix || - receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_destination_prefix && (receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_type && (receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_path && (receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (send_requested_reply && (receive_interface || - receive_member || - receive_error || - receive_sender || - receive_requested_reply || - own || own_prefix || - user || - group)) || - - (receive_interface && (receive_error || - own || own_prefix || - user || - group)) || - - (receive_member && (receive_error || - own || own_prefix || - user || - group)) || - - (receive_error && (own || own_prefix || - user || - group)) || - - (eavesdrop && (own || own_prefix || - user || - group)) || - - (receive_requested_reply && (own || own_prefix || - user || - group)) || - - (own && (own_prefix || user || group)) || - - (own_prefix && (own || user || group)) || - - (user && group)) + if (any_message_attribute + + ((own != NULL) + + (own_prefix != NULL) + + (user != NULL) + + (group != NULL)) > 1) { dbus_set_error (error, DBUS_ERROR_FAILED, - "Invalid combination of attributes on element <%s>", + "Invalid combination of attributes on element <%s>: " + "own, own_prefix, user, group and the message-related " + "attributes cannot be combined", element_name); return FALSE; } - + + if (any_send_attribute && any_receive_attribute) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid combination of attributes on element <%s>: " + "send and receive attributes cannot be combined", + element_name); + return FALSE; + } + + if ((send_member != NULL || send_interface != NULL) && send_error != NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid combination of attributes on element <%s>: " + "send_error cannot be combined with send_member or " + "send_interface", + element_name); + return FALSE; + } + + if ((receive_member != NULL || receive_interface != NULL) && + receive_error != NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid combination of attributes on element <%s>: " + "receive_error cannot be combined with receive_member " + "or receive_interface", + element_name); + return FALSE; + } + rule = NULL; /* In BusPolicyRule, NULL represents wildcard. @@ -1409,8 +1534,7 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send_interface || send_member || send_error || send_destination || send_destination_prefix || - send_path || send_type || send_requested_reply) + if (any_send_attribute) { int message_type; @@ -1450,6 +1574,29 @@ append_rule_from_element (BusConfigParser *parser, return FALSE; } + if (send_broadcast && + !(strcmp (send_broadcast, "true") == 0 || + strcmp (send_broadcast, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be true or false", + send_broadcast, "send_broadcast"); + return FALSE; + } + + if (send_destination != NULL && + send_broadcast != NULL && + strcmp (send_broadcast, "true") == 0) + { + /* Broadcast messages have no destination, so this cannot + * possibly match */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "Rule with send_broadcast=\"true\" and " + "send_destination=\"%s\" cannot match anything", + send_destination); + return FALSE; + } + if (send_requested_reply && !(strcmp (send_requested_reply, "true") == 0 || strcmp (send_requested_reply, "false") == 0)) @@ -1459,7 +1606,19 @@ append_rule_from_element (BusConfigParser *parser, "send_requested_reply", send_requested_reply); return FALSE; } - + + /* Matching only messages with DBUS_MAXIMUM_MESSAGE_UNIX_FDS or fewer + * fds is the same as matching all messages, so we always set a maximum, + * but perhaps an unrealistically high one. */ + if (!parse_int_attribute ("max_fds", max_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, + DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds, + error) || + !parse_int_attribute ("min_fds", min_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds, + error)) + return FALSE; + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access); if (rule == NULL) goto nomem; @@ -1473,6 +1632,18 @@ append_rule_from_element (BusConfigParser *parser, if (send_requested_reply) rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0); + if (send_broadcast) + { + if (strcmp (send_broadcast, "true") == 0) + rule->d.send.broadcast = BUS_POLICY_TRISTATE_TRUE; + else + rule->d.send.broadcast = BUS_POLICY_TRISTATE_FALSE; + } + else + { + rule->d.send.broadcast = BUS_POLICY_TRISTATE_ANY; + } + rule->d.send.message_type = message_type; rule->d.send.path = _dbus_strdup (send_path); rule->d.send.interface = _dbus_strdup (send_interface); @@ -1488,6 +1659,9 @@ append_rule_from_element (BusConfigParser *parser, rule->d.send.destination = _dbus_strdup (send_destination_prefix); rule->d.send.destination_prefix = 1; } + rule->d.send.max_fds = max_fds; + rule->d.send.min_fds = min_fds; + if (send_path && rule->d.send.path == NULL) goto nomem; if (send_interface && rule->d.send.interface == NULL) @@ -1499,8 +1673,7 @@ append_rule_from_element (BusConfigParser *parser, if ((send_destination || send_destination_prefix) && rule->d.send.destination == NULL) goto nomem; } - else if (receive_interface || receive_member || receive_error || receive_sender || - receive_path || receive_type || eavesdrop || receive_requested_reply) + else if (any_receive_attribute) { int message_type; @@ -1550,7 +1723,16 @@ append_rule_from_element (BusConfigParser *parser, "receive_requested_reply", receive_requested_reply); return FALSE; } - + + if (!parse_int_attribute ("max_fds", max_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, + DBUS_MAXIMUM_MESSAGE_UNIX_FDS, &max_fds, + error) || + !parse_int_attribute ("min_fds", min_fds_attr, + 0, DBUS_MAXIMUM_MESSAGE_UNIX_FDS, 0, &min_fds, + error)) + return FALSE; + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access); if (rule == NULL) goto nomem; @@ -1567,6 +1749,8 @@ append_rule_from_element (BusConfigParser *parser, rule->d.receive.member = _dbus_strdup (receive_member); rule->d.receive.error = _dbus_strdup (receive_error); rule->d.receive.origin = _dbus_strdup (receive_sender); + rule->d.receive.max_fds = max_fds; + rule->d.receive.min_fds = min_fds; if (receive_path && rule->d.receive.path == NULL) goto nomem; @@ -1630,7 +1814,7 @@ append_rule_from_element (BusConfigParser *parser, } else { - _dbus_warn ("Unknown username \"%s\" on element <%s>\n", + _dbus_warn ("Unknown username \"%s\" on element <%s>", user, element_name); } } @@ -1662,7 +1846,7 @@ append_rule_from_element (BusConfigParser *parser, } else { - _dbus_warn ("Unknown group \"%s\" on element <%s>\n", + _dbus_warn ("Unknown group \"%s\" on element <%s>", group, element_name); } } @@ -1685,6 +1869,7 @@ append_rule_from_element (BusConfigParser *parser, switch (pe->d.policy.type) { case POLICY_IGNORED: + default: /* drop the rule on the floor */ break; @@ -2121,6 +2306,7 @@ bus_config_parser_end_element (BusConfigParser *parser, switch (e->type) { case ELEMENT_NONE: + default: _dbus_assert_not_reached ("element in stack has no type"); break; @@ -2189,7 +2375,8 @@ make_full_path (const DBusString *basedir, { if (_dbus_path_is_absolute (filename)) { - return _dbus_string_copy (filename, 0, full_path, 0); + if (!_dbus_string_copy (filename, 0, full_path, 0)) + return FALSE; } else { @@ -2198,9 +2385,12 @@ make_full_path (const DBusString *basedir, if (!_dbus_concat_dir_and_file (full_path, filename)) return FALSE; - - return TRUE; } + + if (!_dbus_replace_install_prefix (full_path)) + return FALSE; + + return TRUE; } static dbus_bool_t @@ -2373,15 +2563,17 @@ include_dir (BusConfigParser *parser, { if (dbus_error_is_set (error)) { - /* We log to syslog unconditionally here, because this is + /* We use both syslog and stderr here, because this is * the configuration parser, so we don't yet know whether - * this bus is going to want to write to syslog! (There's - * also some layer inversion going on, if we want to use - * the bus context.) */ - _dbus_system_log (DBUS_SYSTEM_LOG_INFO, - "Encountered error '%s' while parsing '%s'\n", - error->message, - _dbus_string_get_const_data (&full_path)); + * this bus is going to want to write to syslog! Err on + * the side of making sure the message gets to the sysadmin + * somehow. */ + _dbus_init_system_log ("dbus-daemon", + DBUS_LOG_FLAGS_STDERR | DBUS_LOG_FLAGS_SYSTEM_LOG); + _dbus_log (DBUS_SYSTEM_LOG_INFO, + "Encountered error '%s' while parsing '%s'", + error->message, + _dbus_string_get_const_data (&full_path)); dbus_error_free (error); } } @@ -2457,6 +2649,7 @@ bus_config_parser_content (BusConfigParser *parser, switch (top_element_type (parser)) { case ELEMENT_NONE: + default: _dbus_assert_not_reached ("element at top of stack has no type"); return FALSE; @@ -2662,8 +2855,10 @@ bus_config_parser_content (BusConfigParser *parser, case ELEMENT_SERVICEDIR: { char *s; + BusConfigServiceDir *dir; DBusString full_path; - + DBusList *link; + e->had_content = TRUE; if (!_dbus_string_init (&full_path)) @@ -2681,14 +2876,29 @@ bus_config_parser_content (BusConfigParser *parser, goto nomem; } - /* _only_ extra session directories can be specified */ - if (!service_dirs_append_unique_or_free (&parser->service_dirs, s)) + /* <servicedir/> has traditionally implied that we watch the + * directory with inotify, and allow service files whose names do not + * match the bus name */ + dir = bus_config_service_dir_new_take (s, BUS_SERVICE_DIR_FLAGS_NONE); + + if (dir == NULL) { _dbus_string_free (&full_path); dbus_free (s); goto nomem; } + link = _dbus_list_alloc_link (dir); + + if (link == NULL) + { + _dbus_string_free (&full_path); + bus_config_service_dir_free (dir); + goto nomem; + } + + /* cannot fail */ + service_dirs_append_link_unique_or_free (&parser->service_dirs, link); _dbus_string_free (&full_path); } break; @@ -2858,6 +3068,51 @@ bus_config_parser_steal_service_context_table (BusConfigParser *parser) return table; } +/* + * Return a list of the directories that should be watched with inotify, + * as strings. The list might be empty and is in arbitrary order. + * + * The list must be empty on entry. On success, the links are owned by the + * caller and must be freed, but the data in each link remains owned by + * the BusConfigParser and must not be freed: in GObject-Introspection + * notation, it is (transfer container). + */ +dbus_bool_t +bus_config_parser_get_watched_dirs (BusConfigParser *parser, + DBusList **watched_dirs) +{ + DBusList *link; + + _dbus_assert (*watched_dirs == NULL); + + for (link = _dbus_list_get_first_link (&parser->conf_dirs); + link != NULL; + link = _dbus_list_get_next_link (&parser->conf_dirs, link)) + { + if (!_dbus_list_append (watched_dirs, link->data)) + goto oom; + } + + for (link = _dbus_list_get_first_link (&parser->service_dirs); + link != NULL; + link = _dbus_list_get_next_link (&parser->service_dirs, link)) + { + BusConfigServiceDir *dir = link->data; + + if (dir->flags & BUS_SERVICE_DIR_FLAGS_NO_WATCH) + continue; + + if (!_dbus_list_append (watched_dirs, dir->path)) + goto oom; + } + + return TRUE; + +oom: + _dbus_list_clear (watched_dirs); + return FALSE; +} + #ifdef DBUS_ENABLE_EMBEDDED_TESTS #include <stdio.h> @@ -2872,7 +3127,7 @@ static dbus_bool_t do_check_own_rules (BusPolicy *policy) { const struct { - char *name; + const char *name; dbus_bool_t allowed; } checks[] = { {"org.freedesktop", FALSE}, @@ -2902,12 +3157,12 @@ do_check_own_rules (BusPolicy *policy) ret ? "allowed" : "not allowed"); if (checks[i].allowed && !ret) { - _dbus_warn ("Cannot own %s\n", checks[i].name); + _dbus_warn ("Cannot own %s", checks[i].name); return FALSE; } if (!checks[i].allowed && ret) { - _dbus_warn ("Can own %s\n", checks[i].name); + _dbus_warn ("Can own %s", checks[i].name); return FALSE; } _dbus_string_free (&service_name); @@ -2945,7 +3200,7 @@ do_load (const DBusString *full_path, } else if (validity == VALID) { - _dbus_warn ("Failed to load valid file but still had memory: %s\n", + _dbus_warn ("Failed to load valid file but still had memory: %s", error.message); dbus_error_free (&error); @@ -2970,7 +3225,7 @@ do_load (const DBusString *full_path, if (validity == INVALID) { - _dbus_warn ("Accepted invalid file\n"); + _dbus_warn ("Accepted invalid file"); return FALSE; } @@ -3008,7 +3263,7 @@ process_test_valid_subdir (const DBusString *test_base_dir, dir = NULL; if (!_dbus_string_init (&test_directory)) - _dbus_assert_not_reached ("didn't allocate test_directory\n"); + _dbus_assert_not_reached ("didn't allocate test_directory"); _dbus_string_init_const (&filename, subdir); @@ -3021,13 +3276,13 @@ process_test_valid_subdir (const DBusString *test_base_dir, _dbus_string_free (&filename); if (!_dbus_string_init (&filename)) - _dbus_assert_not_reached ("didn't allocate filename string\n"); + _dbus_assert_not_reached ("didn't allocate filename string"); dbus_error_init (&error); dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { - _dbus_warn ("Could not open %s: %s\n", + _dbus_warn ("Could not open %s: %s", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); @@ -3089,7 +3344,7 @@ process_test_valid_subdir (const DBusString *test_base_dir, if (dbus_error_is_set (&error)) { - _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_warn ("Could not get next file in %s: %s", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); @@ -3158,8 +3413,29 @@ elements_equal (const Element *a, return FALSE; break; + case ELEMENT_NONE: + case ELEMENT_BUSCONFIG: + case ELEMENT_USER: + case ELEMENT_LISTEN: + case ELEMENT_AUTH: + case ELEMENT_ALLOW: + case ELEMENT_DENY: + case ELEMENT_FORK: + case ELEMENT_PIDFILE: + case ELEMENT_SERVICEDIR: + case ELEMENT_SERVICEHELPER: + case ELEMENT_INCLUDEDIR: + case ELEMENT_CONFIGTYPE: + case ELEMENT_SELINUX: + case ELEMENT_ASSOCIATE: + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + case ELEMENT_KEEP_UMASK: + case ELEMENT_SYSLOG: + case ELEMENT_ALLOW_ANONYMOUS: + case ELEMENT_APPARMOR: default: - /* do nothing */ + /* do nothing: nothing in the Element struct for these types */ break; } @@ -3210,6 +3486,34 @@ lists_of_c_strings_equal (DBusList *a, } static dbus_bool_t +lists_of_service_dirs_equal (DBusList *a, + DBusList *b) +{ + DBusList *ia; + DBusList *ib; + + ia = a; + ib = b; + + while (ia != NULL && ib != NULL) + { + BusConfigServiceDir *da = ia->data; + BusConfigServiceDir *db = ib->data; + + if (strcmp (da->path, db->path)) + return FALSE; + + if (da->flags != db->flags) + return FALSE; + + ia = _dbus_list_get_next_link (&a, ia); + ib = _dbus_list_get_next_link (&b, ib); + } + + return ia == NULL && ib == NULL; +} + +static dbus_bool_t limits_equal (const BusLimits *a, const BusLimits *b) { @@ -3252,7 +3556,7 @@ config_parsers_equal (const BusConfigParser *a, if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms)) return FALSE; - if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs)) + if (!lists_of_service_dirs_equal (a->service_dirs, b->service_dirs)) return FALSE; /* FIXME: compare policy */ @@ -3300,7 +3604,7 @@ all_are_equiv (const DBusString *target_directory) dir = _dbus_directory_open (target_directory, &error); if (dir == NULL) { - _dbus_warn ("Could not open %s: %s\n", + _dbus_warn ("Could not open %s: %s", _dbus_string_get_const_data (target_directory), error.message); dbus_error_free (&error); @@ -3337,7 +3641,7 @@ all_are_equiv (const DBusString *target_directory) if (parser == NULL) { - _dbus_warn ("Could not load file %s: %s\n", + _dbus_warn ("Could not load file %s: %s", _dbus_string_get_const_data (&full_path), error.message); _dbus_string_free (&full_path); @@ -3406,7 +3710,7 @@ process_test_equiv_subdir (const DBusString *test_base_dir, dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { - _dbus_warn ("Could not open %s: %s\n", + _dbus_warn ("Could not open %s: %s", _dbus_string_get_const_data (&test_directory), error.message); dbus_error_free (&error); @@ -3451,52 +3755,79 @@ process_test_equiv_subdir (const DBusString *test_base_dir, static const char *test_session_service_dir_matches[] = { -#ifdef DBUS_UNIX - "/testhome/foo/.testlocal/testshare/dbus-1/services", - "/testusr/testlocal/testshare/dbus-1/services", - "/testusr/testshare/dbus-1/services", - DBUS_DATADIR"/dbus-1/services", -#endif /* will be filled in test_default_session_servicedirs() */ #ifdef DBUS_WIN - NULL, - NULL, + NULL, /* install root-based */ + NULL, /* CommonProgramFiles-based */ +#else + NULL, /* XDG_RUNTIME_DIR-based */ + NULL, /* XDG_DATA_HOME-based */ + NULL, /* XDG_DATA_DIRS-based */ + NULL, /* XDG_DATA_DIRS-based */ + DBUS_DATADIR "/dbus-1/services", #endif NULL }; static dbus_bool_t -test_default_session_servicedirs (void) +test_default_session_servicedirs (const DBusString *test_base_dir) { - DBusList *dirs; + BusConfigParser *parser = NULL; + DBusError error = DBUS_ERROR_INIT; + DBusList **dirs; + DBusList *watched_dirs = NULL; DBusList *link; + DBusString tmp; + DBusString full_path; DBusString progs; DBusString install_root_based; + DBusString runtime_dir_based; + DBusString data_home_based; + DBusString data_dirs_based; + DBusString data_dirs_based2; int i; dbus_bool_t ret = FALSE; #ifdef DBUS_WIN - const char *tmp; const char *common_progs; +#else + const char *dbus_test_builddir; + const char *xdg_data_home; + const char *xdg_runtime_dir; #endif - /* On Unix we don't actually use these, but it's easier to handle the - * deallocation if we always allocate them, whether needed or not */ - if (!_dbus_string_init (&progs) || - !_dbus_string_init (&install_root_based)) + /* On each platform we don't actually use all of these, but it's easier to + * handle the deallocation if we always allocate them, whether needed or + * not */ + if (!_dbus_string_init (&full_path) || + !_dbus_string_init (&progs) || + !_dbus_string_init (&install_root_based) || + !_dbus_string_init (&runtime_dir_based) || + !_dbus_string_init (&data_home_based) || + !_dbus_string_init (&data_dirs_based) || + !_dbus_string_init (&data_dirs_based2)) _dbus_assert_not_reached ("OOM allocating strings"); + if (!_dbus_string_copy (test_base_dir, 0, + &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to full_path"); + + _dbus_string_init_const (&tmp, "valid-config-files"); + + if (!_dbus_concat_dir_and_file (&full_path, &tmp)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_init_const (&tmp, "standard-session-dirs.conf"); + + if (!_dbus_concat_dir_and_file (&full_path, &tmp)) + _dbus_assert_not_reached ("couldn't allocate full path"); + #ifdef DBUS_WIN if (!_dbus_string_append (&install_root_based, DBUS_DATADIR) || - !_dbus_string_append (&install_root_based, "/dbus-1/services")) + !_dbus_string_append (&install_root_based, "/dbus-1/services") || + !_dbus_replace_install_prefix (&install_root_based)) goto out; - tmp = _dbus_replace_install_prefix ( - _dbus_string_get_const_data (&install_root_based)); - - if (tmp == NULL || - !_dbus_string_set_length (&install_root_based, 0) || - !_dbus_string_append (&install_root_based, tmp)) - goto out; + _dbus_assert (_dbus_path_is_absolute (&install_root_based)); test_session_service_dir_matches[0] = _dbus_string_get_const_data ( &install_root_based); @@ -3513,72 +3844,143 @@ test_default_session_servicedirs (void) test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs); } +#else + dbus_test_builddir = _dbus_getenv ("DBUS_TEST_BUILDDIR"); + xdg_data_home = _dbus_getenv ("XDG_DATA_HOME"); + xdg_runtime_dir = _dbus_getenv ("XDG_RUNTIME_DIR"); + + if (dbus_test_builddir == NULL || xdg_data_home == NULL || + xdg_runtime_dir == NULL) + { + printf ("Not testing default session service directories because a " + "build-time testing environment variable is not set: " + "see AM_TESTS_ENVIRONMENT in tests/Makefile.am\n"); + ret = TRUE; + goto out; + } + + if (!_dbus_string_append (&data_dirs_based, dbus_test_builddir) || + !_dbus_string_append (&data_dirs_based, "/XDG_DATA_DIRS/dbus-1/services") || + !_dbus_string_append (&data_dirs_based2, dbus_test_builddir) || + !_dbus_string_append (&data_dirs_based2, "/XDG_DATA_DIRS2/dbus-1/services") || + !_dbus_string_append (&runtime_dir_based, xdg_runtime_dir) || + !_dbus_string_append (&data_home_based, xdg_data_home) || + !_dbus_string_append (&data_home_based, "/dbus-1/services")) + _dbus_assert_not_reached ("out of memory"); + + if (!_dbus_ensure_directory (&runtime_dir_based, NULL)) + _dbus_assert_not_reached ("Unable to create fake XDG_RUNTIME_DIR"); + + if (!_dbus_string_append (&runtime_dir_based, "/dbus-1/services")) + _dbus_assert_not_reached ("out of memory"); + + /* Sanity check: the Makefile sets this up. We assume that if this is + * right, the XDG_DATA_DIRS will be too. */ + if (!_dbus_string_starts_with_c_str (&data_home_based, dbus_test_builddir)) + _dbus_assert_not_reached ("$XDG_DATA_HOME should start with $DBUS_TEST_BUILDDIR"); + + if (!_dbus_string_starts_with_c_str (&runtime_dir_based, dbus_test_builddir)) + _dbus_assert_not_reached ("$XDG_RUNTIME_DIR should start with $DBUS_TEST_BUILDDIR"); + + test_session_service_dir_matches[0] = _dbus_string_get_const_data ( + &runtime_dir_based); + test_session_service_dir_matches[1] = _dbus_string_get_const_data ( + &data_home_based); + test_session_service_dir_matches[2] = _dbus_string_get_const_data ( + &data_dirs_based); + test_session_service_dir_matches[3] = _dbus_string_get_const_data ( + &data_dirs_based2); #endif - dirs = NULL; - printf ("Testing retrieving the default session service directories\n"); - if (!_dbus_get_standard_session_servicedirs (&dirs)) - _dbus_assert_not_reached ("couldn't get stardard dirs"); + parser = bus_config_load (&full_path, TRUE, NULL, &error); - /* make sure our defaults end with share/dbus-1/service */ - while ((link = _dbus_list_pop_first_link (&dirs))) + if (parser == NULL) + _dbus_assert_not_reached (error.message); + + dirs = bus_config_parser_get_service_dirs (parser); + + for (link = _dbus_list_get_first_link (dirs), i = 0; + link != NULL; + link = _dbus_list_get_next_link (dirs, link), i++) { - DBusString path; - - printf (" default service dir: %s\n", (char *)link->data); - _dbus_string_init_const (&path, (char *)link->data); - if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services")) + BusConfigServiceDir *dir = link->data; + BusServiceDirFlags expected = BUS_SERVICE_DIR_FLAGS_NONE; + + printf (" test service dir: '%s'\n", dir->path); + printf (" current standard service dir: '%s'\n", test_session_service_dir_matches[i]); + if (test_session_service_dir_matches[i] == NULL) { - printf ("error with default session service directories\n"); - dbus_free (link->data); - _dbus_list_free_link (link); + printf ("more directories parsed than in match set\n"); goto out; } - dbus_free (link->data); - _dbus_list_free_link (link); + if (strcmp (test_session_service_dir_matches[i], dir->path) != 0) + { + printf ("'%s' directory does not match '%s' in the match set\n", + dir->path, test_session_service_dir_matches[i]); + goto out; + } + +#ifndef DBUS_WIN + /* On Unix we expect the first directory in the search path to be + * in the XDG_RUNTIME_DIR, and we expect it to have special flags */ + if (i == 0) + expected = (BUS_SERVICE_DIR_FLAGS_NO_WATCH | + BUS_SERVICE_DIR_FLAGS_STRICT_NAMING); +#endif + + if (dir->flags != expected) + { + printf ("'%s' directory has flags 0x%x, should be 0x%x\n", + dir->path, dir->flags, expected); + goto out; + } + } + + if (test_session_service_dir_matches[i] != NULL) + { + printf ("extra data %s in the match set was not matched\n", + test_session_service_dir_matches[i]); + goto out; } -#ifdef DBUS_UNIX - if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare")) - _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME"); + if (!bus_config_parser_get_watched_dirs (parser, &watched_dirs)) + _dbus_assert_not_reached ("out of memory"); - if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:")) - _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS"); +#ifdef DBUS_WIN + /* We expect all directories to be watched (not that it matters on Windows, + * because we don't know how) */ + i = 0; +#else + /* We expect all directories except the first to be watched, because + * the first one is transient */ + i = 1; #endif - if (!_dbus_get_standard_session_servicedirs (&dirs)) - _dbus_assert_not_reached ("couldn't get stardard dirs"); - /* make sure we read and parse the env variable correctly */ - i = 0; - while ((link = _dbus_list_pop_first_link (&dirs))) + for (link = _dbus_list_get_first_link (&watched_dirs); + link != NULL; + link = _dbus_list_get_next_link (&watched_dirs, link), i++) { - printf (" test service dir: %s\n", (char *)link->data); + printf (" watched service dir: '%s'\n", (const char *) link->data); + printf (" current standard service dir: '%s'\n", + test_session_service_dir_matches[i]); + if (test_session_service_dir_matches[i] == NULL) { printf ("more directories parsed than in match set\n"); - dbus_free (link->data); - _dbus_list_free_link (link); goto out; } - - if (strcmp (test_session_service_dir_matches[i], - (char *)link->data) != 0) + + if (strcmp (test_session_service_dir_matches[i], + (const char *) link->data) != 0) { - printf ("%s directory does not match %s in the match set\n", - (char *)link->data, + printf ("'%s' directory does not match '%s' in the match set\n", + (const char *) link->data, test_session_service_dir_matches[i]); - dbus_free (link->data); - _dbus_list_free_link (link); goto out; } - - ++i; - - dbus_free (link->data); - _dbus_list_free_link (link); } - + if (test_session_service_dir_matches[i] != NULL) { printf ("extra data %s in the match set was not matched\n", @@ -3589,25 +3991,27 @@ test_default_session_servicedirs (void) ret = TRUE; out: + if (parser != NULL) + bus_config_parser_unref (parser); + + _dbus_list_clear (&watched_dirs); + _dbus_string_free (&full_path); _dbus_string_free (&install_root_based); _dbus_string_free (&progs); + _dbus_string_free (&runtime_dir_based); + _dbus_string_free (&data_home_based); + _dbus_string_free (&data_dirs_based); + _dbus_string_free (&data_dirs_based2); return ret; } +#ifndef DBUS_WIN static const char *test_system_service_dir_matches[] = { -#ifdef DBUS_UNIX "/usr/local/share/dbus-1/system-services", "/usr/share/dbus-1/system-services", -#endif DBUS_DATADIR"/dbus-1/system-services", -#ifdef DBUS_UNIX "/lib/dbus-1/system-services", -#endif - -#ifdef DBUS_WIN - NULL, -#endif NULL }; @@ -3616,69 +4020,10 @@ test_default_system_servicedirs (void) { DBusList *dirs; DBusList *link; - DBusString progs; -#ifndef DBUS_UNIX - const char *common_progs; -#endif int i; - /* On Unix we don't actually use this variable, but it's easier to handle the - * deallocation if we always allocate it, whether needed or not */ - if (!_dbus_string_init (&progs)) - _dbus_assert_not_reached ("OOM allocating progs"); - -#ifndef DBUS_UNIX - common_progs = _dbus_getenv ("CommonProgramFiles"); - - if (common_progs) - { - if (!_dbus_string_append (&progs, common_progs)) - { - _dbus_string_free (&progs); - return FALSE; - } - - if (!_dbus_string_append (&progs, "/dbus-1/system-services")) - { - _dbus_string_free (&progs); - return FALSE; - } - test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs); - } -#endif dirs = NULL; - printf ("Testing retrieving the default system service directories\n"); - if (!_dbus_get_standard_system_servicedirs (&dirs)) - _dbus_assert_not_reached ("couldn't get stardard dirs"); - - /* make sure our defaults end with share/dbus-1/system-service */ - while ((link = _dbus_list_pop_first_link (&dirs))) - { - DBusString path; - - printf (" default service dir: %s\n", (char *)link->data); - _dbus_string_init_const (&path, (char *)link->data); - if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services")) - { - printf ("error with default system service directories\n"); - dbus_free (link->data); - _dbus_list_free_link (link); - _dbus_string_free (&progs); - return FALSE; - } - - dbus_free (link->data); - _dbus_list_free_link (link); - } - -#ifdef DBUS_UNIX - if (!dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare")) - _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME"); - - if (!dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:")) - _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS"); -#endif if (!_dbus_get_standard_system_servicedirs (&dirs)) _dbus_assert_not_reached ("couldn't get stardard dirs"); @@ -3692,7 +4037,6 @@ test_default_system_servicedirs (void) printf ("more directories parsed than in match set\n"); dbus_free (link->data); _dbus_list_free_link (link); - _dbus_string_free (&progs); return FALSE; } @@ -3704,7 +4048,6 @@ test_default_system_servicedirs (void) test_system_service_dir_matches[i]); dbus_free (link->data); _dbus_list_free_link (link); - _dbus_string_free (&progs); return FALSE; } @@ -3719,13 +4062,12 @@ test_default_system_servicedirs (void) printf ("extra data %s in the match set was not matched\n", test_system_service_dir_matches[i]); - _dbus_string_free (&progs); return FALSE; } - _dbus_string_free (&progs); return TRUE; } +#endif dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir) @@ -3737,7 +4079,7 @@ bus_config_parser_test (const DBusString *test_data_dir) return TRUE; } - if (!test_default_session_servicedirs()) + if (!test_default_session_servicedirs (test_data_dir)) return FALSE; #ifdef DBUS_WIN diff --git a/bus/config-parser.h b/bus/config-parser.h index ba5bf749..a24e74b2 100644 --- a/bus/config-parser.h +++ b/bus/config-parser.h @@ -73,6 +73,8 @@ DBusList** bus_config_parser_get_conf_dirs (BusConfigParser *parser); BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser); void bus_config_parser_get_limits (BusConfigParser *parser, BusLimits *limits); +dbus_bool_t bus_config_parser_get_watched_dirs (BusConfigParser *parser, + DBusList **watched_dirs); DBusHashTable* bus_config_parser_steal_service_context_table (BusConfigParser *parser); @@ -84,4 +86,23 @@ BusConfigParser* bus_config_load (const DBusString *file, const BusConfigParser *parent, DBusError *error); +/* + * These are chosen such that if we configure a directory twice with different + * flags, we have to do an "and" operation on the flags - the compatible + * thing to do is to have no flags. + */ +typedef enum +{ + BUS_SERVICE_DIR_FLAGS_NO_WATCH = (1 << 0), + BUS_SERVICE_DIR_FLAGS_STRICT_NAMING = (1 << 1), + /* Keep this one at the end to reduce diffs when adding new entries */ + BUS_SERVICE_DIR_FLAGS_NONE = 0 +} BusServiceDirFlags; + +typedef struct +{ + BusServiceDirFlags flags; + char *path; +} BusConfigServiceDir; + #endif /* BUS_CONFIG_PARSER_H */ diff --git a/bus/connection.c b/bus/connection.c index 7253c98e..e1802e7d 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -454,9 +454,6 @@ free_connection_data (void *data) if (d->policy) bus_client_policy_unref (d->policy); - if (d->selinux_id) - bus_selinux_id_unref (d->selinux_id); - if (d->apparmor_confinement) bus_apparmor_confinement_unref (d->apparmor_confinement); @@ -601,7 +598,7 @@ cache_peer_loginfo_string (BusConnectionData *d, DBusString loginfo_buf; unsigned long uid; unsigned long pid; - char *windows_sid; + char *windows_sid = NULL, *security_label = NULL; dbus_bool_t prev_added; if (!_dbus_string_init (&loginfo_buf)) @@ -630,16 +627,48 @@ cache_peer_loginfo_string (BusConnectionData *d, _dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL); if (!_dbus_string_append_byte (&loginfo_buf, '"')) goto oom; + else + prev_added = TRUE; } if (dbus_connection_get_windows_user (connection, &windows_sid)) { dbus_bool_t did_append; + + if (prev_added) + { + if (!_dbus_string_append_byte (&loginfo_buf, ' ')) + goto oom; + } + did_append = _dbus_string_append_printf (&loginfo_buf, - "sid=\"%s\" ", windows_sid); + "sid=\"%s\"", windows_sid); dbus_free (windows_sid); + windows_sid = NULL; + if (!did_append) + goto oom; + else + prev_added = TRUE; + } + + if (_dbus_connection_get_linux_security_label (connection, &security_label)) + { + dbus_bool_t did_append; + + if (prev_added) + { + if (!_dbus_string_append_byte (&loginfo_buf, ' ')) + goto oom; + } + + did_append = _dbus_string_append_printf (&loginfo_buf, + "label=\"%s\"", security_label); + dbus_free (security_label); + security_label = NULL; if (!did_append) goto oom; + else + prev_added = TRUE; } if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string))) @@ -650,6 +679,11 @@ cache_peer_loginfo_string (BusConnectionData *d, return TRUE; oom: _dbus_string_free (&loginfo_buf); + if (security_label != NULL) + dbus_free (security_label); + if (windows_sid != NULL) + dbus_free (windows_sid); + return FALSE; } @@ -687,6 +721,18 @@ static dbus_bool_t pending_unix_fds_timeout_cb (void *data) { DBusConnection *connection = data; + BusConnectionData *d = BUS_CONNECTION_DATA (connection); + int limit; + + _dbus_assert (d != NULL); + limit = bus_context_get_pending_fd_timeout (d->connections->context); + bus_context_log (d->connections->context, DBUS_SYSTEM_LOG_WARNING, + "Connection \"%s\" (%s) has had Unix fds pending for too long, " + "closing it (pending_fd_timeout=%d ms)", + d->name != NULL ? d->name : "(null)", + bus_connection_get_loginfo (connection), + limit); + dbus_connection_close (connection); return TRUE; } @@ -696,15 +742,13 @@ bus_connections_setup_connection (BusConnections *connections, DBusConnection *connection) { - BusConnectionData *d; - dbus_bool_t retval; + BusConnectionData *d = NULL; DBusError error; - d = dbus_new0 (BusConnectionData, 1); if (d == NULL) - return FALSE; + goto oom; d->connections = connections; d->connection = connection; @@ -718,39 +762,35 @@ bus_connections_setup_connection (BusConnections *connections, connection_data_slot, d, free_connection_data)) { + /* We have to free d explicitly, because this is the only code + * path where it's non-NULL but dbus_connection_set_data() hasn't + * taken responsibility for freeing it. */ dbus_free (d); - return FALSE; + d = NULL; + goto oom; } dbus_connection_set_route_peer_messages (connection, TRUE); - - retval = FALSE; dbus_error_init (&error); d->selinux_id = bus_selinux_init_connection_id (connection, &error); if (dbus_error_is_set (&error)) { - /* This is a bit bogus because we pretend all errors - * are OOM; this is done because we know that in bus.c - * an OOM error disconnects the connection, which is - * the same thing we want on any other error. - */ + bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING, + "Unable to set up new connection: %s", error.message); dbus_error_free (&error); - goto out; + goto error; } d->apparmor_confinement = bus_apparmor_init_connection_confinement (connection, &error); if (dbus_error_is_set (&error)) { - /* This is a bit bogus because we pretend all errors - * are OOM; this is done because we know that in bus.c - * an OOM error disconnects the connection, which is - * the same thing we want on any other error. - */ + bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING, + "Unable to set up new connection: %s", error.message); dbus_error_free (&error); - goto out; + goto error; } if (!dbus_connection_set_watch_functions (connection, @@ -759,14 +799,14 @@ bus_connections_setup_connection (BusConnections *connections, toggle_connection_watch, connection, NULL)) - goto out; + goto oom; if (!dbus_connection_set_timeout_functions (connection, add_connection_timeout, remove_connection_timeout, NULL, connection, NULL)) - goto out; + goto oom; /* For now we don't need to set a Windows user function because * there are no policies in the config file controlling what @@ -784,18 +824,18 @@ bus_connections_setup_connection (BusConnections *connections, d->link_in_connection_list = _dbus_list_alloc_link (connection); if (d->link_in_connection_list == NULL) - goto out; + goto oom; /* Setup the connection with the dispatcher */ if (!bus_dispatch_add_connection (connection)) - goto out; + goto oom; if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) { if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection)) { bus_dispatch_remove_connection (connection); - goto out; + goto oom; } } @@ -804,12 +844,12 @@ bus_connections_setup_connection (BusConnections *connections, pending_unix_fds_timeout_cb, connection, NULL); if (d->pending_unix_fds_timeout == NULL) - goto out; + goto oom; _dbus_timeout_disable (d->pending_unix_fds_timeout); if (!_dbus_loop_add_timeout (bus_context_get_loop (connections->context), d->pending_unix_fds_timeout)) - goto out; + goto oom; _dbus_connection_set_pending_fds_function (connection, (DBusPendingFdsChangeFunction) check_pending_fds_cb, @@ -832,13 +872,15 @@ bus_connections_setup_connection (BusConnections *connections, * stop accept()ing any more, to avert a DoS. See fd.o #80919 */ bus_context_check_all_watches (d->connections->context); - retval = TRUE; + return TRUE; - out: - if (!retval) +oom: + bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING, + "No memory to set up new connection"); + /* fall through */ +error: + if (d != NULL) { - if (d->selinux_id) - bus_selinux_id_unref (d->selinux_id); d->selinux_id = NULL; if (d->apparmor_confinement) @@ -889,7 +931,7 @@ bus_connections_setup_connection (BusConnections *connections, /* "d" has now been freed */ } - return retval; + return FALSE; } void @@ -1697,13 +1739,23 @@ bus_connection_get_name (DBusConnection *connection) dbus_bool_t bus_connections_check_limits (BusConnections *connections, DBusConnection *requesting_completion, + const char **limit_name_out, + int *limit_out, DBusError *error) { unsigned long uid; + int limit; + + limit = bus_context_get_max_completed_connections (connections->context); - if (connections->n_completed >= - bus_context_get_max_completed_connections (connections->context)) + if (connections->n_completed >= limit) { + if (limit_name_out != NULL) + *limit_name_out = "max_completed_connections"; + + if (limit_out != NULL) + *limit_out = limit; + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The maximum number of active connections has been reached"); return FALSE; @@ -1711,9 +1763,16 @@ bus_connections_check_limits (BusConnections *connections, if (dbus_connection_get_unix_user (requesting_completion, &uid)) { - if (get_connections_for_uid (connections, uid) >= - bus_context_get_max_connections_per_user (connections->context)) + limit = bus_context_get_max_connections_per_user (connections->context); + + if (get_connections_for_uid (connections, uid) >= limit) { + if (limit_name_out != NULL) + *limit_name_out = "max_connections_per_user"; + + if (limit_out != NULL) + *limit_out = limit; + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The maximum number of active connections for UID %lu has been reached", uid); @@ -1933,6 +1992,7 @@ bus_connections_expect_reply (BusConnections *connections, DBusList *link; CancelPendingReplyData *cprd; int count; + int limit; _dbus_assert (will_get_reply != NULL); _dbus_assert (will_send_reply != NULL); @@ -1963,10 +2023,19 @@ bus_connections_expect_reply (BusConnections *connections, if (pending->will_get_reply == will_get_reply) ++count; } - - if (count >= - bus_context_get_max_replies_per_connection (connections->context)) + + limit = bus_context_get_max_replies_per_connection (connections->context); + + if (count >= limit) { + bus_context_log (connections->context, DBUS_SYSTEM_LOG_WARNING, + "The maximum number of pending replies for " + "\"%s\" (%s) has been reached " + "(max_replies_per_connection=%d)", + bus_connection_get_name (will_get_reply), + bus_connection_get_loginfo (will_get_reply), + limit); + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The maximum number of pending replies per connection has been reached"); return FALSE; @@ -2246,6 +2315,7 @@ bus_transaction_get_context (BusTransaction *transaction) dbus_bool_t bus_transaction_capture (BusTransaction *transaction, DBusConnection *sender, + DBusConnection *addressed_recipient, DBusMessage *message) { BusConnections *connections; @@ -2265,8 +2335,8 @@ bus_transaction_capture (BusTransaction *transaction, * There's little point, since there is up to 1 per process. */ _dbus_assert (mm != NULL); - if (!bus_matchmaker_get_recipients (mm, connections, sender, NULL, message, - &recipients)) + if (!bus_matchmaker_get_recipients (mm, connections, sender, + addressed_recipient, message, &recipients)) goto out; for (link = _dbus_list_get_first_link (&recipients); @@ -2288,6 +2358,7 @@ out: dbus_bool_t bus_transaction_capture_error_reply (BusTransaction *transaction, + DBusConnection *addressed_recipient, const DBusError *error, DBusMessage *in_reply_to) { @@ -2314,7 +2385,7 @@ bus_transaction_capture_error_reply (BusTransaction *transaction, if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)) goto out; - ret = bus_transaction_capture (transaction, NULL, reply); + ret = bus_transaction_capture (transaction, NULL, addressed_recipient, reply); out: dbus_message_unref (reply); @@ -2357,7 +2428,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction, /* Capture it for monitors, even if the real recipient's receive policy * does not allow it to receive this message from us (which would be odd). */ - if (!bus_transaction_capture (transaction, NULL, message)) + if (!bus_transaction_capture (transaction, NULL, connection, message)) return FALSE; /* If security policy doesn't allow the message, we would silently @@ -2374,7 +2445,8 @@ bus_transaction_send_from_driver (BusTransaction *transaction, case BUS_RESULT_TRUE: break; case BUS_RESULT_FALSE: - if (!bus_transaction_capture_error_reply (transaction, &error, message)) + if (!bus_transaction_capture_error_reply (transaction, connection, + &error, message)) { bus_context_log (transaction->context, DBUS_SYSTEM_LOG_WARNING, "message from dbus-daemon rejected but not enough " diff --git a/bus/connection.h b/bus/connection.h index 6c6fca8d..ba7ce2f3 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -58,6 +58,8 @@ BusSELinuxID* bus_connection_get_selinux_id (DBusConnection BusAppArmorConfinement* bus_connection_dup_apparmor_confinement (DBusConnection *connection); dbus_bool_t bus_connections_check_limits (BusConnections *connections, DBusConnection *requesting_completion, + const char **limit_name_out, + int *limit_out, DBusError *error); void bus_connections_expire_incomplete (BusConnections *connections); @@ -158,8 +160,10 @@ dbus_bool_t bus_transaction_send (BusTransaction * dbus_bool_t deferred_dispatch); dbus_bool_t bus_transaction_capture (BusTransaction *transaction, DBusConnection *connection, + DBusConnection *addressed_recipient, DBusMessage *message); dbus_bool_t bus_transaction_capture_error_reply (BusTransaction *transaction, + DBusConnection *addressed_recipient, const DBusError *error, DBusMessage *in_reply_to); dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction, diff --git a/bus/dbus.service.in b/bus/dbus.service.in index 9686f362..21ea6769 100644 --- a/bus/dbus.service.in +++ b/bus/dbus.service.in @@ -6,7 +6,7 @@ Requires=dbus.socket [Service] Type=notify -ExecStart=@EXPANDED_BINDIR@/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation +ExecStart=@EXPANDED_BINDIR@/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only ExecReload=@EXPANDED_BINDIR@/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig OOMScoreAdjust=-900 User=dbus diff --git a/bus/desktop-file.c b/bus/desktop-file.c index bfeb72e2..fd4f0d31 100644 --- a/bus/desktop-file.c +++ b/bus/desktop-file.c @@ -88,7 +88,7 @@ static unsigned char valid[256] = { }; static void report_error (BusDesktopFileParser *parser, - char *message, + const char *message, const char *error_name, DBusError *error); @@ -378,12 +378,16 @@ parse_comment_or_blank (BusDesktopFileParser *parser) static dbus_bool_t is_valid_section_name (const char *name) { - /* 5. Group names may contain all ASCII characters except for control characters and '[' and ']'. */ + /* 5. Group names may contain all ASCII characters except for control characters and '[' and ']'. + * + * We don't use isprint() here because it's locale-dependent. ASCII + * characters <= 0x1f and 0x7f are control characters, and bytes with + * values >= 0x80 aren't ASCII. 0x20 is a space, which we must allow, + * not least because DBUS_SERVICE_SECTION contains one. */ while (*name) { - if (!((*name >= 'A' && *name <= 'Z') || (*name >= 'a' || *name <= 'z') || - *name == '\n' || *name == '\t')) + if (*name <= 0x1f || *name >= 0x7f || *name == '[' || *name == ']') return FALSE; name++; @@ -579,7 +583,7 @@ parse_key_value (BusDesktopFileParser *parser, DBusError *error) static void report_error (BusDesktopFileParser *parser, - char *message, + const char *message, const char *error_name, DBusError *error) { diff --git a/bus/desktop-file.h b/bus/desktop-file.h index e405625c..14477387 100644 --- a/bus/desktop-file.h +++ b/bus/desktop-file.h @@ -35,6 +35,7 @@ #define DBUS_SERVICE_EXEC "Exec" #define DBUS_SERVICE_USER "User" #define DBUS_SERVICE_SYSTEMD_SERVICE "SystemdService" +#define DBUS_SERVICE_ASSUMED_APPARMOR_LABEL "AssumedAppArmorLabel" typedef struct BusDesktopFile BusDesktopFile; diff --git a/bus/dir-watch-inotify.c b/bus/dir-watch-inotify.c index a287f0ba..447dc2db 100644 --- a/bus/dir-watch-inotify.c +++ b/bus/dir-watch-inotify.c @@ -157,7 +157,7 @@ _set_watched_dirs_internal (DBusList **directories) /* Not all service directories need to exist. */ if (errno != ENOENT) { - _dbus_warn ("Cannot setup inotify for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + _dbus_warn ("Cannot setup inotify for '%s'; error '%s'", new_dirs[i], _dbus_strerror (errno)); goto out; } else @@ -236,7 +236,7 @@ _init_inotify (BusContext *context) #endif if (inotify_fd <= 0) { - _dbus_warn ("Cannot initialize inotify\n"); + _dbus_warn ("Cannot initialize inotify"); goto out; } @@ -252,7 +252,7 @@ _init_inotify (BusContext *context) if (watch == NULL) { - _dbus_warn ("Unable to create inotify watch\n"); + _dbus_warn ("Unable to create inotify watch"); goto out; } diff --git a/bus/dir-watch-kqueue.c b/bus/dir-watch-kqueue.c index c1e83245..9b1784e8 100644 --- a/bus/dir-watch-kqueue.c +++ b/bus/dir-watch-kqueue.c @@ -137,7 +137,7 @@ _init_kqueue (BusContext *context) kq = kqueue (); if (kq < 0) { - _dbus_warn ("Cannot create kqueue; error '%s'\n", _dbus_strerror (errno)); + _dbus_warn ("Cannot create kqueue; error '%s'", _dbus_strerror (errno)); goto out; } @@ -149,7 +149,7 @@ _init_kqueue (BusContext *context) if (watch == NULL) { - _dbus_warn ("Unable to create kqueue watch\n"); + _dbus_warn ("Unable to create kqueue watch"); goto out1; } @@ -276,7 +276,7 @@ bus_set_watched_dirs (BusContext *context, DBusList **directories) { if (errno != ENOENT) { - _dbus_warn ("Cannot open directory '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + _dbus_warn ("Cannot open directory '%s'; error '%s'", new_dirs[i], _dbus_strerror (errno)); goto out; } else @@ -297,7 +297,7 @@ bus_set_watched_dirs (BusContext *context, DBusList **directories) NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0); if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1) { - _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'", new_dirs[i], _dbus_strerror (errno)); close (fd); goto out; } diff --git a/bus/dispatch.c b/bus/dispatch.c index f4dea605..3cdae9f9 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -75,8 +75,8 @@ send_one_message (DBusConnection *connection, if (result == BUS_RESULT_FALSE) { - if (!bus_transaction_capture_error_reply (transaction, &stack_error, - message)) + if (!bus_transaction_capture_error_reply (transaction, sender, + &stack_error, message)) { bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "broadcast rejected, but not enough " @@ -96,8 +96,8 @@ send_one_message (DBusConnection *connection, bus_connection_get_name (connection), bus_connection_get_loginfo (connection)); - if (!bus_transaction_capture_error_reply (transaction, &stack_error, - message)) + if (!bus_transaction_capture_error_reply (transaction, sender, + &stack_error, message)) { bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "broadcast with Unix fd not delivered, but not " @@ -483,17 +483,17 @@ bus_dispatch (DBusConnection *connection, */ service_name = dbus_message_get_destination (message); - if (!bus_transaction_capture (transaction, connection, message)) - { - BUS_SET_OOM (&error); - goto out; - } - if (service_name && strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ { BusDeferredMessage *deferred_message; + if (!bus_transaction_capture (transaction, connection, NULL, message)) + { + BUS_SET_OOM (&error); + goto out; + } + switch (bus_context_check_security_policy (context, transaction, connection, NULL, NULL, message, NULL, &error, @@ -530,6 +530,12 @@ bus_dispatch (DBusConnection *connection, } else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */ { + if (!bus_transaction_capture (transaction, connection, NULL, message)) + { + BUS_SET_OOM (&error); + goto out; + } + _dbus_verbose ("Received message from non-registered client. Disconnecting.\n"); dbus_connection_close (connection); goto out; @@ -552,6 +558,13 @@ bus_dispatch (DBusConnection *connection, BusActivation *activation; BusDeferredMessage *deferred_message; + if (!bus_transaction_capture (transaction, connection, NULL, + message)) + { + BUS_SET_OOM (&error); + goto out; + } + activation = bus_connection_get_activation (connection); /* This will do as much of a security policy check as it can. @@ -581,6 +594,13 @@ bus_dispatch (DBusConnection *connection, } else if (service == NULL) { + if (!bus_transaction_capture (transaction, connection, + NULL, message)) + { + BUS_SET_OOM (&error); + goto out; + } + dbus_set_error (&error, DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist", @@ -591,6 +611,21 @@ bus_dispatch (DBusConnection *connection, { addressed_recipient = bus_service_get_primary_owners_connection (service); _dbus_assert (addressed_recipient != NULL); + + if (!bus_transaction_capture (transaction, connection, + addressed_recipient, message)) + { + BUS_SET_OOM (&error); + goto out; + } + } + } + else /* service_name == NULL */ + { + if (!bus_transaction_capture (transaction, connection, NULL, message)) + { + BUS_SET_OOM (&error); + goto out; } } @@ -769,7 +804,7 @@ warn_unexpected_real (DBusConnection *connection, int line) { if (message) - _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s", function, line, dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "(unset)", @@ -780,7 +815,7 @@ warn_unexpected_real (DBusConnection *connection, connection, expected); else - _dbus_warn ("%s:%d received no message on %p, expecting %s\n", + _dbus_warn ("%s:%d received no message on %p, expecting %s", function, line, connection, expected); } @@ -840,7 +875,7 @@ check_service_owner_changed_foreach (DBusConnection *connection, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a message on %p, expecting %s\n", + _dbus_warn ("Did not receive a message on %p, expecting %s", connection, "NameOwnerChanged"); goto out; } @@ -876,7 +911,7 @@ check_service_owner_changed_foreach (DBusConnection *connection, } else { - _dbus_warn ("Did not get the expected arguments\n"); + _dbus_warn ("Did not get the expected arguments"); goto out; } } @@ -885,13 +920,13 @@ check_service_owner_changed_foreach (DBusConnection *connection, || (d->expected_kind == OWNER_CHANGED && (!old_owner[0] || !new_owner[0])) || (d->expected_kind == SERVICE_DELETED && (!old_owner[0] || new_owner[0]))) { - _dbus_warn ("inconsistent NameOwnerChanged arguments\n"); + _dbus_warn ("inconsistent NameOwnerChanged arguments"); goto out; } if (strcmp (service_name, d->expected_service_name) != 0) { - _dbus_warn ("expected info on service %s, got info on %s\n", + _dbus_warn ("expected info on service %s, got info on %s", d->expected_service_name, service_name); goto out; @@ -900,7 +935,7 @@ check_service_owner_changed_foreach (DBusConnection *connection, if (*service_name == ':' && new_owner[0] && strcmp (service_name, new_owner) != 0) { - _dbus_warn ("inconsistent ServiceOwnedChanged message (\"%s\" [ %s -> %s ])\n", + _dbus_warn ("inconsistent ServiceOwnedChanged message (\"%s\" [ %s -> %s ])", service_name, old_owner, new_owner); goto out; } @@ -1112,7 +1147,7 @@ check_hello_message (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Hello", serial, connection); goto out; } @@ -1121,7 +1156,7 @@ check_hello_message (BusContext *context, if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -1171,7 +1206,7 @@ check_hello_message (BusContext *context, else { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Did not get the expected single string argument to hello\n"); + _dbus_warn ("Did not get the expected single string argument to hello"); goto out; } } @@ -1203,7 +1238,7 @@ check_hello_message (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Expecting %s, got nothing\n", + _dbus_warn ("Expecting %s, got nothing", "NameAcquired"); goto out; } @@ -1211,7 +1246,7 @@ check_hello_message (BusContext *context, if (! dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameAcquired")) { - _dbus_warn ("Expecting %s, got smthg else\n", + _dbus_warn ("Expecting %s, got smthg else", "NameAcquired"); goto out; } @@ -1231,7 +1266,7 @@ check_hello_message (BusContext *context, else { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n"); + _dbus_warn ("Did not get the expected single string argument to ServiceAcquired"); goto out; } } @@ -1240,7 +1275,7 @@ check_hello_message (BusContext *context, if (strcmp (acquired, name) != 0) { - _dbus_warn ("Acquired name is %s but expected %s\n", + _dbus_warn ("Acquired name is %s but expected %s", acquired, name); goto out; } @@ -1323,7 +1358,7 @@ check_double_hello_message (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Hello", serial, connection); goto out; } @@ -1332,7 +1367,7 @@ check_double_hello_message (BusContext *context, if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -1425,7 +1460,7 @@ check_get_connection_unix_user (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "GetConnectionUnixUser", serial, connection); goto out; } @@ -1481,7 +1516,7 @@ check_get_connection_unix_user (BusContext *context, else { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixUser\n"); + _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixUser"); goto out; } } @@ -1570,7 +1605,7 @@ check_get_connection_unix_process_id (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "GetConnectionUnixProcessID", serial, connection); goto out; } @@ -1644,7 +1679,7 @@ check_get_connection_unix_process_id (BusContext *context, else { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixProcessID\n"); + _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixProcessID"); goto out; } } @@ -1660,7 +1695,7 @@ check_get_connection_unix_process_id (BusContext *context, if (pid != (dbus_uint32_t) _dbus_getpid ()) { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Result from GetConnectionUnixProcessID is not our own pid\n"); + _dbus_warn ("Result from GetConnectionUnixProcessID is not our own pid"); goto out; } } @@ -1755,7 +1790,7 @@ check_add_match (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "AddMatch", serial, connection); goto out; } @@ -1764,7 +1799,7 @@ check_add_match (BusContext *context, if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -1880,7 +1915,7 @@ check_get_all_match_rules (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "AddMatch", serial, connection); goto out; } @@ -1889,7 +1924,7 @@ check_get_all_match_rules (BusContext *context, if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -2047,7 +2082,7 @@ check_nonexistent_service_no_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "StartServiceByName", serial, connection); goto out; } @@ -2058,7 +2093,7 @@ check_nonexistent_service_no_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -2082,7 +2117,7 @@ check_nonexistent_service_no_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully activate %s\n", + _dbus_warn ("Did not expect to successfully activate %s", NONEXISTENT_SERVICE_NAME); goto out; } @@ -2140,7 +2175,7 @@ check_nonexistent_service_auto_start (BusContext *context, if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -2151,7 +2186,7 @@ check_nonexistent_service_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -2175,7 +2210,7 @@ check_nonexistent_service_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully activate %s\n", + _dbus_warn ("Did not expect to successfully activate %s", NONEXISTENT_SERVICE_NAME); goto out; } @@ -2235,7 +2270,7 @@ check_base_service_activated (BusContext *context, } else { - _dbus_warn ("Message %s doesn't have a service name: %s\n", + _dbus_warn ("Message %s doesn't have a service name: %s", "NameOwnerChanged (creation)", error.message); goto out; @@ -2244,21 +2279,21 @@ check_base_service_activated (BusContext *context, if (*base_service != ':') { - _dbus_warn ("Expected base service activation, got \"%s\" instead\n", + _dbus_warn ("Expected base service activation, got \"%s\" instead", base_service); goto out; } if (strcmp (base_service, base_service_from_bus) != 0) { - _dbus_warn ("Expected base service activation, got \"%s\" instead with owner \"%s\"\n", + _dbus_warn ("Expected base service activation, got \"%s\" instead with owner \"%s\"", base_service, base_service_from_bus); goto out; } if (old_owner[0]) { - _dbus_warn ("Received an old_owner argument during base service activation, \"%s\"\n", + _dbus_warn ("Received an old_owner argument during base service activation, \"%s\"", old_owner); goto out; } @@ -2340,7 +2375,7 @@ check_service_activated (BusContext *context, } else { - _dbus_warn ("Message %s doesn't have a service name: %s\n", + _dbus_warn ("Message %s doesn't have a service name: %s", "NameOwnerChanged (creation)", error.message); goto out; @@ -2349,21 +2384,21 @@ check_service_activated (BusContext *context, if (strcmp (service_name, activated_name) != 0) { - _dbus_warn ("Expected to see service %s created, saw %s instead\n", + _dbus_warn ("Expected to see service %s created, saw %s instead", activated_name, service_name); goto out; } if (strcmp (base_service_name, base_service_from_bus) != 0) { - _dbus_warn ("NameOwnerChanged reports wrong base service: %s owner, expected %s instead\n", + _dbus_warn ("NameOwnerChanged reports wrong base service: %s owner, expected %s instead", base_service_from_bus, base_service_name); goto out; } if (old_owner[0]) { - _dbus_warn ("expected a %s, got a %s\n", + _dbus_warn ("expected a %s, got a %s", "NameOwnerChanged (creation)", "NameOwnerChanged (change)"); goto out; @@ -2389,7 +2424,7 @@ check_service_activated (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Expected a reply to %s, got nothing\n", + _dbus_warn ("Expected a reply to %s, got nothing", "StartServiceByName"); goto out; } @@ -2415,7 +2450,7 @@ check_service_activated (BusContext *context, { if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { - _dbus_warn ("Did not have activation result first argument to %s: %s\n", + _dbus_warn ("Did not have activation result first argument to %s: %s", "StartServiceByName", error.message); goto out; } @@ -2430,7 +2465,7 @@ check_service_activated (BusContext *context, ; /* Good also */ else { - _dbus_warn ("Activation result was %u, no good.\n", + _dbus_warn ("Activation result was %u, no good.", activation_result); goto out; } @@ -2441,7 +2476,7 @@ check_service_activated (BusContext *context, if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after verifying existent activation results\n"); + _dbus_warn ("Messages were left over after verifying existent activation results"); goto out; } @@ -2493,7 +2528,7 @@ check_service_auto_activated (BusContext *context, } else { - _dbus_warn ("Message %s doesn't have a service name: %s\n", + _dbus_warn ("Message %s doesn't have a service name: %s", "NameOwnerChanged", error.message); dbus_error_free (&error); @@ -2503,7 +2538,7 @@ check_service_auto_activated (BusContext *context, if (strcmp (service_name, activated_name) != 0) { - _dbus_warn ("Expected to see service %s created, saw %s instead\n", + _dbus_warn ("Expected to see service %s created, saw %s instead", activated_name, service_name); goto out; } @@ -2725,7 +2760,7 @@ check_send_exit_to_service (BusContext *context, if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after %s\n", + _dbus_warn ("Messages were left over after %s", _DBUS_FUNCTION_NAME); goto out; } @@ -2757,7 +2792,7 @@ check_got_error (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not get an expected error\n"); + _dbus_warn ("Did not get an expected error"); goto out; } @@ -2785,7 +2820,7 @@ check_got_error (BusContext *context, if (!error_found) { - _dbus_warn ("Expected error %s or other, got %s instead\n", + _dbus_warn ("Expected error %s or other, got %s instead", first_error_name, dbus_message_get_error_name (message)); goto out; @@ -2840,7 +2875,7 @@ check_got_service_info (DBusMessage *message) } else { - _dbus_warn ("unexpected arguments for NameOwnerChanged message\n"); + _dbus_warn ("unexpected arguments for NameOwnerChanged message"); message_kind = GOT_SOMETHING_ELSE; } } @@ -2929,7 +2964,7 @@ check_existent_service_no_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after %s %d on %p\n", + _dbus_warn ("Did not receive any messages after %s %d on %p", "StartServiceByName", serial, connection); goto out; } @@ -2941,7 +2976,7 @@ check_existent_service_no_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -2963,7 +2998,7 @@ check_existent_service_no_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect error %s\n", + _dbus_warn ("Did not expect error %s", dbus_message_get_error_name (message)); goto out; } @@ -2985,7 +3020,7 @@ check_existent_service_no_auto_start (BusContext *context, message = dbus_connection_borrow_message (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after base service creation notification\n"); + _dbus_warn ("Did not receive any messages after base service creation notification"); goto out; } @@ -2997,6 +3032,7 @@ check_existent_service_no_auto_start (BusContext *context, switch (message_kind) { case GOT_SOMETHING_ELSE: + default: _dbus_warn ("Unexpected message after ActivateService " "(should be an error or a service announcement"); goto out; @@ -3056,7 +3092,7 @@ check_existent_service_no_auto_start (BusContext *context, if (message == NULL) { _dbus_warn ("Failed to pop message we just put back! " - "should have been a NameOwnerChanged (creation)\n"); + "should have been a NameOwnerChanged (creation)"); goto out; } @@ -3069,7 +3105,7 @@ check_existent_service_no_auto_start (BusContext *context, if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after successful activation\n"); + _dbus_warn ("Messages were left over after successful activation"); goto out; } @@ -3151,7 +3187,7 @@ check_segfault_service_no_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "StartServiceByName", serial, connection); goto out; } @@ -3162,7 +3198,7 @@ check_segfault_service_no_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -3203,7 +3239,7 @@ check_segfault_service_no_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully activate segfault service\n"); + _dbus_warn ("Did not expect to successfully activate segfault service"); goto out; } @@ -3260,7 +3296,7 @@ check_segfault_service_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -3271,7 +3307,7 @@ check_segfault_service_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -3304,7 +3340,7 @@ check_segfault_service_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully activate segfault service\n"); + _dbus_warn ("Did not expect to successfully activate segfault service"); goto out; } @@ -3367,13 +3403,13 @@ check_existent_hello_from_self (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Failed to pop message! Should have been reply from RunHelloFromSelf message\n"); + _dbus_warn ("Failed to pop message! Should have been reply from RunHelloFromSelf message"); return FALSE; } if (dbus_message_get_reply_serial (message) != serial) { - _dbus_warn ("Wrong reply serial\n"); + _dbus_warn ("Wrong reply serial"); dbus_message_unref (message); return FALSE; } @@ -3420,20 +3456,20 @@ check_existent_ping (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Failed to pop message! Should have been reply from Ping message\n"); + _dbus_warn ("Failed to pop message! Should have been reply from Ping message"); return FALSE; } if (dbus_message_get_reply_serial (message) != serial) { - _dbus_warn ("Wrong reply serial\n"); + _dbus_warn ("Wrong reply serial"); dbus_message_unref (message); return FALSE; } if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) { - _dbus_warn ("Unexpected message return during Ping\n"); + _dbus_warn ("Unexpected message return during Ping"); dbus_message_unref (message); return FALSE; } @@ -3451,10 +3487,21 @@ static dbus_bool_t check_existent_get_machine_id (BusContext *context, DBusConnection *connection) { + DBusError error = DBUS_ERROR_INIT; DBusMessage *message; dbus_uint32_t serial; + DBusGUID uuid; const char *machine_id; + if (!_dbus_read_local_machine_uuid (&uuid, FALSE, &error)) + { + /* Unable to test further: either we ran out of memory, or neither + * dbus nor systemd was ever correctly installed on this machine */ + _dbus_verbose ("Machine UUID not available: %s", error.message); + dbus_error_free (&error); + return TRUE; + } + message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, "/org/freedesktop/TestSuite", "org.freedesktop.DBus.Peer", @@ -3482,20 +3529,20 @@ check_existent_get_machine_id (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Failed to pop message! Should have been reply from GetMachineId message\n"); + _dbus_warn ("Failed to pop message! Should have been reply from GetMachineId message"); return FALSE; } if (dbus_message_get_reply_serial (message) != serial) { - _dbus_warn ("Wrong reply serial\n"); + _dbus_warn ("Wrong reply serial"); dbus_message_unref (message); return FALSE; } if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) { - _dbus_warn ("Unexpected message return during GetMachineId\n"); + _dbus_warn ("Unexpected message return during GetMachineId"); dbus_message_unref (message); return FALSE; } @@ -3503,14 +3550,14 @@ check_existent_get_machine_id (BusContext *context, machine_id = NULL; if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &machine_id, DBUS_TYPE_INVALID)) { - _dbus_warn ("Did not get a machine ID in reply to GetMachineId\n"); + _dbus_warn ("Did not get a machine ID in reply to GetMachineId"); dbus_message_unref (message); return FALSE; } if (machine_id == NULL || strlen (machine_id) != 32) { - _dbus_warn ("Machine id looks bogus: '%s'\n", machine_id ? machine_id : "null"); + _dbus_warn ("Machine id looks bogus: '%s'", machine_id ? machine_id : "null"); dbus_message_unref (message); return FALSE; } @@ -3586,7 +3633,7 @@ check_existent_service_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after auto start %d on %p\n", + _dbus_warn ("Did not receive any messages after auto start %d on %p", serial, connection); goto out; } @@ -3616,7 +3663,7 @@ check_existent_service_auto_start (BusContext *context, if (message == NULL) { _dbus_warn ("No message after auto activation " - "(should be a service announcement)\n"); + "(should be a service announcement)"); dbus_connection_return_message (connection, message); message = NULL; goto out; @@ -3634,7 +3681,7 @@ check_existent_service_auto_start (BusContext *context, if (message == NULL) { _dbus_warn ("Failed to pop message we just put back! " - "should have been a NameOwnerChanged (creation)\n"); + "should have been a NameOwnerChanged (creation)"); goto out; } @@ -3672,7 +3719,8 @@ check_existent_service_auto_start (BusContext *context, case GOT_ERROR: case GOT_SOMETHING_ELSE: - _dbus_warn ("Unexpected message after auto activation\n"); + default: + _dbus_warn ("Unexpected message after auto activation"); goto out; } } @@ -3689,13 +3737,13 @@ check_existent_service_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Failed to pop message! Should have been reply from echo message\n"); + _dbus_warn ("Failed to pop message! Should have been reply from echo message"); goto out; } if (dbus_message_get_reply_serial (message) != serial) { - _dbus_warn ("Wrong reply serial\n"); + _dbus_warn ("Wrong reply serial"); goto out; } @@ -3773,7 +3821,7 @@ check_launch_service_file_missing (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -3784,7 +3832,7 @@ check_launch_service_file_missing (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -3810,7 +3858,7 @@ check_launch_service_file_missing (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + _dbus_warn ("Did not expect to successfully auto-start missing service"); goto out; } @@ -3823,6 +3871,8 @@ check_launch_service_file_missing (BusContext *context, return retval; } +#ifndef DBUS_WIN + #define SERVICE_USER_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoUser" /* returns TRUE if the correct thing happens, @@ -3860,7 +3910,7 @@ check_launch_service_user_missing (BusContext *context, if (!dbus_connection_get_is_connected (connection)) { - _dbus_warn ("connection was disconnected\n"); + _dbus_warn ("connection was disconnected"); return TRUE; } @@ -3869,7 +3919,7 @@ check_launch_service_user_missing (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -3880,7 +3930,7 @@ check_launch_service_user_missing (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -3906,7 +3956,7 @@ check_launch_service_user_missing (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + _dbus_warn ("Did not expect to successfully auto-start missing service"); goto out; } @@ -3956,7 +4006,7 @@ check_launch_service_exec_missing (BusContext *context, if (!dbus_connection_get_is_connected (connection)) { - _dbus_warn ("connection was disconnected\n"); + _dbus_warn ("connection was disconnected"); return TRUE; } @@ -3965,7 +4015,7 @@ check_launch_service_exec_missing (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -3976,7 +4026,7 @@ check_launch_service_exec_missing (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -4010,7 +4060,7 @@ check_launch_service_exec_missing (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + _dbus_warn ("Did not expect to successfully auto-start missing service"); goto out; } @@ -4060,7 +4110,7 @@ check_launch_service_service_missing (BusContext *context, if (!dbus_connection_get_is_connected (connection)) { - _dbus_warn ("connection was disconnected\n"); + _dbus_warn ("connection was disconnected"); return TRUE; } @@ -4069,7 +4119,7 @@ check_launch_service_service_missing (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -4080,7 +4130,7 @@ check_launch_service_service_missing (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -4114,7 +4164,7 @@ check_launch_service_service_missing (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + _dbus_warn ("Did not expect to successfully auto-start missing service"); goto out; } @@ -4126,6 +4176,7 @@ check_launch_service_service_missing (BusContext *context, return retval; } +#endif #define SHELL_FAIL_SERVICE_NAME "org.freedesktop.DBus.TestSuiteShellEchoServiceFail" @@ -4172,7 +4223,7 @@ check_shell_fail_service_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", "Echo message (auto activation)", serial, connection); goto out; } @@ -4183,7 +4234,7 @@ check_shell_fail_service_auto_start (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -4209,7 +4260,7 @@ check_shell_fail_service_auto_start (BusContext *context, } else { - _dbus_warn ("Did not expect to successfully auto-start shell fail service\n"); + _dbus_warn ("Did not expect to successfully auto-start shell fail service"); goto out; } @@ -4276,7 +4327,7 @@ check_shell_service_success_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after auto start %d on %p\n", + _dbus_warn ("Did not receive any messages after auto start %d on %p", serial, connection); goto out; } @@ -4306,7 +4357,7 @@ check_shell_service_success_auto_start (BusContext *context, if (message == NULL) { _dbus_warn ("No message after auto activation " - "(should be a service announcement)\n"); + "(should be a service announcement)"); dbus_connection_return_message (connection, message); message = NULL; goto out; @@ -4324,7 +4375,7 @@ check_shell_service_success_auto_start (BusContext *context, if (message == NULL) { _dbus_warn ("Failed to pop message we just put back! " - "should have been a NameOwnerChanged (creation)\n"); + "should have been a NameOwnerChanged (creation)"); goto out; } @@ -4362,7 +4413,8 @@ check_shell_service_success_auto_start (BusContext *context, case GOT_ERROR: case GOT_SOMETHING_ELSE: - _dbus_warn ("Unexpected message after auto activation\n"); + default: + _dbus_warn ("Unexpected message after auto activation"); goto out; } } @@ -4379,13 +4431,13 @@ check_shell_service_success_auto_start (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Failed to pop message! Should have been reply from echo message\n"); + _dbus_warn ("Failed to pop message! Should have been reply from echo message"); goto out; } if (dbus_message_get_reply_serial (message) != serial) { - _dbus_warn ("Wrong reply serial\n"); + _dbus_warn ("Wrong reply serial"); goto out; } @@ -4399,7 +4451,7 @@ check_shell_service_success_auto_start (BusContext *context, DBUS_TYPE_STRING, &argv[6], DBUS_TYPE_INVALID)) { - _dbus_warn ("Error getting arguments from return\n"); + _dbus_warn ("Error getting arguments from return"); goto out; } @@ -4408,42 +4460,42 @@ check_shell_service_success_auto_start (BusContext *context, */ if (strcmp("-test", argv[1]) != 0) { - _dbus_warn ("Unexpected argv[1] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[1] in shell success service test (expected: %s, got: %s)", "-test", argv[1]); goto out; } if (strcmp("that", argv[2]) != 0) { - _dbus_warn ("Unexpected argv[2] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[2] in shell success service test (expected: %s, got: %s)", "that", argv[2]); goto out; } if (strcmp("we get", argv[3]) != 0) { - _dbus_warn ("Unexpected argv[3] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[3] in shell success service test (expected: %s, got: %s)", "we get", argv[3]); goto out; } if (strcmp("back", argv[4]) != 0) { - _dbus_warn ("Unexpected argv[4] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[4] in shell success service test (expected: %s, got: %s)", "back", argv[4]); goto out; } if (strcmp("--what", argv[5]) != 0) { - _dbus_warn ("Unexpected argv[5] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[5] in shell success service test (expected: %s, got: %s)", "--what", argv[5]); goto out; } if (strcmp("we put in", argv[6]) != 0) { - _dbus_warn ("Unexpected argv[6] in shell success service test (expected: %s, got: %s)\n", + _dbus_warn ("Unexpected argv[6] in shell success service test (expected: %s, got: %s)", "we put in", argv[6]); goto out; } @@ -4484,7 +4536,7 @@ check_oom_check1_func (void *data) if (!check_no_leftovers (d->context)) { - _dbus_warn ("Messages were left over, should be covered by test suite\n"); + _dbus_warn ("Messages were left over, should be covered by test suite"); return FALSE; } @@ -4561,7 +4613,7 @@ check_get_services (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive a reply to %s %d on %p\n", + _dbus_warn ("Did not receive a reply to %s %d on %p", method, serial, connection); goto out; } @@ -4613,7 +4665,7 @@ check_get_services (BusContext *context, else { _dbus_assert (dbus_error_is_set (&error)); - _dbus_warn ("Did not get the expected DBUS_TYPE_ARRAY from %s\n", method); + _dbus_warn ("Did not get the expected DBUS_TYPE_ARRAY from %s", method); goto out; } } else { @@ -4662,7 +4714,7 @@ check_list_services (BusContext *context, if (!_dbus_string_array_contains ((const char **)services, existent)) { - _dbus_warn ("Did not get the expected %s from ListActivatableNames\n", existent); + _dbus_warn ("Did not get the expected %s from ListActivatableNames", existent); dbus_free_string_array (services); return FALSE; } @@ -4720,7 +4772,7 @@ check_list_services (BusContext *context, message = pop_message_waiting_for_memory (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after %s %d on %p\n", + _dbus_warn ("Did not receive any messages after %s %d on %p", "StartServiceByName", serial, connection); goto out; } @@ -4732,7 +4784,7 @@ check_list_services (BusContext *context, { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { - _dbus_warn ("Message has wrong sender %s\n", + _dbus_warn ("Message has wrong sender %s", dbus_message_get_sender (message) ? dbus_message_get_sender (message) : "(none)"); goto out; @@ -4754,7 +4806,7 @@ check_list_services (BusContext *context, } else { - _dbus_warn ("Did not expect error %s\n", + _dbus_warn ("Did not expect error %s", dbus_message_get_error_name (message)); goto out; } @@ -4776,7 +4828,7 @@ check_list_services (BusContext *context, message = dbus_connection_borrow_message (connection); if (message == NULL) { - _dbus_warn ("Did not receive any messages after base service creation notification\n"); + _dbus_warn ("Did not receive any messages after base service creation notification"); goto out; } @@ -4790,8 +4842,9 @@ check_list_services (BusContext *context, case GOT_SOMETHING_ELSE: case GOT_ERROR: case GOT_SERVICE_DELETED: + default: _dbus_warn ("Unexpected message after ActivateService " - "(should be an error or a service announcement)\n"); + "(should be an error or a service announcement)"); goto out; case GOT_SERVICE_CREATED: @@ -4799,7 +4852,7 @@ check_list_services (BusContext *context, if (message == NULL) { _dbus_warn ("Failed to pop message we just put back! " - "should have been a NameOwnerChanged (creation)\n"); + "should have been a NameOwnerChanged (creation)"); goto out; } @@ -4812,7 +4865,7 @@ check_list_services (BusContext *context, if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after successful activation\n"); + _dbus_warn ("Messages were left over after successful activation"); goto out; } @@ -4827,7 +4880,7 @@ check_list_services (BusContext *context, if (!_dbus_string_array_contains ((const char **)services, existent)) { - _dbus_warn ("Did not get the expected %s from ListNames\n", existent); + _dbus_warn ("Did not get the expected %s from ListNames", existent); goto out; } @@ -4866,7 +4919,7 @@ check_oom_check2_func (void *data) if (!check_no_leftovers (d->context)) { - _dbus_warn ("Messages were left over, should be covered by test suite\n"); + _dbus_warn ("Messages were left over, should be covered by test suite"); return FALSE; } @@ -4888,7 +4941,7 @@ check2_try_iterations (BusContext *context, if (!_dbus_test_oom_handling (description, check_oom_check2_func, &d)) { - _dbus_warn ("%s failed during oom\n", description); + _dbus_warn ("%s failed during oom", description); _dbus_assert_not_reached ("test failed"); } } @@ -5019,7 +5072,7 @@ bus_dispatch_test_conf (const DBusString *test_data_dir, if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after setting up initial connections\n"); + _dbus_warn ("Messages were left over after setting up initial connections"); _dbus_assert_not_reached ("initial connection setup failed"); } @@ -5077,6 +5130,7 @@ bus_dispatch_test_conf (const DBusString *test_data_dir, return TRUE; } +#ifndef DBUS_WIN static dbus_bool_t bus_dispatch_test_conf_fail (const DBusString *test_data_dir, const char *filename) @@ -5133,6 +5187,7 @@ bus_dispatch_test_conf_fail (const DBusString *test_data_dir, return TRUE; } +#endif typedef struct { DBusTimeout *timeout; @@ -5316,7 +5371,7 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir) if (!check_no_leftovers (context)) { - _dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n"); + _dbus_warn ("Messages were left over after setting up initial SHA-1 connection"); _dbus_assert_not_reached ("initial connection setup failed"); } diff --git a/bus/driver.c b/bus/driver.c index d5c662cb..c468fe58 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -43,13 +43,6 @@ #include <dbus/dbus-marshal-validate.h> #include <string.h> -typedef enum -{ - BUS_DRIVER_FOUND_SELF, - BUS_DRIVER_FOUND_PEER, - BUS_DRIVER_FOUND_ERROR, -} BusDriverFound; - static inline const char * nonnull (const char *maybe_null, const char *if_null) @@ -75,7 +68,7 @@ bus_driver_get_owner_of_name (DBusConnection *connection, return bus_service_get_primary_owners_connection (serv); } -static BusDriverFound +BusDriverFound bus_driver_get_conn_helper (DBusConnection *connection, DBusMessage *message, const char *what_we_want, @@ -257,7 +250,7 @@ bus_driver_send_service_owner_changed (const char *service_name, _dbus_assert (dbus_message_has_signature (message, "sss")); - if (!bus_transaction_capture (transaction, NULL, message)) + if (!bus_transaction_capture (transaction, NULL, NULL, message)) goto oom; switch (bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error)) @@ -441,6 +434,9 @@ bus_driver_handle_hello (DBusConnection *connection, BusResult retval; BusRegistry *registry; BusConnections *connections; + DBusError tmp_error; + int limit; + const char *limit_name; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -458,11 +454,19 @@ bus_driver_handle_hello (DBusConnection *connection, * incomplete connections. It's even OK if the connection wants to * retry the hello message, we support that. */ + dbus_error_init (&tmp_error); connections = bus_connection_get_connections (connection); if (!bus_connections_check_limits (connections, connection, - error)) + &limit_name, &limit, + &tmp_error)) { - _DBUS_ASSERT_ERROR_IS_SET (error); + BusContext *context; + + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + context = bus_connection_get_context (connection); + bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s (%s=%d)", + tmp_error.message, limit_name, limit); + dbus_move_error (&tmp_error, error); return BUS_RESULT_FALSE; } @@ -983,11 +987,11 @@ bus_driver_handle_activate_service (DBusConnection *connection, return retval; } -static dbus_bool_t -send_ack_reply (DBusConnection *connection, - BusTransaction *transaction, - DBusMessage *message, - DBusError *error) +dbus_bool_t +bus_driver_send_ack_reply (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { DBusMessage *reply; @@ -1047,7 +1051,7 @@ bus_driver_send_or_activate (BusTransaction *transaction, activation = bus_context_get_activation (context); - if (!bus_transaction_capture (transaction, NULL, message)) + if (!bus_transaction_capture (transaction, NULL, NULL, message)) { BUS_SET_OOM (error); _dbus_verbose ("No memory for bus_transaction_capture()"); @@ -1100,21 +1104,6 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!bus_driver_check_message_is_for_us (message, error)) - return FALSE; - -#ifdef DBUS_UNIX - { - /* UpdateActivationEnvironment is basically a recipe for privilege - * escalation so let's be extra-careful: do not allow the sysadmin - * to shoot themselves in the foot. - */ - if (!bus_driver_check_caller_is_privileged (connection, transaction, - message, error)) - return FALSE; - } -#endif - context = bus_connection_get_context (connection); if (bus_context_get_servicehelper (context) != NULL) @@ -1298,8 +1287,7 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, } } - if (!send_ack_reply (connection, transaction, - message, error)) + if (!bus_driver_send_ack_reply (connection, transaction, message, error)) goto out; retval = BUS_RESULT_TRUE; @@ -1322,6 +1310,7 @@ bus_driver_handle_add_match (DBusConnection *connection, const char *text, *bustype; DBusString str; BusMatchmaker *matchmaker; + int limit; BusContext *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1329,15 +1318,25 @@ bus_driver_handle_add_match (DBusConnection *connection, text = NULL; rule = NULL; - if (bus_connection_get_n_match_rules (connection) >= - bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction))) + context = bus_transaction_get_context (transaction); + limit = bus_context_get_max_match_rules_per_connection (context); + + if (bus_connection_get_n_match_rules (connection) >= limit) { - dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + DBusError tmp_error; + + dbus_error_init (&tmp_error); + dbus_set_error (&tmp_error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" is not allowed to add more match rules " - "(increase limits in configuration file if required)", + "(increase limits in configuration file if required; " + "max_match_rules_per_connection=%d)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : - "(inactive)"); + "(inactive)", + limit); + bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, "%s", + tmp_error.message); + dbus_move_error (&tmp_error, error); goto failed; } @@ -1355,11 +1354,17 @@ bus_driver_handle_add_match (DBusConnection *connection, if (rule == NULL) goto failed; - context = bus_transaction_get_context (transaction); - bustype = context ? bus_context_get_type (context) : NULL; - if (bus_match_rule_get_client_is_eavesdropping (rule) && - !bus_apparmor_allows_eavesdropping (connection, bustype, error)) - goto failed; + bustype = bus_context_get_type (context); + + if (bus_match_rule_get_client_is_eavesdropping (rule)) + { + if (!bus_driver_check_caller_is_privileged (connection, + transaction, + message, + error) || + !bus_apparmor_allows_eavesdropping (connection, bustype, error)) + goto failed; + } matchmaker = bus_connection_get_matchmaker (connection); @@ -1369,8 +1374,7 @@ bus_driver_handle_add_match (DBusConnection *connection, goto failed; } - if (!send_ack_reply (connection, transaction, - message, error)) + if (!bus_driver_send_ack_reply (connection, transaction, message, error)) { bus_matchmaker_remove_rule (matchmaker, rule); goto failed; @@ -1420,8 +1424,7 @@ bus_driver_handle_remove_match (DBusConnection *connection, /* Send the ack before we remove the rule, since the ack is undone * on transaction cancel, but rule removal isn't. */ - if (!send_ack_reply (connection, transaction, - message, error)) + if (!bus_driver_send_ack_reply (connection, transaction, message, error)) goto failed; matchmaker = bus_connection_get_matchmaker (connection); @@ -1528,6 +1531,8 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, DBusMessage *message, DBusError *error) { + static const char dbus_service_name[] = DBUS_SERVICE_DBUS; + const char *text; DBusList *base_names; DBusList *link; @@ -1536,7 +1541,6 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, BusService *service; DBusMessage *reply; DBusMessageIter iter, array_iter; - char *dbus_service_name = DBUS_SERVICE_DBUS; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1557,7 +1561,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection, _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) { /* ORG_FREEDESKTOP_DBUS owns itself */ - if (! _dbus_list_append (&base_names, dbus_service_name)) + if (! _dbus_list_append (&base_names, (char *) dbus_service_name)) goto oom; } else if (service == NULL) @@ -1658,6 +1662,8 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection, uid = DBUS_UID_UNSET; break; case BUS_DRIVER_FOUND_ERROR: + /* fall through */ + default: goto failed; } @@ -1725,6 +1731,8 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, pid = DBUS_PID_UNSET; break; case BUS_DRIVER_FOUND_ERROR: + /* fall through */ + default: goto failed; } @@ -1772,7 +1780,7 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection, DBusConnection *conn; DBusMessage *reply; void *data = NULL; - dbus_uint32_t data_size; + dbus_int32_t data_size; const char *service; BusDriverFound found; @@ -1852,8 +1860,9 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne if (reply == NULL) goto oom; - /* FIXME: Obtain the SELinux security context for the bus daemon itself */ - if (found == BUS_DRIVER_FOUND_PEER) + if (found == BUS_DRIVER_FOUND_SELF) + context = bus_selinux_get_self (); + else if (found == BUS_DRIVER_FOUND_PEER) context = bus_connection_get_selinux_id (conn); else context = NULL; @@ -1922,6 +1931,8 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, ulong_uid = DBUS_UID_UNSET; break; case BUS_DRIVER_FOUND_ERROR: + /* fall through */ + default: goto failed; } @@ -2193,18 +2204,11 @@ bus_driver_handle_become_monitor (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!bus_driver_check_message_is_for_us (message, error)) - goto out; - context = bus_transaction_get_context (transaction); bustype = context ? bus_context_get_type (context) : NULL; if (!bus_apparmor_allows_eavesdropping (connection, bustype, error)) goto out; - if (!bus_driver_check_caller_is_privileged (connection, transaction, - message, error)) - goto out; - if (!dbus_message_get_args (message, error, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &match_rules, &n_match_rules, DBUS_TYPE_UINT32, &flags, @@ -2263,7 +2267,7 @@ bus_driver_handle_become_monitor (DBusConnection *connection, /* Send the ack before we remove the rule, since the ack is undone * on transaction cancel, but becoming a monitor isn't. */ - if (!send_ack_reply (connection, transaction, message, error)) + if (!bus_driver_send_ack_reply (connection, transaction, message, error)) goto out; if (!bus_connection_be_monitor (connection, transaction, &rules, error)) @@ -2288,6 +2292,109 @@ out: return ret; } +static dbus_bool_t +bus_driver_handle_get_machine_id (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply = NULL; + DBusString uuid; + const char *str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&uuid)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_get_local_machine_uuid_encoded (&uuid, error)) + goto fail; + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) + goto oom; + + str = _dbus_string_get_const_data (&uuid); + + if (!dbus_message_append_args (reply, + DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID)) + goto oom; + + _dbus_assert (dbus_message_has_signature (reply, "s")); + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + _dbus_string_free (&uuid); + dbus_message_unref (reply); + return TRUE; + +oom: + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + BUS_SET_OOM (error); + +fail: + _DBUS_ASSERT_ERROR_IS_SET (error); + + if (reply != NULL) + dbus_message_unref (reply); + + _dbus_string_free (&uuid); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_ping (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + return bus_driver_send_ack_reply (connection, transaction, message, error); +} + +static dbus_bool_t bus_driver_handle_get (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); + +static dbus_bool_t bus_driver_handle_get_all (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); + +static dbus_bool_t bus_driver_handle_set (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); + +static dbus_bool_t features_getter (BusContext *context, + DBusMessageIter *variant_iter); +static dbus_bool_t interfaces_getter (BusContext *context, + DBusMessageIter *variant_iter); + +typedef enum +{ + /* Various older methods were available at every object path. We have to + * preserve that behaviour for backwards compatibility, but we can at least + * stop doing that for newly added methods. + * The special Peer interface should also work at any object path. + * <https://bugs.freedesktop.org/show_bug.cgi?id=101256> */ + METHOD_FLAG_ANY_PATH = (1 << 0), + + /* If set, callers must be privileged. On Unix, the uid of the connection + * must either be the uid of this process, or 0 (root). On Windows, + * the SID of the connection must be the SID of this process. */ + METHOD_FLAG_PRIVILEGED = (1 << 1), + + METHOD_FLAG_NONE = 0 +} MethodFlags; + typedef struct { const char *name; @@ -2297,8 +2404,17 @@ typedef struct BusTransaction *transaction, DBusMessage *message, DBusError *error); + MethodFlags flags; } MessageHandler; +typedef struct +{ + const char *name; + const char *type; + dbus_bool_t (* getter) (BusContext *context, + DBusMessageIter *variant_iter); +} PropertyHandler; + /* For speed it might be useful to sort this in order of * frequency of use (but doesn't matter with only a few items * anyhow) @@ -2307,114 +2423,178 @@ static const MessageHandler dbus_message_handlers[] = { { "Hello", "", DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_hello }, + bus_driver_handle_hello, + METHOD_FLAG_ANY_PATH }, { "RequestName", DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING, - bus_driver_handle_acquire_service }, + bus_driver_handle_acquire_service, + METHOD_FLAG_ANY_PATH }, { "ReleaseName", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_UINT32_AS_STRING, - bus_driver_handle_release_service }, + bus_driver_handle_release_service, + METHOD_FLAG_ANY_PATH }, { "StartServiceByName", DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING, - bus_driver_handle_activate_service }, + bus_driver_handle_activate_service, + METHOD_FLAG_ANY_PATH }, { "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 }, + bus_driver_handle_update_activation_environment, + METHOD_FLAG_PRIVILEGED }, { "NameHasOwner", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_BOOLEAN_AS_STRING, - bus_driver_handle_service_exists }, + bus_driver_handle_service_exists, + METHOD_FLAG_ANY_PATH }, { "ListNames", "", DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_list_services }, + bus_driver_handle_list_services, + METHOD_FLAG_ANY_PATH }, { "ListActivatableNames", "", DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_list_activatable_services }, + bus_driver_handle_list_activatable_services, + METHOD_FLAG_ANY_PATH }, { "AddMatch", DBUS_TYPE_STRING_AS_STRING, "", - bus_driver_handle_add_match }, + bus_driver_handle_add_match, + METHOD_FLAG_ANY_PATH }, { "RemoveMatch", DBUS_TYPE_STRING_AS_STRING, "", - bus_driver_handle_remove_match }, + bus_driver_handle_remove_match, + METHOD_FLAG_ANY_PATH }, { "GetNameOwner", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_get_service_owner }, + bus_driver_handle_get_service_owner, + METHOD_FLAG_ANY_PATH }, { "ListQueuedOwners", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_list_queued_owners }, + bus_driver_handle_list_queued_owners, + METHOD_FLAG_ANY_PATH }, { "GetConnectionUnixUser", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_UINT32_AS_STRING, - bus_driver_handle_get_connection_unix_user }, + bus_driver_handle_get_connection_unix_user, + METHOD_FLAG_ANY_PATH }, { "GetConnectionUnixProcessID", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_UINT32_AS_STRING, - bus_driver_handle_get_connection_unix_process_id }, + bus_driver_handle_get_connection_unix_process_id, + METHOD_FLAG_ANY_PATH }, { "GetAdtAuditSessionData", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, - bus_driver_handle_get_adt_audit_session_data }, + bus_driver_handle_get_adt_audit_session_data, + METHOD_FLAG_ANY_PATH }, { "GetConnectionSELinuxSecurityContext", DBUS_TYPE_STRING_AS_STRING, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, - bus_driver_handle_get_connection_selinux_security_context }, + bus_driver_handle_get_connection_selinux_security_context, + METHOD_FLAG_ANY_PATH }, { "ReloadConfig", "", "", - bus_driver_handle_reload_config }, + bus_driver_handle_reload_config, + METHOD_FLAG_ANY_PATH }, { "GetId", "", DBUS_TYPE_STRING_AS_STRING, - bus_driver_handle_get_id }, + bus_driver_handle_get_id, + METHOD_FLAG_ANY_PATH }, { "GetConnectionCredentials", "s", "a{sv}", - bus_driver_handle_get_connection_credentials }, + bus_driver_handle_get_connection_credentials, + METHOD_FLAG_ANY_PATH }, { NULL, NULL, NULL, NULL } }; +static const PropertyHandler dbus_property_handlers[] = { + { "Features", "as", features_getter }, + { "Interfaces", "as", interfaces_getter }, + { NULL, NULL, NULL } +}; + static BusResult bus_driver_handle_introspect (DBusConnection *, BusTransaction *, DBusMessage *, DBusError *); +static const MessageHandler properties_message_handlers[] = { + { "Get", "ss", "v", bus_driver_handle_get, METHOD_FLAG_NONE }, + { "GetAll", "s", "a{sv}", bus_driver_handle_get_all, METHOD_FLAG_NONE }, + { "Set", "ssv", "", bus_driver_handle_set, METHOD_FLAG_NONE }, + { NULL, NULL, NULL, NULL } +}; + static const MessageHandler introspectable_message_handlers[] = { - { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect }, + { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect, + METHOD_FLAG_ANY_PATH }, { NULL, NULL, NULL, NULL } }; static const MessageHandler monitoring_message_handlers[] = { - { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor }, + { "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor, + METHOD_FLAG_PRIVILEGED }, { NULL, NULL, NULL, NULL } }; #ifdef DBUS_ENABLE_VERBOSE_MODE static const MessageHandler verbose_message_handlers[] = { - { "EnableVerbose", "", "", bus_driver_handle_enable_verbose}, - { "DisableVerbose", "", "", bus_driver_handle_disable_verbose}, + { "EnableVerbose", "", "", bus_driver_handle_enable_verbose, + METHOD_FLAG_NONE }, + { "DisableVerbose", "", "", bus_driver_handle_disable_verbose, + METHOD_FLAG_NONE }, { NULL, NULL, NULL, NULL } }; #endif #ifdef DBUS_ENABLE_STATS static const MessageHandler stats_message_handlers[] = { - { "GetStats", "", "a{sv}", bus_stats_handle_get_stats }, - { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats }, - { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules }, + { "GetStats", "", "a{sv}", bus_stats_handle_get_stats, + METHOD_FLAG_NONE }, + { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats, + METHOD_FLAG_NONE }, + { "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules, + METHOD_FLAG_NONE }, { NULL, NULL, NULL, NULL } }; #endif +static const MessageHandler peer_message_handlers[] = { + { "GetMachineId", "", "s", bus_driver_handle_get_machine_id, + METHOD_FLAG_ANY_PATH }, + { "Ping", "", "", bus_driver_handle_ping, METHOD_FLAG_ANY_PATH }, + { NULL, NULL, NULL, NULL } +}; + +typedef enum +{ + /* Various older interfaces were available at every object path. We have to + * preserve that behaviour for backwards compatibility, but we can at least + * stop doing that for newly added interfaces: + * <https://bugs.freedesktop.org/show_bug.cgi?id=101256> + * Introspectable and Peer are also useful at all object paths. */ + INTERFACE_FLAG_ANY_PATH = (1 << 0), + + /* Set this flag for interfaces that should not show up in the + * Interfaces property. */ + INTERFACE_FLAG_UNINTERESTING = (1 << 1), + + INTERFACE_FLAG_NONE = 0 +} InterfaceFlags; + typedef struct { const char *name; const MessageHandler *message_handlers; const char *extra_introspection; + InterfaceFlags flags; + const PropertyHandler *property_handlers; } InterfaceHandler; /* These should ideally be sorted by frequency of use, although it @@ -2431,15 +2611,42 @@ static InterfaceHandler interface_handlers[] = { " </signal>\n" " <signal name=\"NameAcquired\">\n" " <arg type=\"s\"/>\n" - " </signal>\n" }, - { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL }, - { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL }, + " </signal>\n", + /* Not in the Interfaces property because if you can get the properties + * of the o.fd.DBus interface, then you certainly have the o.fd.DBus + * interface, so there is little point in listing it explicitly. + * Partially available at all paths for backwards compatibility. */ + INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING, + dbus_property_handlers }, + { DBUS_INTERFACE_PROPERTIES, properties_message_handlers, + " <signal name=\"PropertiesChanged\">\n" + " <arg type=\"s\" name=\"interface_name\"/>\n" + " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" + " <arg type=\"as\" name=\"invalidated_properties\"/>\n" + " </signal>\n", + /* Not in the Interfaces property because if you can get the properties + * of the o.fd.DBus interface, then you certainly have Properties. */ + INTERFACE_FLAG_UNINTERESTING }, + { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL, + /* Not in the Interfaces property because introspection isn't really a + * feature in the same way as e.g. Monitoring. + * Available at all paths so tools like d-feet can start from "/". */ + INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING }, + { DBUS_INTERFACE_MONITORING, monitoring_message_handlers, NULL, + INTERFACE_FLAG_NONE }, #ifdef DBUS_ENABLE_VERBOSE_MODE - { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL }, + { DBUS_INTERFACE_VERBOSE, verbose_message_handlers, NULL, + INTERFACE_FLAG_NONE }, #endif #ifdef DBUS_ENABLE_STATS - { BUS_INTERFACE_STATS, stats_message_handlers, NULL }, + { BUS_INTERFACE_STATS, stats_message_handlers, NULL, + INTERFACE_FLAG_NONE }, #endif + { DBUS_INTERFACE_PEER, peer_message_handlers, NULL, + /* Not in the Interfaces property because it's a pseudo-interface + * on all object paths of all connections, rather than a feature of the + * bus driver object. */ + INTERFACE_FLAG_ANY_PATH | INTERFACE_FLAG_UNINTERESTING }, { NULL, NULL, NULL } }; @@ -2479,10 +2686,13 @@ write_args_for_direction (DBusString *xml, } dbus_bool_t -bus_driver_generate_introspect_string (DBusString *xml) +bus_driver_generate_introspect_string (DBusString *xml, + dbus_bool_t is_canonical_path, + DBusMessage *message) { const InterfaceHandler *ih; const MessageHandler *mh; + const PropertyHandler *ph; if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) return FALSE; @@ -2491,6 +2701,9 @@ bus_driver_generate_introspect_string (DBusString *xml) for (ih = interface_handlers; ih->name != NULL; ih++) { + if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH))) + continue; + if (!_dbus_string_append_printf (xml, " <interface name=\"%s\">\n", ih->name)) return FALSE; @@ -2511,6 +2724,20 @@ bus_driver_generate_introspect_string (DBusString *xml) return FALSE; } + for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++) + { + /* We only have constant properties so far, so hard-code that bit */ + if (!_dbus_string_append_printf (xml, + " <property name=\"%s\" type=\"%s\" access=\"read\">\n", + ph->name, ph->type)) + return FALSE; + + if (!_dbus_string_append (xml, + " <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n" + " </property>\n")) + return FALSE; + } + if (ih->extra_introspection != NULL && !_dbus_string_append (xml, ih->extra_introspection)) return FALSE; @@ -2519,6 +2746,28 @@ bus_driver_generate_introspect_string (DBusString *xml) return FALSE; } + if (message != NULL) + { + /* Make the bus driver object path discoverable */ + if (dbus_message_has_path (message, "/")) + { + if (!_dbus_string_append (xml, + " <node name=\"org/freedesktop/DBus\"/>\n")) + return FALSE; + } + else if (dbus_message_has_path (message, "/org")) + { + if (!_dbus_string_append (xml, + " <node name=\"freedesktop/DBus\"/>\n")) + return FALSE; + } + else if (dbus_message_has_path (message, "/org/freedesktop")) + { + if (!_dbus_string_append (xml, " <node name=\"DBus\"/>\n")) + return FALSE; + } + } + if (!_dbus_string_append (xml, "</node>\n")) return FALSE; @@ -2534,6 +2783,7 @@ bus_driver_handle_introspect (DBusConnection *connection, DBusString xml; DBusMessage *reply; const char *v_STRING; + dbus_bool_t is_canonical_path; _dbus_verbose ("Introspect() on bus driver\n"); @@ -2554,7 +2804,9 @@ bus_driver_handle_introspect (DBusConnection *connection, return BUS_RESULT_FALSE; } - if (!bus_driver_generate_introspect_string (&xml)) + is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS); + + if (!bus_driver_generate_introspect_string (&xml, is_canonical_path, message)) goto oom; v_STRING = _dbus_string_get_const_data (&xml); @@ -2587,38 +2839,6 @@ bus_driver_handle_introspect (DBusConnection *connection, return BUS_RESULT_FALSE; } -/* - * Set @error and return FALSE if the message is not directed to the - * dbus-daemon by its canonical object path. This is hardening against - * system services with poorly-written security policy files, which - * might allow sending dangerously broad equivalence classes of messages - * such as "anything with this assumed-to-be-safe object path". - * - * dbus-daemon is unusual in that it normally ignores the object path - * of incoming messages; we need to keep that behaviour for the "read" - * read-only method calls like GetConnectionUnixUser for backwards - * compatibility, but it seems safer to be more restrictive for things - * intended to be root-only or privileged-developers-only. - * - * It is possible that there are other system services with the same - * quirk as dbus-daemon. - */ -dbus_bool_t -bus_driver_check_message_is_for_us (DBusMessage *message, - DBusError *error) -{ - if (!dbus_message_has_path (message, DBUS_PATH_DBUS)) - { - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, - "Method '%s' is only available at the canonical object path '%s'", - dbus_message_get_member (message), DBUS_PATH_DBUS); - - return FALSE; - } - - return TRUE; -} - BusResult bus_driver_handle_message (DBusConnection *connection, BusTransaction *transaction, @@ -2629,6 +2849,7 @@ bus_driver_handle_message (DBusConnection *connection, const InterfaceHandler *ih; const MessageHandler *mh; dbus_bool_t found_interface = FALSE; + dbus_bool_t is_canonical_path; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -2637,6 +2858,15 @@ bus_driver_handle_message (DBusConnection *connection, BusContext *context; DBusConnection *systemd; + /* This is a directed signal, not a method call, so the log message + * is a little weird (it talks about "calling" ActivationFailure), + * but it's close enough */ + if (!bus_driver_check_caller_is_privileged (connection, + transaction, + message, + error)) + return BUS_RESULT_FALSE; + context = bus_connection_get_context (connection); systemd = bus_driver_get_owner_of_name (connection, "org.freedesktop.systemd1"); @@ -2655,6 +2885,14 @@ bus_driver_handle_message (DBusConnection *connection, return BUS_RESULT_TRUE; } + if (!bus_context_get_systemd_activation (context)) + { + bus_context_log (context, DBUS_SYSTEM_LOG_WARNING, + "Ignoring unexpected ActivationFailure message " + "while not using systemd activation"); + return BUS_RESULT_FALSE; + } + return dbus_activation_systemd_failure(bus_context_get_activation(context), message) == TRUE ? BUS_RESULT_TRUE : BUS_RESULT_FALSE; } @@ -2677,8 +2915,13 @@ bus_driver_handle_message (DBusConnection *connection, _dbus_assert (dbus_message_get_sender (message) != NULL || strcmp (name, "Hello") == 0); + is_canonical_path = dbus_message_has_path (message, DBUS_PATH_DBUS); + for (ih = interface_handlers; ih->name != NULL; ih++) { + if (!(is_canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH))) + continue; + if (interface != NULL && strcmp (interface, ih->name) != 0) continue; @@ -2691,6 +2934,24 @@ bus_driver_handle_message (DBusConnection *connection, _dbus_verbose ("Found driver handler for %s\n", name); + if ((mh->flags & METHOD_FLAG_PRIVILEGED) && + !bus_driver_check_caller_is_privileged (connection, transaction, + message, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return BUS_RESULT_FALSE; + } + + if (!(is_canonical_path || (mh->flags & METHOD_FLAG_ANY_PATH))) + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Method '%s' is only available at the canonical object path '%s'", + dbus_message_get_member (message), DBUS_PATH_DBUS); + _DBUS_ASSERT_ERROR_IS_SET (error); + return BUS_RESULT_FALSE; + } + if (!dbus_message_has_signature (message, mh->in_args)) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -2741,3 +3002,298 @@ bus_driver_remove_connection (DBusConnection *connection) * with the bus driver. */ } + +static dbus_bool_t +features_getter (BusContext *context, + DBusMessageIter *variant_iter) +{ + DBusMessageIter arr_iter; + + if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &arr_iter)) + return FALSE; + + if (bus_apparmor_enabled ()) + { + const char *s = "AppArmor"; + + if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s)) + goto abandon; + } + + if (bus_selinux_enabled ()) + { + const char *s = "SELinux"; + + if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s)) + goto abandon; + } + + if (bus_context_get_systemd_activation (context)) + { + const char *s = "SystemdActivation"; + + if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, &s)) + goto abandon; + } + + return dbus_message_iter_close_container (variant_iter, &arr_iter); + +abandon: + dbus_message_iter_abandon_container (variant_iter, &arr_iter); + return FALSE; +} + +static dbus_bool_t +interfaces_getter (BusContext *context, + DBusMessageIter *variant_iter) +{ + DBusMessageIter arr_iter; + const InterfaceHandler *ih; + + if (!dbus_message_iter_open_container (variant_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &arr_iter)) + return FALSE; + + for (ih = interface_handlers; ih->name != NULL; ih++) + { + if (ih->flags & INTERFACE_FLAG_UNINTERESTING) + continue; + + if (!dbus_message_iter_append_basic (&arr_iter, DBUS_TYPE_STRING, + &ih->name)) + goto abandon; + } + + return dbus_message_iter_close_container (variant_iter, &arr_iter); + +abandon: + dbus_message_iter_abandon_container (variant_iter, &arr_iter); + return FALSE; +} + +static const InterfaceHandler * +bus_driver_find_interface (const char *name, + dbus_bool_t canonical_path, + DBusError *error) +{ + const InterfaceHandler *ih; + + for (ih = interface_handlers; ih->name != NULL; ih++) + { + if (!(canonical_path || (ih->flags & INTERFACE_FLAG_ANY_PATH))) + continue; + + if (strcmp (name, ih->name) == 0) + return ih; + } + + dbus_set_error (error, DBUS_ERROR_UNKNOWN_INTERFACE, + "Interface \"%s\" not found", name); + return NULL; +} + +static const PropertyHandler * +interface_handler_find_property (const InterfaceHandler *ih, + const char *name, + DBusError *error) +{ + const PropertyHandler *ph; + + for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++) + { + if (strcmp (name, ph->name) == 0) + return ph; + } + + dbus_set_error (error, DBUS_ERROR_UNKNOWN_PROPERTY, + "Property \"%s.%s\" not found", ih->name, name); + return NULL; +} + +static dbus_bool_t +bus_driver_handle_get (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const InterfaceHandler *ih; + const PropertyHandler *handler; + const char *iface; + const char *prop; + BusContext *context; + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter var_iter; + + /* The message signature has already been checked for us, + * so this should always succeed. */ + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &iface, + DBUS_TYPE_STRING, &prop, + DBUS_TYPE_INVALID)) + return FALSE; + + /* We only implement Properties on /org/freedesktop/DBus so far. */ + ih = bus_driver_find_interface (iface, TRUE, error); + + if (ih == NULL) + return FALSE; + + handler = interface_handler_find_property (ih, prop, error); + + if (handler == NULL) + return FALSE; + + context = bus_transaction_get_context (transaction); + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) + goto oom; + + dbus_message_iter_init_append (reply, &iter); + + if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, + handler->type, &var_iter)) + goto oom; + + if (!handler->getter (context, &var_iter)) + { + dbus_message_iter_abandon_container (&iter, &var_iter); + goto oom; + } + + if (!dbus_message_iter_close_container (&iter, &var_iter)) + goto oom; + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + return TRUE; + +oom: + if (reply != NULL) + dbus_message_unref (reply); + + BUS_SET_OOM (error); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_all (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const InterfaceHandler *ih; + const char *iface; + const PropertyHandler *ph; + DBusMessageIter reply_iter; + DBusMessageIter array_iter; + BusContext *context; + DBusMessage *reply = NULL; + + /* The message signature has already been checked for us, + * so this should always succeed. */ + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &iface, + DBUS_TYPE_INVALID)) + return FALSE; + + /* We only implement Properties on /org/freedesktop/DBus so far. */ + ih = bus_driver_find_interface (iface, TRUE, error); + + if (ih == NULL) + return FALSE; + + context = bus_transaction_get_context (transaction); + + reply = _dbus_asv_new_method_return (message, &reply_iter, &array_iter); + + if (reply == NULL) + goto oom; + + for (ph = ih->property_handlers; ph != NULL && ph->name != NULL; ph++) + { + DBusMessageIter entry_iter; + DBusMessageIter var_iter; + + if (!_dbus_asv_open_entry (&array_iter, &entry_iter, ph->name, + ph->type, &var_iter)) + goto oom_abandon_message; + + if (!ph->getter (context, &var_iter)) + { + _dbus_asv_abandon_entry (&array_iter, &entry_iter, &var_iter); + goto oom_abandon_message; + } + + if (!_dbus_asv_close_entry (&array_iter, &entry_iter, &var_iter)) + goto oom_abandon_message; + } + + if (!_dbus_asv_close (&reply_iter, &array_iter)) + goto oom; + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + return TRUE; + +oom_abandon_message: + _dbus_asv_abandon (&reply_iter, &array_iter); + /* fall through */ +oom: + if (reply != NULL) + dbus_message_unref (reply); + + BUS_SET_OOM (error); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_set (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const InterfaceHandler *ih; + const char *iface; + const char *prop; + const PropertyHandler *handler; + DBusMessageIter iter; + + /* We already checked this in bus_driver_handle_message() */ + _dbus_assert (dbus_message_has_signature (message, "ssv")); + + if (!dbus_message_iter_init (message, &iter)) + _dbus_assert_not_reached ("Message type was already checked to be 'ssv'"); + + dbus_message_iter_get_basic (&iter, &iface); + + if (!dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Message type was already checked to be 'ssv'"); + + dbus_message_iter_get_basic (&iter, &prop); + + /* We only implement Properties on /org/freedesktop/DBus so far. */ + ih = bus_driver_find_interface (iface, TRUE, error); + + if (ih == NULL) + return FALSE; + + handler = interface_handler_find_property (ih, prop, error); + + if (handler == NULL) + return FALSE; + + /* We don't implement any properties that can be set yet. */ + dbus_set_error (error, DBUS_ERROR_PROPERTY_READ_ONLY, + "Property '%s.%s' cannot be set", iface, prop); + return FALSE; +} diff --git a/bus/driver.h b/bus/driver.h index 3ff4ff15..183c28b9 100644 --- a/bus/driver.h +++ b/bus/driver.h @@ -27,6 +27,13 @@ #include <dbus/dbus.h> #include "connection.h" +typedef enum +{ + BUS_DRIVER_FOUND_SELF, + BUS_DRIVER_FOUND_PEER, + BUS_DRIVER_FOUND_ERROR, +} BusDriverFound; + void bus_driver_remove_connection (DBusConnection *connection); BusResult bus_driver_handle_message (DBusConnection *connection, BusTransaction *transaction, @@ -45,8 +52,19 @@ dbus_bool_t bus_driver_send_service_owner_changed (const char *service_name const char *new_owner, BusTransaction *transaction, DBusError *error); -dbus_bool_t bus_driver_generate_introspect_string (DBusString *xml); -dbus_bool_t bus_driver_check_message_is_for_us (DBusMessage *message, - DBusError *error); +dbus_bool_t bus_driver_generate_introspect_string (DBusString *xml, + dbus_bool_t canonical_path, + DBusMessage *message); + +BusDriverFound bus_driver_get_conn_helper (DBusConnection *connection, + DBusMessage *message, + const char *what_we_want, + const char **name_p, + DBusConnection **peer_conn_p, + DBusError *error); +dbus_bool_t bus_driver_send_ack_reply (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); #endif /* BUS_DRIVER_H */ @@ -45,6 +45,9 @@ #ifdef HAVE_SYSTEMD #include <systemd/sd-daemon.h> #endif +#ifdef DBUS_UNIX +#include <dbus/dbus-sysdeps-unix.h> +#endif static BusContext *context; @@ -67,6 +70,10 @@ typedef enum static void signal_handler (int sig) { + /* Signal handlers that might set errno must save and restore the errno + * that the interrupted function might have been relying on. */ + int saved_errno = errno; + switch (sig) { case SIGHUP: @@ -128,10 +135,19 @@ signal_handler (int sig) } } break; + + default: + /* can't happen unless this signal handler gets used for a wrong + * signal, but keep -Wswitch-default happy */ + break; } + + errno = saved_errno; } #endif /* DBUS_UNIX */ +static void usage (void) _DBUS_GNUC_NORETURN; + static void usage (void) { @@ -146,6 +162,9 @@ usage (void) " [--introspect]" " [--address=ADDRESS]" " [--nopidfile]" + " [--nosyslog]" + " [--syslog]" + " [--syslog-only]" " [--nofork]" #ifdef DBUS_UNIX " [--fork]" @@ -155,6 +174,8 @@ usage (void) exit (1); } +static void version (void) _DBUS_GNUC_NORETURN; + static void version (void) { @@ -166,6 +187,8 @@ version (void) exit (0); } +static void introspect (void) _DBUS_GNUC_NORETURN; + static void introspect (void) { @@ -175,7 +198,7 @@ introspect (void) if (!_dbus_string_init (&xml)) goto oom; - if (!bus_driver_generate_introspect_string (&xml)) + if (!bus_driver_generate_introspect_string (&xml, TRUE, NULL)) { _dbus_string_free (&xml); goto oom; @@ -187,7 +210,7 @@ introspect (void) exit (0); oom: - _dbus_warn ("Can not introspect - Out of memory\n"); + _dbus_warn ("Can not introspect - Out of memory"); exit (1); } @@ -256,7 +279,7 @@ handle_reload_watch (DBusWatch *watch, if ((reload_pipe[RELOAD_READ_END].fd > 0) && _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1) { - _dbus_warn ("Couldn't read from reload pipe.\n"); + _dbus_warn ("Couldn't read from reload pipe."); close_reload_pipe (&watch); return TRUE; } @@ -282,7 +305,7 @@ handle_reload_watch (DBusWatch *watch, _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) || dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)); - _dbus_warn ("Unable to reload configuration: %s\n", + _dbus_warn ("Unable to reload configuration: %s", error.message); dbus_error_free (&error); } @@ -323,7 +346,7 @@ setup_reload_pipe (DBusLoop *loop) if (!_dbus_socketpair (&reload_pipe[0], &reload_pipe[1], TRUE, &error)) { - _dbus_warn ("Unable to create reload pipe: %s\n", + _dbus_warn ("Unable to create reload pipe: %s", error.message); dbus_error_free (&error); exit (1); @@ -335,7 +358,7 @@ setup_reload_pipe (DBusLoop *loop) if (watch == NULL) { - _dbus_warn ("Unable to create reload watch: %s\n", + _dbus_warn ("Unable to create reload watch: %s", error.message); dbus_error_free (&error); exit (1); @@ -343,7 +366,7 @@ setup_reload_pipe (DBusLoop *loop) if (!_dbus_loop_add_watch (loop, watch)) { - _dbus_warn ("Unable to add reload watch to main loop: %s\n", + _dbus_warn ("Unable to add reload watch to main loop: %s", error.message); dbus_error_free (&error); exit (1); @@ -382,6 +405,27 @@ main (int argc, char **argv) dbus_bool_t print_address; dbus_bool_t print_pid; BusContextFlags flags; +#ifdef DBUS_UNIX + const char *error_str; + + /* Redirect stdin from /dev/null since we will never need it, and + * redirect stdout and stderr to /dev/null if not already open. + * + * We should do this as the very first thing, to ensure that when we + * create other file descriptors (for example for epoll, inotify or + * a socket), they never get assigned as fd 0, 1 or 2. If they were, + * which could happen if our caller had (incorrectly) closed those + * standard fds, they'd get closed when we daemonize - for example, + * closing our listening socket would stop us listening, and closing + * a Linux epoll socket would cause the main loop to fail. */ + if (!_dbus_ensure_standard_fds (DBUS_FORCE_STDIN_NULL, &error_str)) + { + fprintf (stderr, + "dbus-daemon: fatal error setting up standard fds: %s: %s\n", + error_str, _dbus_strerror (errno)); + return 1; + } +#endif if (!_dbus_string_init (&config_file)) return 1; @@ -420,6 +464,21 @@ main (int argc, char **argv) { introspect (); } + else if (strcmp (arg, "--nosyslog") == 0) + { + flags &= ~BUS_CONTEXT_FLAG_SYSLOG_ALWAYS; + flags |= BUS_CONTEXT_FLAG_SYSLOG_NEVER; + } + else if (strcmp (arg, "--syslog") == 0) + { + flags &= ~BUS_CONTEXT_FLAG_SYSLOG_NEVER; + flags |= BUS_CONTEXT_FLAG_SYSLOG_ALWAYS; + } + else if (strcmp (arg, "--syslog-only") == 0) + { + flags &= ~BUS_CONTEXT_FLAG_SYSLOG_NEVER; + flags |= (BUS_CONTEXT_FLAG_SYSLOG_ALWAYS|BUS_CONTEXT_FLAG_SYSLOG_ONLY); + } else if (strcmp (arg, "--nofork") == 0) { flags &= ~BUS_CONTEXT_FLAG_FORK_ALWAYS; @@ -444,14 +503,14 @@ main (int argc, char **argv) { check_two_config_files (&config_file, "system"); - if (!_dbus_append_system_config_file (&config_file)) + if (!_dbus_get_system_config_file (&config_file)) exit (1); } else if (strcmp (arg, "--session") == 0) { check_two_config_files (&config_file, "session"); - if (!_dbus_append_session_config_file (&config_file)) + if (!_dbus_get_session_config_file (&config_file)) exit (1); } else if (strstr (arg, "--config-file=") == arg) @@ -620,13 +679,13 @@ main (int argc, char **argv) if (!bus_selinux_pre_init ()) { - _dbus_warn ("SELinux pre-initialization failed\n"); + _dbus_warn ("SELinux pre-initialization failed"); exit (1); } if (!bus_apparmor_pre_init ()) { - _dbus_warn ("AppArmor pre-initialization failed: out of memory\n"); + _dbus_warn ("AppArmor pre-initialization failed: out of memory"); exit (1); } @@ -636,9 +695,10 @@ main (int argc, char **argv) _dbus_string_get_length(&address) > 0 ? &address : NULL, &error); _dbus_string_free (&config_file); + _dbus_string_free (&address); if (context == NULL) { - _dbus_warn ("Failed to start message bus: %s\n", + _dbus_warn ("Failed to start message bus: %s", error.message); dbus_error_free (&error); exit (1); diff --git a/bus/messagebus-config.in b/bus/messagebus-config.in deleted file mode 100644 index 39459dcb..00000000 --- a/bus/messagebus-config.in +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/sh -# -# messagebus-config, Copyright 2009 Yaakov Selkowitz -# -# This file is part of the Cygwin port of dbus. - -# ====================================================================== -# Initialization -# ====================================================================== -PROGNAME=$(basename $0) -_tdir=$(dirname $0) -PROGDIR=$(cd $_tdir && pwd) - -CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh - -# Subdirectory where the new package is being installed -PREFIX=@prefix@ - -# Directory where the config files are stored -SYSCONFDIR=@sysconfdir@/dbus-1 -DEVDIR=/dev -LOGDIR=/var/log -RUNDIR=$(dirname @DBUS_SYSTEM_PID_FILE@) -SOCKDIR=$(dirname @DBUS_SYSTEM_SOCKET@) - -source ${CSIH_SCRIPT} - -# ====================================================================== -# Routine: install_service -# Install messagebus as a service -# ====================================================================== -install_service() { - - if csih_is_nt - then - - # Check if messagebus is installed and remove on user request. - if cygrunsrv -Q messagebus > /dev/null 2>&1 - then - csih_warning "The messagebus service is already installed." - echo - if csih_request "Do you want to reinstall it with different args?" - then - cygrunsrv -E messagebus - cygrunsrv -R messagebus - fi - fi - - # Install messagebus service if it is not already installed - if ! cygrunsrv -Q messagebus > /dev/null 2>&1 - then - echo - csih_warning "The following function requires administrator privileges!" - if csih_request "Do you want to install messagebus as service?" - then - if cygrunsrv -I messagebus -d "CYGWIN D-Bus system service" -p @EXPANDED_BINDIR@/dbus-daemon -a "--nofork --system" - then - echo - csih_inform "The messagebus service has been installed under the LocalSystem" - csih_inform "account (also known as SYSTEM). To start the service now, call" - csih_inform "\`net start messagebus' or \`cygrunsrv -S messagebus'. Otherwise, it" - csih_inform "will start automatically after the next reboot." - echo - csih_inform "Check ${SYSCONFDIR}/system.conf first, if it suits your needs." - fi - fi # user allowed us to install messagebus - fi # messagebus already installed - fi # csih_is_nt -} # --- End of install_service --- # - - -# ====================================================================== -# Main Entry Point -# ====================================================================== - - -# Check how the script has been started. If -# (1) it has been started by giving the full path and -# that path is /etc/postinstall, OR -# (2) Otherwise, if the environment variable -# CONFIG_AUTO_ANSWER_NO is set -# then set auto_answer to "no". This allows automatic -# creation of the config files in /etc w/o overwriting -# them if they already exist. In both cases, color -# escape sequences are suppressed, so as to prevent -# cluttering setup's logfiles. -if [ "$PROGDIR" = "/etc/postinstall" ] -then - csih_auto_answer="no" - csih_disable_color -fi -if [ -n "${CONFIG_AUTO_ANSWER_NO}" ] -then - csih_auto_answer="no" - csih_disable_color -fi - - -# ====================================================================== -# Parse options -# ====================================================================== -while : -do - case $# in - 0) - break - ;; - esac - - option=$1 - shift - - case "$option" in - -d | --debug ) - set -x - csih_trace_on - ;; - - -y | --yes ) - csih_auto_answer=yes - ;; - - -n | --no ) - csih_auto_answer=no - ;; - - *) - echo "usage: ${PROGNAME} [OPTION]..." - echo - echo "This script creates a basic messagebus configuration." - echo - echo "Options:" - echo " --debug -d Enable shell's debug output." - echo " --yes -y Answer all questions with \"yes\" automatically." - echo " --no -n Answer all questions with \"no\" automatically." - echo - exit 1 - ;; - - esac -done - -# ====================================================================== -# Action! -# ====================================================================== - -# Check for ${SYSCONFDIR} directory -csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files." -chmod 775 "${SYSCONFDIR}" -setfacl -m u:system:rwx "${SYSCONFDIR}" - -# Check for ${DEVDIR} directory -csih_make_dir "${DEVDIR}" "Syslogging using messagebus will not work." -chmod 775 "${DEVDIR}" -setfacl -m u:system:rwx "${DEVDIR}" - -# Check for ${LOGDIR} directory -csih_make_dir "${LOGDIR}" "Syslogging using messagebus will not work." -chmod 775 "${LOGDIR}" -setfacl -m u:system:rwx "${LOGDIR}" - -# Check for ${RUNDIR} directory -csih_make_dir "${RUNDIR}" "PID files of running processes will not be created." -chmod 775 "${RUNDIR}" -setfacl -m u:system:rwx "${RUNDIR}" - -# Check for ${SOCKDIR} directory -csih_make_dir "${SOCKDIR}" "SOCKET files of running processes will not be created." -chmod 775 "${SOCKDIR}" -setfacl -m u:system:rwx "${SOCKDIR}" - -# maybe: csih_auto_answer=no will skip, -# interactive user will get a chance to override -install_service - - -echo -echo "Configuration finished. Have fun!" diff --git a/bus/messagebus.in b/bus/messagebus.in deleted file mode 100755 index 3e2ee07a..00000000 --- a/bus/messagebus.in +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh -# -# messagebus: The D-BUS systemwide message bus -# -# chkconfig: 345 22 85 -# description: This is a daemon which broadcasts notifications of system events \ -# and other messages. See http://www.freedesktop.org/software/dbus/ -# -# processname: dbus-daemon -# pidfile: @DBUS_SYSTEM_PID_FILE@ -# -### BEGIN INIT INFO -# Provides: messagebus -# Required-Start: $syslog $local_fs -# Required-Stop: $syslog $local_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: The D-Bus systemwide message bus -# Description: This is a daemon which broadcasts notifications of system -# events and other messages. See http://www.freedesktop.org/software/dbus -### END INIT INFO - -# Sanity checks. -[ -x @EXPANDED_BINDIR@/dbus-daemon ] || exit 0 - -# Source function library. -. @EXPANDED_SYSCONFDIR@/rc.d/init.d/functions - -# so we can rearrange this easily -processname=dbus-daemon -servicename=messagebus - -RETVAL=0 - -start() { - echo -n $"Starting system message bus: " - if [ -x @EXPANDED_BINDIR@/dbus-uuidgen ] ; then - @EXPANDED_BINDIR@/dbus-uuidgen --ensure - fi - - daemon --check $servicename $processname --system - RETVAL=$? - echo - [ $RETVAL -eq 0 ] && touch @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename -} - -stop() { - echo -n $"Stopping system message bus: " - - ## we don't want to kill all the per-user $processname, we want - ## to use the pid file *only*; because we use the fake nonexistent - ## program name "$servicename" that should be safe-ish - killproc $servicename -TERM - RETVAL=$? - echo - if [ $RETVAL -eq 0 ]; then - rm -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename - rm -f @DBUS_SYSTEM_PID_FILE@ - fi -} - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status $servicename - RETVAL=$? - ;; - restart) - stop - start - ;; - condrestart) - if [ -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename ]; then - stop - start - fi - ;; - reload) - echo "Message bus can't reload its configuration, you have to restart it" - RETVAL=$? - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" - ;; -esac -exit $RETVAL diff --git a/bus/policy.c b/bus/policy.c index 24c0f06d..6e642951 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -30,6 +30,7 @@ #include <dbus/dbus-list.h> #include <dbus/dbus-hash.h> #include <dbus/dbus-internals.h> +#include <dbus/dbus-message-internal.h> BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, @@ -71,6 +72,8 @@ bus_policy_rule_new (BusPolicyRuleType type, break; case BUS_POLICY_RULE_OWN: break; + default: + _dbus_assert_not_reached ("invalid rule"); } return rule; @@ -118,6 +121,8 @@ bus_policy_rule_unref (BusPolicyRule *rule) break; case BUS_POLICY_RULE_GROUP: break; + default: + _dbus_assert_not_reached ("invalid rule"); } dbus_free (rule->privilege); @@ -264,6 +269,9 @@ add_list_to_client (DBusList **list, if (!bus_client_policy_append_rule (client, rule)) return FALSE; break; + + default: + _dbus_assert_not_reached ("invalid rule"); } } @@ -836,8 +844,11 @@ bus_client_policy_optimize (BusClientPolicy *policy) remove_preceding = rule->d.own.service_name == NULL; break; + + /* The other rule types don't appear in this list */ case BUS_POLICY_RULE_USER: case BUS_POLICY_RULE_GROUP: + default: _dbus_assert_not_reached ("invalid rule"); break; } @@ -1090,7 +1101,27 @@ bus_client_policy_check_can_send (DBusConnection *sender, continue; } } - + + if (rule->d.send.broadcast != BUS_POLICY_TRISTATE_ANY) + { + if (dbus_message_get_destination (message) == NULL && + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) + { + /* it's a broadcast */ + if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_FALSE) + { + _dbus_verbose (" (policy) skipping rule because message is a broadcast\n"); + continue; + } + } + /* else it isn't a broadcast: there is some destination */ + else if (rule->d.send.broadcast == BUS_POLICY_TRISTATE_TRUE) + { + _dbus_verbose (" (policy) skipping rule because message is not a broadcast\n"); + continue; + } + } + if (rule->d.send.destination != NULL) { if (!rule->d.send.destination_prefix) @@ -1176,6 +1207,20 @@ bus_client_policy_check_can_send (DBusConnection *sender, } } + if (rule->d.send.min_fds > 0 || + rule->d.send.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (message); + + if (n_fds < rule->d.send.min_fds || n_fds > rule->d.send.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.send.min_fds, rule->d.send.max_fds); + continue; + } + } + /* Use this rule */ switch (rule->access) { @@ -1421,7 +1466,22 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } } } - + + if (rule->d.receive.min_fds > 0 || + rule->d.receive.max_fds < DBUS_MAXIMUM_MESSAGE_UNIX_FDS) + { + unsigned int n_fds = _dbus_message_get_n_unix_fds (message); + + if (n_fds < rule->d.receive.min_fds || n_fds > rule->d.receive.max_fds) + { + _dbus_verbose (" (policy) skipping rule because message has %u fds " + "and that is outside range [%u,%u]", + n_fds, rule->d.receive.min_fds, + rule->d.receive.max_fds); + continue; + } + } + /* Use this rule */ switch (rule->access) { diff --git a/bus/policy.h b/bus/policy.h index 951ece1f..be704e3b 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -47,6 +47,13 @@ typedef enum BUS_POLICY_RULE_ACCESS_CHECK } BusPolicyRuleAccess; +typedef enum +{ + BUS_POLICY_TRISTATE_ANY = 0, + BUS_POLICY_TRISTATE_FALSE, + BUS_POLICY_TRISTATE_TRUE +} BusPolicyTristate; + /** determines whether the rule affects a connection, or some global item */ #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \ (rule)->type == BUS_POLICY_RULE_GROUP)) @@ -72,10 +79,13 @@ struct BusPolicyRule char *member; char *error; char *destination; + unsigned int max_fds; + unsigned int min_fds; unsigned int eavesdrop : 1; unsigned int requested_reply : 1; unsigned int log : 1; unsigned int destination_prefix : 1; + unsigned int broadcast : 2; /**< really a BusPolicyTristate */ } send; struct @@ -88,6 +98,8 @@ struct BusPolicyRule char *member; char *error; char *origin; + unsigned int max_fds; + unsigned int min_fds; unsigned int eavesdrop : 1; unsigned int requested_reply : 1; } receive; diff --git a/bus/rc.messagebus.in b/bus/rc.messagebus.in deleted file mode 100644 index c52ca777..00000000 --- a/bus/rc.messagebus.in +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# -# messagebus: The D-BUS systemwide message bus -# -# chkconfig: 345 97 03 -# description: This is a daemon which broadcasts notifications of system events \ -# and other messages. See http://www.freedesktop.org/software/dbus/ -# -# processname: dbus-daemon -# pidfile: @DBUS_SYSTEM_PID_FILE@ -# - -# Sanity checks. -#[ -x @EXPANDED_BINDIR@/dbus-daemon ] || exit 0 - -# Source function library. -#. @EXPANDED_SYSCONFDIR@/rc.d/init.d/functions - -# so we can rearrange this easily -#processname=dbus-daemon -#servicename=messagebus - -#RETVAL=0 - -start() { - echo "Starting system message bus" - if [ -x @EXPANDED_BINDIR@/dbus-uuidgen ] ; then - @EXPANDED_BINDIR@/dbus-uuidgen --ensure - fi - - if [ -x @EXPANDED_BINDIR@/dbus-daemon ];then - @EXPANDED_BINDIR@/dbus-daemon --system - fi - #daemon --check $servicename $processname --system - #RETVAL=$? - #echo - #[ $RETVAL -eq 0 ] && touch @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename -} - -stop() { - echo "Stopping system message bus" - - ## we don't want to kill all the per-user $processname, we want - ## to use the pid file *only*; because we use the fake nonexistent - ## program name "$servicename" that should be safe-ish - killall dbus-daemon - #RETVAL=$? - #echo - #if [ $RETVAL -eq 0 ]; then - # rm -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename - # rm -f @DBUS_SYSTEM_PID_FILE@ - #fi -} - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status $servicename - RETVAL=$? - ;; - restart) - stop - start - ;; - reload) - echo "Message bus can't reload its configuration, you have to restart it" - RETVAL=$? - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|reload}" - ;; -esac -exit $RETVAL diff --git a/bus/selinux.c b/bus/selinux.c index be66d4f0..d09afb4b 100644 --- a/bus/selinux.c +++ b/bus/selinux.c @@ -71,7 +71,7 @@ static security_id_t bus_sid = SECSID_WILD; static pthread_t avc_notify_thread; /* Prototypes for AVC callback functions. */ -static void log_callback (const char *fmt, ...); +static void log_callback (const char *fmt, ...) _DBUS_GNUC_PRINTF (1, 2); static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft); static void *avc_create_thread (void (*run) (void)); static void avc_stop_thread (void *thread); @@ -146,7 +146,9 @@ log_callback (const char *fmt, ...) vsyslog (LOG_USER | LOG_INFO, fmt, ap); +#ifdef HAVE_LIBAUDIT out: +#endif va_end(ap); } @@ -203,7 +205,7 @@ avc_create_thread (void (*run) (void)) rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL); if (rc != 0) { - _dbus_warn ("Failed to start AVC thread: %s\n", _dbus_strerror (rc)); + _dbus_warn ("Failed to start AVC thread: %s", _dbus_strerror (rc)); exit (1); } return &avc_notify_thread; @@ -225,7 +227,7 @@ avc_alloc_lock (void) avc_mutex = dbus_new (pthread_mutex_t, 1); if (avc_mutex == NULL) { - _dbus_warn ("Could not create mutex: %s\n", _dbus_strerror (errno)); + _dbus_warn ("Could not create mutex: %s", _dbus_strerror (errno)); exit (1); } pthread_mutex_init (avc_mutex, NULL); @@ -270,6 +272,19 @@ bus_selinux_enabled (void) #endif /* HAVE_SELINUX */ } +BusSELinuxID* +bus_selinux_get_self (void) +{ +#ifdef HAVE_SELINUX + if(bus_selinux_enabled ()) + return BUS_SID_FROM_SELINUX (bus_sid); + else + return NULL; +#else + return NULL; +#endif /* HAVE_SELINUX */ +} + /** * Do early initialization; determine whether SELinux is enabled. */ @@ -284,7 +299,7 @@ bus_selinux_pre_init (void) r = is_selinux_enabled (); if (r < 0) { - _dbus_warn ("Could not tell if SELinux is enabled: %s\n", + _dbus_warn ("Could not tell if SELinux is enabled: %s", _dbus_strerror (errno)); return FALSE; } @@ -337,7 +352,7 @@ bus_selinux_full_init (void) if (selinux_set_mapping (dbus_map) < 0) { - _dbus_warn ("Failed to set up security class mapping (selinux_set_mapping():%s).\n", + _dbus_warn ("Failed to set up security class mapping (selinux_set_mapping():%s).", strerror (errno)); return FALSE; } @@ -345,7 +360,7 @@ bus_selinux_full_init (void) avc_entry_ref_init (&aeref); if (avc_init ("avc", &mem_cb, &log_cb, &thread_cb, &lock_cb) < 0) { - _dbus_warn ("Failed to start Access Vector Cache (AVC).\n"); + _dbus_warn ("Failed to start Access Vector Cache (AVC)."); return FALSE; } else @@ -356,7 +371,7 @@ bus_selinux_full_init (void) if (avc_add_callback (policy_reload_callback, AVC_CALLBACK_RESET, NULL, NULL, 0, 0) < 0) { - _dbus_warn ("Failed to add policy reload callback: %s\n", + _dbus_warn ("Failed to add policy reload callback: %s", _dbus_strerror (errno)); avc_destroy (); return FALSE; @@ -387,37 +402,6 @@ bus_selinux_full_init (void) } /** - * Decrement SID reference count. - * - * @param sid the SID to decrement - */ -void -bus_selinux_id_unref (BusSELinuxID *sid) -{ -#ifdef HAVE_SELINUX - if (!selinux_enabled) - return; - - _dbus_assert (sid != NULL); - - sidput (SELINUX_SID_FROM_BUS (sid)); -#endif /* HAVE_SELINUX */ -} - -void -bus_selinux_id_ref (BusSELinuxID *sid) -{ -#ifdef HAVE_SELINUX - if (!selinux_enabled) - return; - - _dbus_assert (sid != NULL); - - sidget (SELINUX_SID_FROM_BUS (sid)); -#endif /* HAVE_SELINUX */ -} - -/** * Determine if the SELinux security policy allows the given sender * security context to go to the given recipient security context. * This function determines if the requested permissions are to be @@ -448,7 +432,7 @@ bus_selinux_check (BusSELinuxID *sender_sid, if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid), override_sid ? SELINUX_SID_FROM_BUS (override_sid) : - SELINUX_SID_FROM_BUS (bus_sid), + bus_sid, target_class, requested, &aeref, auxdata) < 0) { switch (errno) @@ -773,7 +757,7 @@ bus_selinux_init_connection_id (DBusConnection *connection, "Error getting SID from context \"%s\": %s\n", con, _dbus_strerror (errno)); - _dbus_warn ("Error getting SID from context \"%s\": %s\n", + _dbus_warn ("Error getting SID from context \"%s\": %s", con, _dbus_strerror (errno)); freecon (con); @@ -787,21 +771,6 @@ bus_selinux_init_connection_id (DBusConnection *connection, #endif /* HAVE_SELINUX */ } - -/** - * Function for freeing hash table data. These SIDs - * should no longer be referenced. - */ -static void -bus_selinux_id_table_free_value (BusSELinuxID *sid) -{ -#ifdef HAVE_SELINUX - /* NULL sometimes due to how DBusHashTable works */ - if (sid) - bus_selinux_id_unref (sid); -#endif /* HAVE_SELINUX */ -} - /** * Creates a new table mapping service names to security ID. * A security ID is a "compiled" security context, a security @@ -813,8 +782,7 @@ DBusHashTable* bus_selinux_id_table_new (void) { return _dbus_hash_table_new (DBUS_HASH_STRING, - (DBusFreeFunction) dbus_free, - (DBusFreeFunction) bus_selinux_id_table_free_value); + (DBusFreeFunction) dbus_free, NULL); } /** @@ -854,7 +822,7 @@ bus_selinux_id_table_insert (DBusHashTable *service_table, return FALSE; } - _dbus_warn ("Error getting SID from context \"%s\": %s\n", + _dbus_warn ("Error getting SID from context \"%s\": %s", (char *) service_context, _dbus_strerror (errno)); goto out; @@ -876,9 +844,6 @@ bus_selinux_id_table_insert (DBusHashTable *service_table, retval = TRUE; out: - if (sid != SECSID_WILD) - sidput (sid); - if (key) dbus_free (key); @@ -1013,7 +978,6 @@ bus_selinux_shutdown (void) if (bus_sid != SECSID_WILD) { - sidput (bus_sid); bus_sid = SECSID_WILD; bus_avc_print_stats (); diff --git a/bus/selinux.h b/bus/selinux.h index 5252b189..a0383cdd 100644 --- a/bus/selinux.h +++ b/bus/selinux.h @@ -33,8 +33,7 @@ void bus_selinux_shutdown (void); dbus_bool_t bus_selinux_enabled (void); -void bus_selinux_id_ref (BusSELinuxID *sid); -void bus_selinux_id_unref (BusSELinuxID *sid); +BusSELinuxID *bus_selinux_get_self (void); DBusHashTable* bus_selinux_id_table_new (void); BusSELinuxID* bus_selinux_id_table_lookup (DBusHashTable *service_table, diff --git a/bus/services.c b/bus/services.c index 9e466d87..af0307c4 100644 --- a/bus/services.c +++ b/bus/services.c @@ -393,6 +393,7 @@ bus_registry_acquire_service (BusRegistry *registry, BusActivation *activation; BusSELinuxID *sid; BusOwner *primary_owner; + int limit; retval = BUS_RESULT_FALSE; @@ -493,16 +494,25 @@ bus_registry_acquire_service (BusRegistry *registry, goto out; } - if (bus_connection_get_n_services_owned (connection) >= - bus_context_get_max_services_per_connection (registry->context)) + limit = bus_context_get_max_services_per_connection (registry->context); + + if (bus_connection_get_n_services_owned (connection) >= limit) { - dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + DBusError tmp_error; + + dbus_error_init (&tmp_error); + dbus_set_error (&tmp_error, DBUS_ERROR_LIMITS_EXCEEDED, "Connection \"%s\" (%s) is not allowed to own more services " - "(increase limits in configuration file if required)", + "(increase limits in configuration file if required)" + "max_names_per_connection=%d)", bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", - bus_connection_get_loginfo (connection)); + bus_connection_get_loginfo (connection), + limit); + bus_context_log (registry->context, DBUS_SYSTEM_LOG_WARNING, + "%s", tmp_error.message); + dbus_move_error (&tmp_error, error); goto out; } diff --git a/bus/signals.c b/bus/signals.c index e8def9f7..6b7a464c 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -871,7 +871,7 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, else { dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg); + "Key '%s' in match rule contains junk after argument number (%lu). Only 'arg%lupath' (for example) or 'arg0namespace' are valid", key, arg, arg); goto failed; } } @@ -889,7 +889,7 @@ bus_match_rule_parse_arg_match (BusMatchRule *rule, rule->args[arg] != NULL) { dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, - "Argument %d matched more than once in match rule\n", key); + "Argument %s matched more than once in match rule\n", key); goto failed; } @@ -1887,9 +1887,18 @@ match_rule_matches (BusMatchRule *rule, return FALSE; if (addressed_recipient == NULL) - { - if (strcmp (rule->destination, - DBUS_SERVICE_DBUS) != 0) + { + /* If the message is going to be delivered to the dbus-daemon + * itself, its destination will be "org.freedesktop.DBus", + * which we again match against the rule (see bus_dispatch() + * in bus/dispatch.c, which checks for o.fd.DBus first). + * + * If we are monitoring and we don't know who is going to receive + * the message (for instance because they haven't been activated yet), + * assume they will own the requested destination name and no other, + * and match the rule's destination against that. + */ + if (strcmp (rule->destination, destination) != 0) return FALSE; } else @@ -2192,7 +2201,7 @@ check_parse (dbus_bool_t should_succeed, if (should_succeed && rule == NULL) { - _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n", + _dbus_warn ("Failed to parse: %s: %s: \"%s\"", error.name, error.message, _dbus_string_get_const_data (&str)); exit (1); @@ -2200,7 +2209,7 @@ check_parse (dbus_bool_t should_succeed, if (!should_succeed && rule != NULL) { - _dbus_warn ("Failed to fail to parse: \"%s\"\n", + _dbus_warn ("Failed to fail to parse: \"%s\"", _dbus_string_get_const_data (&str)); exit (1); } @@ -2540,7 +2549,7 @@ test_equality (void) if (!match_rule_equal (first, second)) { - _dbus_warn ("rule %s and %s should have been equal\n", + _dbus_warn ("rule %s and %s should have been equal", equality_tests[i].first, equality_tests[i].second); exit (1); @@ -2553,7 +2562,9 @@ test_equality (void) _dbus_assert (second_str != NULL); _dbus_assert (strcmp (first_str, second_str) == 0); first_reparsed = check_parse (TRUE, first_str); + _dbus_assert (first_reparsed != NULL); second_reparsed = check_parse (TRUE, second_str); + _dbus_assert (second_reparsed != NULL); _dbus_assert (match_rule_equal (first, first_reparsed)); _dbus_assert (match_rule_equal (second, second_reparsed)); bus_match_rule_unref (first_reparsed); @@ -2572,10 +2583,11 @@ test_equality (void) if (i != j) { second = check_parse (TRUE, equality_tests[j].second); + _dbus_assert (second != NULL); if (match_rule_equal (first, second)) { - _dbus_warn ("rule %s and %s should not have been equal\n", + _dbus_warn ("rule %s and %s should not have been equal", equality_tests[i].first, equality_tests[j].second); exit (1); @@ -2685,7 +2697,7 @@ check_matches (dbus_bool_t expected_to_match, if (matched != expected_to_match) { - _dbus_warn ("Expected rule %s to %s message %d, failed\n", + _dbus_warn ("Expected rule %s to %s message %d, failed", rule_text, expected_to_match ? "match" : "not match", number); exit (1); @@ -2814,7 +2826,7 @@ test_path_match (int type, if (matched != should_match) { _dbus_warn ("Expected rule %s to %s message " - "with first arg %s of type '%c', failed\n", + "with first arg %s of type '%c', failed", rule_text, should_match ? "match" : "not match", path, diff --git a/bus/stats.c b/bus/stats.c index 5312b96a..27422352 100644 --- a/bus/stats.c +++ b/bus/stats.c @@ -51,9 +51,6 @@ bus_stats_handle_get_stats (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!bus_driver_check_message_is_for_us (message, error)) - return FALSE; - context = bus_transaction_get_context (transaction); connections = bus_context_get_connections (context); @@ -123,40 +120,37 @@ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection, DBusMessage *message, DBusError *error) { - const char *bus_name = NULL; - DBusString bus_name_str; + BusDriverFound found; DBusMessage *reply = NULL; DBusMessageIter iter, arr_iter; static dbus_uint32_t stats_serial = 0; dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds; dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds; - BusRegistry *registry; - BusService *service; DBusConnection *stats_connection; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!bus_driver_check_message_is_for_us (message, error)) - return FALSE; + found = bus_driver_get_conn_helper (caller_connection, message, + "statistics", NULL, &stats_connection, + error); - registry = bus_connection_get_registry (caller_connection); - - if (! dbus_message_get_args (message, error, - DBUS_TYPE_STRING, &bus_name, - DBUS_TYPE_INVALID)) - return BUS_RESULT_FALSE; - - _dbus_string_init_const (&bus_name_str, bus_name); - service = bus_registry_lookup (registry, &bus_name_str); - - if (service == NULL) + switch (found) { - dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER, - "Bus name '%s' has no owner", bus_name); - return BUS_RESULT_FALSE; + case BUS_DRIVER_FOUND_SELF: + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "GetConnectionStats is not meaningful for the " + "message bus \"%s\" itself", DBUS_SERVICE_DBUS); + goto failed; + + case BUS_DRIVER_FOUND_PEER: + break; + + case BUS_DRIVER_FOUND_ERROR: + /* fall through */ + default: + goto failed; } - stats_connection = bus_service_get_primary_owners_connection (service); _dbus_assert (stats_connection != NULL); reply = _dbus_asv_new_method_return (message, &iter, &arr_iter); @@ -218,10 +212,12 @@ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection, return BUS_RESULT_TRUE; oom: + BUS_SET_OOM (error); + /* fall through */ +failed: if (reply != NULL) dbus_message_unref (reply); - BUS_SET_OOM (error); return BUS_RESULT_FALSE; } diff --git a/bus/system.conf.in b/bus/system.conf.in index 58975dc5..f139b557 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -67,7 +67,8 @@ send_interface="org.freedesktop.DBus" /> <allow send_destination="org.freedesktop.DBus" send_interface="org.freedesktop.DBus.Introspectable"/> - + <allow send_destination="org.freedesktop.DBus" + send_interface="org.freedesktop.DBus.Properties"/> <!-- But disallow some specific bus services --> <deny send_destination="org.freedesktop.DBus" send_interface="org.freedesktop.DBus" @@ -101,6 +102,29 @@ <!-- Include legacy configuration location --> <include ignore_missing="yes">@SYSCONFDIR_FROM_PKGDATADIR@/dbus-1/system.conf</include> + <!-- The defaults for these limits are hard-coded in dbus-daemon. + Some clarifications: + Times are in milliseconds (ms); 1000ms = 1 second + 133169152 bytes = 127 MiB + 33554432 bytes = 32 MiB + 150000ms = 2.5 minutes --> + <!-- <limit name="max_incoming_bytes">133169152</limit> --> + <!-- <limit name="max_incoming_unix_fds">64</limit> --> + <!-- <limit name="max_outgoing_bytes">133169152</limit> --> + <!-- <limit name="max_outgoing_unix_fds">64</limit> --> + <!-- <limit name="max_message_size">33554432</limit> --> + <!-- <limit name="max_message_unix_fds">16</limit> --> + <!-- <limit name="service_start_timeout">25000</limit> --> + <!-- <limit name="auth_timeout">5000</limit> --> + <!-- <limit name="pending_fd_timeout">150000</limit> --> + <!-- <limit name="max_completed_connections">2048</limit> --> + <!-- <limit name="max_incomplete_connections">64</limit> --> + <!-- <limit name="max_connections_per_user">256</limit> --> + <!-- <limit name="max_pending_service_starts">512</limit> --> + <!-- <limit name="max_names_per_connection">512</limit> --> + <!-- <limit name="max_match_rules_per_connection">512</limit> --> + <!-- <limit name="max_replies_per_connection">128</limit> --> + <!-- Config files are placed here that among other things, punch holes in the above policy for specific services. --> <includedir>system.d</includedir> diff --git a/bus/systemd-user/dbus.service.in b/bus/systemd-user/dbus.service.in index 6af9c19b..103fdec9 100644 --- a/bus/systemd-user/dbus.service.in +++ b/bus/systemd-user/dbus.service.in @@ -5,7 +5,7 @@ DefaultDependencies=no Requires=dbus.socket [Service] -ExecStart=@EXPANDED_BINDIR@/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation +ExecStart=@EXPANDED_BINDIR@/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only ExecReload=@EXPANDED_BINDIR@/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig Capabilities=all-eip diff --git a/bus/systemd-user/dbus.socket.in b/bus/systemd-user/dbus.socket.in index 0028e0a7..45d938b7 100644 --- a/bus/systemd-user/dbus.socket.in +++ b/bus/systemd-user/dbus.socket.in @@ -4,6 +4,8 @@ DefaultDependencies=no [Socket] ListenStream=%t/bus +# FIXME: check the commented line below +#ExecStartPost=-@SYSTEMCTL@ --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus [Install] Also=dbus.service diff --git a/bus/sysusers.d/dbus.conf.in b/bus/sysusers.d/dbus.conf.in new file mode 100644 index 00000000..fb35702d --- /dev/null +++ b/bus/sysusers.d/dbus.conf.in @@ -0,0 +1,5 @@ +# sysusers.d snippet for creating the D-Bus system user automatically +# at boot on systemd-based systems that ship with an unpopulated +# /etc. See sysusers.d(5) for details. + +u @DBUS_USER@ - "System Message Bus" diff --git a/bus/test-launch-helper.c b/bus/test-launch-helper.c index e9ba412a..5872ab20 100644 --- a/bus/test-launch-helper.c +++ b/bus/test-launch-helper.c @@ -30,7 +30,12 @@ #include <dbus/dbus-internals.h> #include <dbus/dbus-misc.h> -#ifdef DBUS_ENABLE_EMBEDDED_TESTS +#if !defined(DBUS_ENABLE_EMBEDDED_TESTS) || !defined(DBUS_UNIX) +#error This file is only relevant for the embedded tests on Unix +#endif + +static void die (const char *failure) _DBUS_GNUC_NORETURN; + static void die (const char *failure) { @@ -46,7 +51,7 @@ check_memleaks (const char *name) printf ("%s: checking for memleaks\n", name); if (_dbus_get_malloc_blocks_outstanding () != 0) { - _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_warn ("%d dbus_malloc blocks were not freed", _dbus_get_malloc_blocks_outstanding ()); die ("memleaks"); } @@ -57,8 +62,6 @@ test_post_hook (const char *name) { check_memleaks (name); } -#endif /* DBUS_ENABLE_EMBEDDED_TESTS */ - #ifdef ACTIVATION_LAUNCHER_DO_OOM @@ -80,7 +83,7 @@ bus_activation_helper_oom_test (void *data) /* we failed, but a OOM is good */ if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { - _dbus_warn ("FAILED SELF TEST: Error: %s\n", error.message); + _dbus_warn ("FAILED SELF TEST: Error: %s", error.message); retval = FALSE; } dbus_error_free (&error); @@ -98,11 +101,10 @@ bus_activation_helper_oom_test (void *data) int main (int argc, char **argv) { -#ifdef DBUS_ENABLE_EMBEDDED_TESTS const char *dir; DBusString config_file; - if (argc > 1) + if (argc > 1 && strcmp (argv[1], "--tap") != 0) dir = argv[1]; else dir = _dbus_getenv ("DBUS_TEST_DATA"); @@ -130,7 +132,7 @@ main (int argc, char **argv) if (!_dbus_test_oom_handling ("dbus-daemon-launch-helper", bus_activation_helper_oom_test, - "org.freedesktop.DBus.TestSuiteEchoService")) + (char *) "org.freedesktop.DBus.TestSuiteEchoService")) die ("OOM failed"); test_post_hook (argv[0]); @@ -138,11 +140,4 @@ main (int argc, char **argv) printf ("%s: Success\n", argv[0]); return 0; -#else /* DBUS_ENABLE_EMBEDDED_TESTS */ - - printf ("Not compiled with test support\n"); - - return 0; -#endif } - diff --git a/bus/test-main.c b/bus/test-main.c index 788574fe..4d3df87a 100644 --- a/bus/test-main.c +++ b/bus/test-main.c @@ -31,11 +31,16 @@ #include <dbus/dbus-message-internal.h> #include "selinux.h" +#ifndef DBUS_ENABLE_EMBEDDED_TESTS +#error This file is only relevant for the embedded tests +#endif + #ifdef DBUS_UNIX # include <dbus/dbus-sysdeps-unix.h> #endif -#ifdef DBUS_ENABLE_EMBEDDED_TESTS +static void die (const char *failure) _DBUS_GNUC_NORETURN; + static void die (const char *failure) { @@ -51,12 +56,11 @@ check_memleaks (const char *name) printf ("%s: checking for memleaks\n", name); if (_dbus_get_malloc_blocks_outstanding () != 0) { - _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_warn ("%d dbus_malloc blocks were not freed", _dbus_get_malloc_blocks_outstanding ()); die ("memleaks"); } } -#endif /* DBUS_ENABLE_EMBEDDED_TESTS */ static DBusInitialFDs *initial_fds = NULL; @@ -72,7 +76,7 @@ test_pre_hook (void) initial_fds = _dbus_check_fdleaks_enter (); } -static char *progname = ""; +static const char *progname = ""; static void test_post_hook (void) @@ -88,14 +92,13 @@ test_post_hook (void) int main (int argc, char **argv) { -#ifdef DBUS_ENABLE_EMBEDDED_TESTS const char *dir; const char *only; DBusString test_data_dir; progname = argv[0]; - if (argc > 1) + if (argc > 1 && strcmp (argv[1], "--tap") != 0) dir = argv[1]; else dir = _dbus_getenv ("DBUS_TEST_DATA"); @@ -190,10 +193,4 @@ main (int argc, char **argv) return 0; -#else /* DBUS_ENABLE_EMBEDDED_TESTS */ - - printf ("Not compiled with test support\n"); - - return 0; -#endif } diff --git a/bus/test-system.c b/bus/test-system.c index 5f02d0ab..de1f003b 100644 --- a/bus/test-system.c +++ b/bus/test-system.c @@ -29,7 +29,12 @@ #include <dbus/dbus-sysdeps.h> #include <dbus/dbus-internals.h> -#ifdef DBUS_ENABLE_EMBEDDED_TESTS +#if !defined(DBUS_ENABLE_EMBEDDED_TESTS) || !defined(DBUS_UNIX) +#error This file is only relevant for the embedded tests on Unix +#endif + +static void die (const char *failure) _DBUS_GNUC_NORETURN; + static void die (const char *failure) { @@ -45,19 +50,18 @@ check_memleaks (const char *name) printf ("%s: checking for memleaks\n", name); if (_dbus_get_malloc_blocks_outstanding () != 0) { - _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_warn ("%d dbus_malloc blocks were not freed", _dbus_get_malloc_blocks_outstanding ()); die ("memleaks"); } } -#endif /* DBUS_ENABLE_EMBEDDED_TESTS */ static void test_pre_hook (void) { } -static char *progname = ""; +static const char *progname = ""; static void test_post_hook (void) { @@ -67,13 +71,12 @@ test_post_hook (void) int main (int argc, char **argv) { -#ifdef DBUS_ENABLE_EMBEDDED_TESTS const char *dir; DBusString test_data_dir; progname = argv[0]; - if (argc > 1) + if (argc > 1 && strcmp (argv[1], "--tap") != 0) dir = argv[1]; else dir = _dbus_getenv ("DBUS_TEST_DATA"); @@ -98,10 +101,4 @@ main (int argc, char **argv) printf ("%s: Success\n", argv[0]); return 0; -#else /* DBUS_ENABLE_EMBEDDED_TESTS */ - - printf ("Not compiled with test support\n"); - - return 0; -#endif } @@ -270,14 +270,14 @@ bus_context_new_test (const DBusString *test_data_dir, if (!_dbus_string_init (&config_file)) { - _dbus_warn ("No memory\n"); + _dbus_warn ("No memory"); return NULL; } if (!_dbus_string_copy (test_data_dir, 0, &config_file, 0)) { - _dbus_warn ("No memory\n"); + _dbus_warn ("No memory"); _dbus_string_free (&config_file); return NULL; } @@ -286,7 +286,7 @@ bus_context_new_test (const DBusString *test_data_dir, if (!_dbus_concat_dir_and_file (&config_file, &relative)) { - _dbus_warn ("No memory\n"); + _dbus_warn ("No memory"); _dbus_string_free (&config_file); return NULL; } @@ -297,7 +297,7 @@ bus_context_new_test (const DBusString *test_data_dir, { _DBUS_ASSERT_ERROR_IS_SET (&error); - _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n", + _dbus_warn ("Failed to create debug bus context from configuration file %s: %s", filename, error.message); dbus_error_free (&error); diff --git a/bus/tmpfiles.d/dbus.conf.in b/bus/tmpfiles.d/dbus.conf.in new file mode 100644 index 00000000..0ec7de04 --- /dev/null +++ b/bus/tmpfiles.d/dbus.conf.in @@ -0,0 +1,9 @@ +# Fields: type; path; mode; uid; gid; age; argument (symlink target) + +# Make ${localstatedir}/lib/dbus (required for systemd < 237) +# Adjust mode and ownership if it already exists. +d @EXPANDED_LOCALSTATEDIR@/lib/dbus 0755 - - - + +# Make ${localstatedir}/lib/dbus/machine-id a symlink to /etc/machine-id +# if it does not already exist +L @EXPANDED_LOCALSTATEDIR@/lib/dbus/machine-id - - - - /etc/machine-id |