D-Bus  1.10.12
dbus-server-unix.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-server-unix.c Server implementation for Unix network protocols.
00003  *
00004  * Copyright (C) 2002, 2003, 2004  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-server-unix.h"
00027 #include "dbus-server-socket.h"
00028 #include "dbus-server-launchd.h"
00029 #include "dbus-transport-unix.h"
00030 #include "dbus-connection-internal.h"
00031 #include "dbus-sysdeps-unix.h"
00032 #include "dbus-string.h"
00033 
00053 DBusServerListenResult
00054 _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
00055                                        DBusServer      **server_p,
00056                                        DBusError        *error)
00057 {
00058   const char *method;
00059 
00060   *server_p = NULL;
00061 
00062   method = dbus_address_entry_get_method (entry);
00063 
00064   if (strcmp (method, "unix") == 0)
00065     {
00066       const char *path = dbus_address_entry_get_value (entry, "path");
00067       const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
00068       const char *abstract = dbus_address_entry_get_value (entry, "abstract");
00069       const char *runtime = dbus_address_entry_get_value (entry, "runtime");
00070       int mutually_exclusive_modes = 0;
00071 
00072       mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
00073         (abstract != NULL) + (runtime != NULL);
00074 
00075       if (mutually_exclusive_modes < 1)
00076         {
00077           _dbus_set_bad_address(error, "unix",
00078                                 "path or tmpdir or abstract or runtime",
00079                                 NULL);
00080           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
00081         }
00082 
00083       if (mutually_exclusive_modes > 1)
00084         {
00085           _dbus_set_bad_address(error, NULL, NULL,
00086                                 "cannot specify two of \"path\", \"tmpdir\", \"abstract\" and \"runtime\" at the same time");
00087           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
00088         }
00089 
00090       if (runtime != NULL)
00091         {
00092           DBusString full_path;
00093           DBusString filename;
00094           const char *runtimedir;
00095 
00096           if (strcmp (runtime, "yes") != 0)
00097             {
00098               _dbus_set_bad_address(error, NULL, NULL,
00099                   "if given, the only value allowed for \"runtime\" is \"yes\"");
00100               return DBUS_SERVER_LISTEN_BAD_ADDRESS;
00101             }
00102 
00103           runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
00104 
00105           if (runtimedir == NULL)
00106             {
00107               dbus_set_error (error,
00108                   DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
00109               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00110             }
00111 
00112           _dbus_string_init_const (&filename, "bus");
00113 
00114           if (!_dbus_string_init (&full_path))
00115             {
00116               _DBUS_SET_OOM (error);
00117               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00118             }
00119 
00120           if (!_dbus_string_append (&full_path, runtimedir) ||
00121               !_dbus_concat_dir_and_file (&full_path, &filename))
00122             {
00123               _dbus_string_free (&full_path);
00124               _DBUS_SET_OOM (error);
00125               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00126             }
00127 
00128           /* We can safely use filesystem sockets in the runtime directory,
00129            * and they are preferred because they can be bind-mounted between
00130            * Linux containers. */
00131           *server_p = _dbus_server_new_for_domain_socket (
00132               _dbus_string_get_const_data (&full_path),
00133               FALSE, error);
00134 
00135           _dbus_string_free (&full_path);
00136         }
00137       else if (tmpdir != NULL)
00138         {
00139           DBusString full_path;
00140           DBusString filename;
00141 
00142           if (!_dbus_string_init (&full_path))
00143             {
00144               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00145               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00146             }
00147 
00148           if (!_dbus_string_init (&filename))
00149             {
00150               _dbus_string_free (&full_path);
00151               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00152               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00153             }
00154 
00155           if (!_dbus_string_append (&filename, "dbus-"))
00156             {
00157               _dbus_string_free (&full_path);
00158               _dbus_string_free (&filename);
00159               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00160               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00161             }
00162 
00163           if (!_dbus_generate_random_ascii (&filename, 10, error))
00164             {
00165               _dbus_string_free (&full_path);
00166               _dbus_string_free (&filename);
00167               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00168             }
00169 
00170           if (!_dbus_string_append (&full_path, tmpdir) ||
00171               !_dbus_concat_dir_and_file (&full_path, &filename))
00172             {
00173               _dbus_string_free (&full_path);
00174               _dbus_string_free (&filename);
00175               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00176               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00177             }
00178 
00179           /* Always use abstract namespace if possible with tmpdir */
00180 
00181           *server_p =
00182             _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
00183 #ifdef HAVE_ABSTRACT_SOCKETS
00184                                                 TRUE,
00185 #else
00186                                                 FALSE,
00187 #endif
00188                                                 error);
00189 
00190           _dbus_string_free (&full_path);
00191           _dbus_string_free (&filename);
00192         }
00193       else
00194         {
00195           if (path)
00196             *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
00197           else
00198             *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
00199         }
00200 
00201       if (*server_p != NULL)
00202         {
00203           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
00204           return DBUS_SERVER_LISTEN_OK;
00205         }
00206       else
00207         {
00208           _DBUS_ASSERT_ERROR_IS_SET(error);
00209           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00210         }
00211     }
00212   else if (strcmp (method, "systemd") == 0)
00213     {
00214       int i, n;
00215       DBusSocket *fds;
00216       DBusString address;
00217 
00218       n = _dbus_listen_systemd_sockets (&fds, error);
00219       if (n < 0)
00220         {
00221           _DBUS_ASSERT_ERROR_IS_SET (error);
00222           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00223         }
00224 
00225       if (!_dbus_string_init (&address))
00226           goto systemd_oom;
00227 
00228       for (i = 0; i < n; i++)
00229         {
00230           if (i > 0)
00231             {
00232               if (!_dbus_string_append (&address, ";"))
00233                 goto systemd_oom;
00234             }
00235           if (!_dbus_append_address_from_socket (fds[i], &address, error))
00236             goto systemd_err;
00237         }
00238 
00239       *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error);
00240       if (*server_p == NULL)
00241         goto systemd_err;
00242 
00243       dbus_free (fds);
00244 
00245       return DBUS_SERVER_LISTEN_OK;
00246 
00247   systemd_oom:
00248       _DBUS_SET_OOM (error);
00249   systemd_err:
00250       for (i = 0; i < n; i++)
00251         {
00252           _dbus_close_socket (fds[i], NULL);
00253         }
00254       dbus_free (fds);
00255       _dbus_string_free (&address);
00256 
00257       return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00258     }
00259 #ifdef DBUS_ENABLE_LAUNCHD
00260   else if (strcmp (method, "launchd") == 0)
00261     {
00262       const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
00263       if (launchd_env_var == NULL)
00264         {
00265           _dbus_set_bad_address (error, "launchd", "env", NULL);
00266           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00267         }
00268       *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);
00269 
00270       if (*server_p != NULL)
00271         {
00272           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
00273           return DBUS_SERVER_LISTEN_OK;
00274         }
00275       else
00276         {
00277           _DBUS_ASSERT_ERROR_IS_SET(error);
00278           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
00279         }
00280     }
00281 #endif
00282   else
00283     {
00284       /* If we don't handle the method, we return NULL with the
00285        * error unset
00286        */
00287       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
00288       return DBUS_SERVER_LISTEN_NOT_HANDLED;
00289     }
00290 }
00291 
00300 DBusServer*
00301 _dbus_server_new_for_domain_socket (const char     *path,
00302                                     dbus_bool_t     abstract,
00303                                     DBusError      *error)
00304 {
00305   DBusServer *server;
00306   DBusSocket listen_fd;
00307   DBusString address;
00308   char *path_copy;
00309   DBusString path_str;
00310 
00311   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00312 
00313   if (!_dbus_string_init (&address))
00314     {
00315       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00316       return NULL;
00317     }
00318 
00319   _dbus_string_init_const (&path_str, path);
00320   if ((abstract &&
00321        !_dbus_string_append (&address, "unix:abstract=")) ||
00322       (!abstract &&
00323        !_dbus_string_append (&address, "unix:path=")) ||
00324       !_dbus_address_append_escaped (&address, &path_str))
00325     {
00326       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00327       goto failed_0;
00328     }
00329 
00330   if (abstract)
00331     {
00332       path_copy = NULL;
00333     }
00334   else
00335     {
00336       path_copy = _dbus_strdup (path);
00337       if (path_copy == NULL)
00338         {
00339           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00340           goto failed_0;
00341         }
00342     }
00343 
00344   listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
00345 
00346   if (listen_fd.fd < 0)
00347     {
00348       _DBUS_ASSERT_ERROR_IS_SET (error);
00349       goto failed_1;
00350     }
00351 
00352   server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
00353   if (server == NULL)
00354     {
00355       goto failed_2;
00356     }
00357 
00358   if (path_copy != NULL)
00359     _dbus_server_socket_own_filename(server, path_copy);
00360 
00361   _dbus_string_free (&address);
00362 
00363   return server;
00364 
00365  failed_2:
00366   _dbus_close_socket (listen_fd, NULL);
00367  failed_1:
00368   dbus_free (path_copy);
00369  failed_0:
00370   _dbus_string_free (&address);
00371 
00372   return NULL;
00373 }
00374