diff --git a/configure.ac b/configure.ac index 70d31b7..b9a7c8c 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,7 @@ AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue suppor AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto) AC_ARG_ENABLE(launchd, AS_HELP_STRING([--enable-launchd],[build with launchd auto-launch support]),enable_launchd=$enableval,enable_launchd=auto) AC_ARG_ENABLE(systemd, AS_HELP_STRING([--enable-systemd],[build with systemd at_console support]),enable_systemd=$enableval,enable_systemd=auto) +AC_ARG_ENABLE(systemd-environment, AS_HELP_STRING([--enable-systemd-environment],[build with systemd environment import in dbus-launch]),enable_systemd_environment=$enableval,enable_systemd_environment=auto) AC_ARG_WITH(init-scripts, AS_HELP_STRING([--with-init-scripts=[redhat]],[Style of init scripts to install])) AC_ARG_WITH(session-socket-dir, AS_HELP_STRING([--with-session-socket-dir=[dirname]],[Where to put sockets for the per-login-session message bus])) @@ -1172,6 +1173,18 @@ if test x$enable_systemd = xyes -a x$have_systemd != xyes ; then AC_MSG_ERROR([Explicitly requested systemd support, but systemd not found]) fi +if test x$enable_systemd_environment = xauto -a x$have_systemd = xyes ; then + enable_systemd_environment=yes +fi + +if test x$enable_systemd_environment = xyes -a x$have_systemd != xyes ; then + AC_MSG_ERROR([Explicitly requested systemd environment support, but systemd not found]) +fi + +if test x$enable_systemd_environment = xyes ; then + AC_DEFINE(SYSTEMD_ENVIRONMENT,1,[Systemd environment]) +fi + # libaudit detection if test x$enable_libaudit = xno ; then have_libaudit=no; @@ -1506,6 +1519,8 @@ if test "x$with_systemdsystemunitdir" != xno; then fi AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$have_systemd" != "xno" -a -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) +AM_CONDITIONAL(SYSTEMD_ENVIRONMENT, test x$enable_systemd_environment = xyes) + ##### Set up location for system bus socket if ! test -z "$with_system_socket"; then DBUS_SYSTEM_SOCKET=$with_system_socket diff --git a/tools/Makefile.am b/tools/Makefile.am index 05d1dcb..edf5cf7 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -77,6 +77,11 @@ dbus_launch_LDADD = \ $(DBUS_X_LIBS) \ $(NULL) +if SYSTEMD_ENVIRONMENT +dbus_launch_LDADD += \ + $(top_builddir)/dbus/libdbus-1.la +endif + examplesdir = ${docdir}/examples dist_examples_SCRIPTS = \ GetAllMatchRules.py \ diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c index 41a20e8..a37a75b 100644 --- a/tools/dbus-launch.c +++ b/tools/dbus-launch.c @@ -38,6 +38,10 @@ #include #include +#ifdef SYSTEMD_ENVIRONMENT +#include +#endif + #ifdef DBUS_BUILD_X11 #include extern Display *xdisplay; @@ -222,6 +226,7 @@ xstrdup (const char *str) return copy; } +#ifdef DBUS_ENABLE_EMBEDDED_TESTS static char * concat2 (const char *a, const char *b) @@ -241,6 +246,7 @@ concat2 (const char *a, memcpy (ret + la, b, lb + 1); return ret; } +#endif typedef enum { @@ -830,6 +836,143 @@ oom: exit (1); } +#ifdef SYSTEMD_ENVIRONMENT +static int syncenv_append_var(const char* container_sig, DBusMessageIter *container_iter, const char* key) { + const char *val; + + val = getenv (key); + if (val == NULL || *val == '\0') + return 0; + + if (container_sig[1] != '\0') + { + DBusMessageIter dict_iter; + dbus_message_iter_open_container (container_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter); + dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &val); + dbus_message_iter_close_container (container_iter, &dict_iter); + } + else + { + char* keyvalue; + int len; + + len = strlen (key) + strlen (val) + 2; + keyvalue = malloc (len); + + if (snprintf(keyvalue, len, "%s=%s", key, val) < 0) { + free (keyvalue); + fprintf (stderr, "Cannot allocate memory for environment variable definition\n"); + return 0; + } + + dbus_message_iter_append_basic (container_iter, DBUS_TYPE_STRING, &keyvalue); + + free (keyvalue); + } + + return 1; +} + +static int syncenv_to_daemon(DBusConnection *connection, DBusError *error, const char* dest, const char* path, const char* iface, const char* method) { + DBusMessage *message; + DBusMessageIter iter, container_iter; + char container_sig[5]; + + DBusMessage *reply; + int timeout = -1, vars_sent = 0; + + message = dbus_message_new_method_call (dest, path, iface, method); + if (message == NULL) { + fprintf (stderr, "Cannot allocate memory for dbus message\n"); + return 1; + } + dbus_message_set_auto_start (message, TRUE); + + if (strcmp (iface, "org.freedesktop.systemd1.Manager") == 0) + { + container_sig[0] = DBUS_TYPE_STRING; + container_sig[1] = '\0'; + } + else + { + container_sig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR; + container_sig[1] = DBUS_TYPE_STRING; + container_sig[2] = DBUS_TYPE_STRING; + container_sig[3] = DBUS_DICT_ENTRY_END_CHAR; + container_sig[4] = '\0'; + } + + dbus_message_iter_init_append (message, &iter); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, container_sig, &container_iter); + + vars_sent += syncenv_append_var(container_sig, &container_iter, "DISPLAY"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XAUTHORITY"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "SESSION_MANAGER"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_CONFIG_DIRS"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_CURRENT_DESKTOP"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_MENU_PREFIX"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_RUNTIME_DIR"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_SEAT"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_SESSION_DESKTOP"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_SESSION_ID"); + vars_sent += syncenv_append_var(container_sig, &container_iter, "XDG_VTNR"); + + dbus_message_iter_close_container (&iter, &container_iter); + + if (!vars_sent) + return 0; + + + reply = dbus_connection_send_with_reply_and_block (connection, message, timeout, error); + if (dbus_error_is_set (error)) + { + fprintf (stderr, "Error %s: %s\n", error->name, error->message); + dbus_error_free (error); + return 1; + } + + if (reply) + dbus_message_unref (reply); + dbus_message_unref (message); + + return 0; +} + + +static int syncenv(const char* bus_socket) { + DBusConnection *connection; + DBusError error; + int r_systemd, r_dbus_daemon; + + dbus_error_init (&error); + connection = dbus_connection_open (bus_socket, &error); + if (connection == NULL) { + fprintf (stderr, "Failed to open connection to \"%s\" message bus: %s\n", bus_socket, error.message); + dbus_error_free (&error); + return 1; + } + + if (!dbus_bus_register (connection, &error)) + { + fprintf (stderr, "Failed to register on connection to \"%s\" message bus: %s\n", bus_socket, error.message); + /* ?? dbus_connection_unref (connection); */ + dbus_error_free (&error); + return 1; + } + + r_systemd = syncenv_to_daemon(connection, &error, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment"); + r_dbus_daemon = syncenv_to_daemon(connection, &error, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "UpdateActivationEnvironment"); + + dbus_connection_unref (connection); + dbus_error_free (&error); + + return (r_systemd + r_dbus_daemon) ? 1 : 0; +} +#endif + + #define READ_END 0 #define WRITE_END 1 @@ -1074,6 +1217,11 @@ main (int argc, char **argv) char write_pid_fd_as_string[MAX_FD_LEN]; char write_address_fd_as_string[MAX_FD_LEN]; +#ifdef SYSTEMD_ENVIRONMENT + char systemd_socket[MAX_FD_LEN]; + uid_t uid; +#endif + #ifdef DBUS_BUILD_X11 xdisplay = NULL; #endif @@ -1167,6 +1315,30 @@ main (int argc, char **argv) } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ + #ifdef SYSTEMD_ENVIRONMENT + uid = getuid (); + if (uid > 1) + { + verbose ("checking for systemd socket activated socket path.\n"); + + snprintf (systemd_socket, MAX_FD_LEN, "unix:path=/run/user/%d/dbus/user_bus_socket", uid); + + if (access (systemd_socket+10, F_OK) != -1) + { + syncenv (systemd_socket); + + /* Use a -1 value for the PID so it's not killed - we leave it to systemd */ + do_write (bus_pid_to_launcher_pipe[WRITE_END], "-1", 3); + close (bus_pid_to_launcher_pipe[WRITE_END]); + + do_write (bus_address_to_launcher_pipe[WRITE_END], systemd_socket, strlen(systemd_socket) + 1); + close (bus_address_to_launcher_pipe[WRITE_END]); + + exit (0); + } + } + #endif + execl (DBUS_DAEMONDIR"/dbus-daemon", DBUS_DAEMONDIR"/dbus-daemon", "--fork", diff --git a/tools/dbus-send.c b/tools/dbus-send.c index d3ff258..49cf24a 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -387,7 +387,8 @@ main (int argc, char *argv[]) dbus_error_free (&error); exit (1); } - else if ((address != NULL) && is_bus) + + if ((address != NULL) && is_bus) { if (!dbus_bus_register (connection, &error)) {