diff options
| -rw-r--r-- | ChangeLog | 22 | ||||
| -rw-r--r-- | bus/system.conf.in | 7 | ||||
| -rw-r--r-- | configure.in | 90 | ||||
| -rw-r--r-- | dbus/dbus-server-unix.c | 9 | ||||
| -rw-r--r-- | dbus/dbus-server-unix.h | 1 | ||||
| -rw-r--r-- | dbus/dbus-server.c | 32 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 91 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-transport-unix.c | 14 | ||||
| -rw-r--r-- | dbus/dbus-transport-unix.h | 1 | ||||
| -rw-r--r-- | dbus/dbus-transport.c | 20 | ||||
| -rw-r--r-- | doc/dbus-specification.sgml | 9 | 
12 files changed, 238 insertions, 60 deletions
| @@ -1,3 +1,25 @@ +2003-06-04  Havoc Pennington  <hp@pobox.com> + +	* dbus/dbus-server.c (dbus_server_listen): allow abstract sockets +	using unix:abstract=/foo, and when listening in a tmpdir +	i.e. unix:tmpdir=/tmp, always use abstract sockets if we can. + +	* dbus/dbus-transport.c (_dbus_transport_open): support +	unix:abstract=/foo + +	* dbus/dbus-server-unix.c (_dbus_server_new_for_domain_socket): +	support abstract sockets + +	* dbus/dbus-transport-unix.c +	(_dbus_transport_new_for_domain_socket): support abstract sockets + +	* dbus/dbus-sysdeps.c (_dbus_connect_unix_socket): add "abstract" +	toggle as an argument, implement abstract namespace support +	(_dbus_listen_unix_socket): ditto + +	* configure.in: add --enable-abstract-sockets and implement  +	a configure check for autodetection of the right value. +  2003-06-01  Havoc Pennington  <hp@pobox.com>  	* tools/dbus-cleanup-sockets.c: add utility to clean up sockets  diff --git a/bus/system.conf.in b/bus/system.conf.in index cab68d3a..bd454ff3 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -26,8 +26,11 @@    <!-- Only allow socket-credentials-based authentication -->    <auth>EXTERNAL</auth> -  <!-- Only listen on a local socket --> -  <listen>unix:path=@DBUS_SYSTEM_SOCKET@</listen> +  <!-- Only listen on a local socket. (abstract=/path/to/socket  +       means use abstract namespace, don't really create filesystem  +       file; only Linux supports this. Use path=/whatever on other  +       systems.) --> +  <listen>unix:@DBUS_PATH_OR_ABSTRACT@=@DBUS_SYSTEM_SOCKET@</listen>    <policy context="default">      <!-- Deny everything then punch holes --> diff --git a/configure.in b/configure.in index a47d1109..613bf2dc 100644 --- a/configure.in +++ b/configure.in @@ -23,15 +23,17 @@ AC_ISC_POSIX  AC_HEADER_STDC  AM_PROG_LIBTOOL -AC_ARG_ENABLE(qt,      [  --enable-qt      enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto) -AC_ARG_ENABLE(glib,    [  --enable-glib    enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto) -AC_ARG_ENABLE(tests,   [  --enable-tests   enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE) -AC_ARG_ENABLE(ansi,    [  --enable-ansi    enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) -AC_ARG_ENABLE(verbose-mode, [  --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) -AC_ARG_ENABLE(asserts, [  --enable-asserts include assertion checks],enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE) -AC_ARG_ENABLE(checks,  [  --enable-checks  include sanity checks on public API],enable_checks=$enableval,enable_checks=yes) -AC_ARG_ENABLE(docs,    [  --enable-docs    build documentation (requires Doxygen and jade)],enable_docs=$enableval,enable_docs=auto) -AC_ARG_ENABLE(gcov,    [  --enable-gcov    compile with coverage profiling instrumentation (gcc only)],enable_gcov=$enableval,enable_gcov=no) +AC_ARG_ENABLE(qt,               [  --enable-qt           enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto) +AC_ARG_ENABLE(glib,             [  --enable-glib         enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto) +AC_ARG_ENABLE(tests,            [  --enable-tests        enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(ansi,             [  --enable-ansi         enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) +AC_ARG_ENABLE(verbose-mode,     [  --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(asserts,          [  --enable-asserts      include assertion checks],enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(checks,           [  --enable-checks       include sanity checks on public API],enable_checks=$enableval,enable_checks=yes) +AC_ARG_ENABLE(docs,             [  --enable-docs         build documentation (requires Doxygen and jade)],enable_docs=$enableval,enable_docs=auto) +AC_ARG_ENABLE(gcov,             [  --enable-gcov         compile with coverage profiling instrumentation (gcc only)],enable_gcov=$enableval,enable_gcov=no) +AC_ARG_ENABLE(abstract-sockets, [  --enable-abstract-sockets  use abstract socket namespace (linux only)],enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) +  AC_ARG_WITH(xml,                [  --with-xml=[libxml/expat]           XML library to use])  AC_ARG_WITH(init-scripts,       [  --with-init-scripts=[redhat]        Style of init scripts to install]) @@ -317,6 +319,75 @@ if test x$dbus_have_struct_cmsgcred = xyes; then  fi +#### Abstract sockets + +AC_MSG_CHECKING(abstract socket namespace) +AC_LANG_PUSH(C) +AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> +]], +[[ +  int listen_fd; +  struct sockaddr_un addr; +   +  listen_fd = socket (PF_UNIX, SOCK_STREAM, 0); +   +  if (listen_fd < 0) +    { +      fprintf (stderr, "socket() failed: %s\n", strerror (errno)); +      exit (1); +    } + +  memset (&addr, '\0', sizeof (addr)); +  addr.sun_family = AF_UNIX; +  strcpy (addr.sun_path, "X/tmp/dbus-fake-socket-path-used-in-configure-test"); +  addr.sun_path[0] = '\0'; /* this is what makes it abstract */ +   +  if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) +    { +       fprintf (stderr, "Abstract socket namespace bind() failed: %s\n",  +                strerror (errno)); +       exit (1); +    } +  else  +    exit (0); +]])], +              [have_abstract_sockets=yes], +              [have_abstract_sockets=no]) +AC_LANG_POP(C) +AC_MSG_RESULT($have_abstract_sockets) + +if test x$enable_abstract_sockets = xyes; then +    if test x$have_abstract_sockets = xno; then +	AC_MSG_ERROR([Abstract sockets explicitly required, and support not detected.]) +    fi +fi + +if test x$enable_abstract_sockets = xno; then +   have_abstract_sockets=no; +fi + +if test x$have_abstract_sockets = xyes ; then +   abstract_sockets=1 +   DBUS_PATH_OR_ABSTRACT=abstract +else +   abstract_sockets=0 +   DBUS_PATH_OR_ABSTRACT=path +fi + +AC_DEFINE_UNQUOTED(HAVE_ABSTRACT_SOCKETS, $abstract_sockets, [Have abstract socket namespace]) + +# this is used in addresses to prefer abstract, e.g.  +# unix:path=/foo or unix:abstract=/foo  +AC_SUBST(DBUS_PATH_OR_ABSTRACT) +  #### Sort out XML library  # see what we have @@ -692,6 +763,7 @@ echo "          Building documentation:   ${enable_docs}          Using XML parser:         ${with_xml}          Init scripts style:       ${with_init_scripts} +        Abstract socket names:    ${have_abstract_sockets}          System bus socket:        ${DBUS_SYSTEM_SOCKET}          System bus PID file:      ${DBUS_SYSTEM_PID_FILE}          Session bus socket dir:   ${DBUS_SESSION_SOCKET_DIR} diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index fe4dbaa4..036446af 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -268,11 +268,13 @@ _dbus_server_new_for_fd (int               fd,   * Creates a new server listening on the given Unix domain socket.   *   * @param path the path for the domain socket. + * @param abstract #TRUE to use abstract socket namespace   * @param error location to store reason for failure.   * @returns the new server, or #NULL on failure.   */  DBusServer*  _dbus_server_new_for_domain_socket (const char     *path, +                                    dbus_bool_t     abstract,                                      DBusError      *error)  {    DBusServer *server; @@ -289,7 +291,10 @@ _dbus_server_new_for_domain_socket (const char     *path,        return NULL;      } -  if (!_dbus_string_append (&address, "unix:path=") || +  if ((abstract && +       !_dbus_string_append (&address, "unix:abstract=")) || +      (!abstract && +       !_dbus_string_append (&address, "unix:path=")) ||        !_dbus_string_append (&address, path))      {        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); @@ -303,7 +308,7 @@ _dbus_server_new_for_domain_socket (const char     *path,        goto failed_0;      } -  listen_fd = _dbus_listen_unix_socket (path, error); +  listen_fd = _dbus_listen_unix_socket (path, abstract, error);    _dbus_fd_set_close_on_exec (listen_fd);    if (listen_fd < 0) diff --git a/dbus/dbus-server-unix.h b/dbus/dbus-server-unix.h index 1d038db0..95f0b756 100644 --- a/dbus/dbus-server-unix.h +++ b/dbus/dbus-server-unix.h @@ -31,6 +31,7 @@ DBUS_BEGIN_DECLS;  DBusServer* _dbus_server_new_for_fd            (int               fd,                                                  const DBusString *address);  DBusServer* _dbus_server_new_for_domain_socket (const char       *path, +                                                dbus_bool_t       abstract,                                                  DBusError        *error);  DBusServer* _dbus_server_new_for_tcp_socket    (const char       *host,                                                  dbus_uint32_t     port, diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index e62c0284..4007d7a5 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -295,17 +295,20 @@ dbus_server_listen (const char     *address,  	{  	  const char *path = dbus_address_entry_get_value (entries[i], "path");            const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); +          const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); -	  if (path == NULL && tmpdir == NULL) +	  if (path == NULL && tmpdir == NULL && abstract == NULL)              {                address_problem_type = "unix"; -              address_problem_field = "path or tmpdir"; +              address_problem_field = "path or tmpdir or abstract";                goto bad_address;              } -          if (path && tmpdir) +          if ((path && tmpdir) || +              (path && abstract) || +              (tmpdir && abstract))              { -              address_problem_other = "cannot specify both \"path\" and \"tmpdir\" at the same time"; +              address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time";                goto bad_address;              } @@ -339,14 +342,22 @@ dbus_server_listen (const char     *address,                    goto out;                  } -              /* FIXME - we will unconditionally unlink() the path. -               * unlink() does not follow symlinks, but would like -               * independent confirmation this is safe enough. See -               * also _dbus_listen_unix_socket() and comments therein. +              /* FIXME - we will unconditionally unlink() the path if +               * we don't support abstract namespace.  unlink() does +               * not follow symlinks, but would like independent +               * confirmation this is safe enough. See also +               * _dbus_listen_unix_socket() and comments therein.                 */ + +              /* Always use abstract namespace if possible with tmpdir */                server =                  _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), +#ifdef HAVE_ABSTRACT_SOCKETS +                                                    TRUE, +#else +                                                    FALSE, +#endif                                                      error);                _dbus_string_free (&full_path); @@ -354,7 +365,10 @@ dbus_server_listen (const char     *address,              }            else              { -              server = _dbus_server_new_for_domain_socket (path, error); +              if (path) +                server = _dbus_server_new_for_domain_socket (path, FALSE, error); +              else +                server = _dbus_server_new_for_domain_socket (abstract, TRUE, error);              }  	}        else if (strcmp (method, "tcp") == 0) diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index ab79a722..35900d70 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -373,13 +373,19 @@ _dbus_write_two (int               fd,   * Creates a socket and connects it to the UNIX domain socket at the   * given path.  The connection fd is returned, and is set up as   * nonblocking. + *  + * Uses abstract sockets instead of filesystem-linked sockets if + * requested (it's possible only on Linux; see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails.   *   * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace   * @param error return location for error code   * @returns connection file descriptor or -1 on error   */  int  _dbus_connect_unix_socket (const char     *path, +                           dbus_bool_t     abstract,                             DBusError      *error)  {    int fd; @@ -401,7 +407,23 @@ _dbus_connect_unix_socket (const char     *path,    _DBUS_ZERO (addr);    addr.sun_family = AF_UNIX; -  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); + +  if (abstract) +    { +#ifdef HAVE_ABSTRACT_SOCKETS +      addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ +      strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2); +#else /* HAVE_ABSTRACT_SOCKETS */ +      dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, +                      "Operating system does not support abstract socket namespace\n"); +      close (fd); +      return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */       +    } +  else +    { +      strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); +    }    if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)      {       @@ -434,18 +456,19 @@ _dbus_connect_unix_socket (const char     *path,   * then listens on the socket. The socket is   * set to be nonblocking.   * - * @todo we'd like to be able to use the abstract namespace on linux - * (see "man 7 unix"). The question is whether to silently move all - * paths into that namespace if we can (I think that's best) or to - * require it to be specified explicitly in the dbus address.  Also, - * need to sort out how to check for abstract namespace support. + * Uses abstract sockets instead of filesystem-linked + * sockets if requested (it's possible only on Linux; + * see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails.   *   * @param path the socket name + * @param abstract #TRUE to use abstract namespace   * @param error return location for errors   * @returns the listening file descriptor or -1 on error   */  int  _dbus_listen_unix_socket (const char     *path, +                          dbus_bool_t     abstract,                            DBusError      *error)  {    int listen_fd; @@ -463,27 +486,43 @@ _dbus_listen_unix_socket (const char     *path,        return -1;      } -  /* FIXME discussed security implications of this with Nalin, -   * and we couldn't think of where it would kick our ass, but -   * it still seems a bit sucky. It also has non-security suckage; -   * really we'd prefer to exit if the socket is already in use. -   * But there doesn't seem to be a good way to do this. -   * -   * Just to be extra careful, I threw in the stat() - clearly -   * the stat() can't *fix* any security issue, but it at least -   * avoids inadvertent/accidental data loss. -   */ -  { -    struct stat sb; - -    if (stat (path, &sb) == 0 && -        S_ISSOCK (sb.st_mode)) -      unlink (path); -  } -      _DBUS_ZERO (addr);    addr.sun_family = AF_UNIX; -  strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); +   +  if (abstract) +    { +#ifdef HAVE_ABSTRACT_SOCKETS +      addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ +      strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2); +#else /* HAVE_ABSTRACT_SOCKETS */ +      dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, +                      "Operating system does not support abstract socket namespace\n"); +      close (listen_fd); +      return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */ +    } +  else +    { +      /* FIXME discussed security implications of this with Nalin, +       * and we couldn't think of where it would kick our ass, but +       * it still seems a bit sucky. It also has non-security suckage; +       * really we'd prefer to exit if the socket is already in use. +       * But there doesn't seem to be a good way to do this. +       * +       * Just to be extra careful, I threw in the stat() - clearly +       * the stat() can't *fix* any security issue, but it at least +       * avoids inadvertent/accidental data loss. +       */ +      { +        struct stat sb; + +        if (stat (path, &sb) == 0 && +            S_ISSOCK (sb.st_mode)) +          unlink (path); +      } + +      strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); +    }    if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)      { @@ -513,7 +552,7 @@ _dbus_listen_unix_socket (const char     *path,    /* Try opening up the permissions, but if we can't, just go ahead     * and continue, maybe it will be good enough.     */ -  if (chmod (path, 0777) < 0) +  if (!abstract && chmod (path, 0777) < 0)      _dbus_warn ("Could not set mode 0777 on socket %s\n",                  path); diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 7a4696f3..cfe0cd25 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -105,8 +105,10 @@ typedef struct  } DBusCredentials;  int _dbus_connect_unix_socket (const char     *path, +                               dbus_bool_t     abstract,                                 DBusError      *error);  int _dbus_listen_unix_socket  (const char     *path, +                               dbus_bool_t     abstract,                                 DBusError      *error);  int _dbus_connect_tcp_socket  (const char     *host,                                 dbus_uint32_t   port, diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 5df1c461..e5e446c2 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -1080,12 +1080,17 @@ _dbus_transport_new_for_fd (int               fd,   * Creates a new transport for the given Unix domain socket   * path. This creates a client-side of a transport.   * + * @todo once we add a way to escape paths in a dbus + * address, this function needs to do escaping. + *   * @param path the path to the domain socket. + * @param abstract #TRUE to use abstract socket namespace   * @param error address where an error can be returned.   * @returns a new transport, or #NULL on failure.   */  DBusTransport*  _dbus_transport_new_for_domain_socket (const char     *path, +                                       dbus_bool_t     abstract,                                         DBusError      *error)  {    int fd; @@ -1101,15 +1106,18 @@ _dbus_transport_new_for_domain_socket (const char     *path,      }    fd = -1; -   -  if (!_dbus_string_append (&address, "unix:path=") || + +  if ((abstract && +       !_dbus_string_append (&address, "unix:abstract=")) || +      (!abstract && +       !_dbus_string_append (&address, "unix:path=")) ||        !_dbus_string_append (&address, path))      {        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);        goto failed_0;      } -  fd = _dbus_connect_unix_socket (path, error); +  fd = _dbus_connect_unix_socket (path, abstract, error);    if (fd < 0)      {        _DBUS_ASSERT_ERROR_IS_SET (error); diff --git a/dbus/dbus-transport-unix.h b/dbus/dbus-transport-unix.h index ef7ac9b1..8d3f5b10 100644 --- a/dbus/dbus-transport-unix.h +++ b/dbus/dbus-transport-unix.h @@ -31,6 +31,7 @@ DBusTransport* _dbus_transport_new_for_fd            (int               fd,                                                        dbus_bool_t       server,                                                        const DBusString *address);  DBusTransport* _dbus_transport_new_for_domain_socket (const char       *path, +                                                      dbus_bool_t       abstract,                                                        DBusError        *error);  DBusTransport* _dbus_transport_new_for_tcp_socket    (const char       *host,                                                        dbus_int32_t      port, diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index af1cb421..59ec6ea1 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -243,21 +243,33 @@ _dbus_transport_open (const char     *address,  	{  	  const char *path = dbus_address_entry_get_value (entries[i], "path");            const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); - +          const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); +            	  if (tmpdir != NULL)              {                address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";                goto bad_address;              } -	  if (path == NULL) +	  if (path == NULL && abstract == NULL)              {                address_problem_type = "unix"; -              address_problem_field = "path";               +              address_problem_field = "path or abstract";                  goto bad_address;              } -          transport = _dbus_transport_new_for_domain_socket (path, &tmp_error); +	  if (path != NULL && abstract != NULL) +            { +              address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address"; +              goto bad_address; +            } + +          if (path) +            transport = _dbus_transport_new_for_domain_socket (path, FALSE, +                                                               &tmp_error); +          else +            transport = _dbus_transport_new_for_domain_socket (abstract, TRUE, +                                                               &tmp_error);  	}        else if (strcmp (method, "tcp") == 0)  	{ diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index d510ca6a..8b3a1d36 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -898,11 +898,10 @@      </para>      <para>        [FIXME we need to specify in detail each transport and its possible arguments] -      Currently, a transport over local UNIX sockets exists, a debug -      transport that only works in-process and therefore can be used -      for for unit testing also exists. It is possible that other -      transports are added, such as a TCP/IP transport, and a -      transport that works over X11. +      Current transports include: unix domain sockets (including  +      abstract namespace on linux), TCP/IP, and a debug/testing transport using  +      in-process pipes. Future possible transports include one that  +      tunnels over X11 protocol.      </para>    </sect1> | 
