1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-server-unix.c Server implementation for Unix network protocols.
4 * Copyright (C) 2002, 2003, 2004 Red Hat Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "dbus-internals.h"
26 #include "dbus-server-unix.h"
27 #include "dbus-server-socket.h"
28 #include "dbus-server-launchd.h"
29 #include "dbus-transport-unix.h"
30 #include "dbus-connection-internal.h"
31 #include "dbus-sysdeps-unix.h"
32 #include "dbus-string.h"
35 * @defgroup DBusServerUnix DBusServer implementations for UNIX
36 * @ingroup DBusInternals
37 * @brief Implementation details of DBusServer on UNIX
43 * Tries to interpret the address entry in a platform-specific
44 * way, creating a platform-specific server type if appropriate.
45 * Sets error if the result is not OK.
47 * @param entry an address entry
48 * @param server_p location to store a new DBusServer, or #NULL on failure.
49 * @param error location to store rationale for failure on bad address
50 * @returns the outcome
53 DBusServerListenResult
54 _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
55 DBusServer **server_p,
62 method = dbus_address_entry_get_method (entry);
64 if (strcmp (method, "unix") == 0)
66 const char *path = dbus_address_entry_get_value (entry, "path");
67 const char *dir = dbus_address_entry_get_value (entry, "dir");
68 const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
69 const char *abstract = dbus_address_entry_get_value (entry, "abstract");
70 const char *runtime = dbus_address_entry_get_value (entry, "runtime");
71 int mutually_exclusive_modes = 0;
73 mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
74 (abstract != NULL) + (runtime != NULL) + (dir != NULL);
76 if (mutually_exclusive_modes < 1)
78 _dbus_set_bad_address(error, "unix",
79 "path or tmpdir or abstract or runtime or dir",
81 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
84 if (mutually_exclusive_modes > 1)
86 _dbus_set_bad_address(error, NULL, NULL,
87 "cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time");
88 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
95 const char *runtimedir;
97 if (strcmp (runtime, "yes") != 0)
99 _dbus_set_bad_address(error, NULL, NULL,
100 "if given, the only value allowed for \"runtime\" is \"yes\"");
101 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
104 runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
106 if (runtimedir == NULL)
108 dbus_set_error (error,
109 DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
110 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
113 _dbus_string_init_const (&filename, "bus");
115 if (!_dbus_string_init (&full_path))
117 _DBUS_SET_OOM (error);
118 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
121 if (!_dbus_string_append (&full_path, runtimedir) ||
122 !_dbus_concat_dir_and_file (&full_path, &filename))
124 _dbus_string_free (&full_path);
125 _DBUS_SET_OOM (error);
126 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
129 /* We can safely use filesystem sockets in the runtime directory,
130 * and they are preferred because they can be bind-mounted between
131 * Linux containers. */
132 *server_p = _dbus_server_new_for_domain_socket (
133 _dbus_string_get_const_data (&full_path),
136 _dbus_string_free (&full_path);
138 else if (tmpdir != NULL || dir != NULL)
140 DBusString full_path;
142 dbus_bool_t use_abstract = FALSE;
149 /* Use abstract sockets for tmpdir if supported, so that it
150 * never needs to be cleaned up. Use dir instead if you want a
151 * path-based socket. */
156 if (!_dbus_string_init (&full_path))
158 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
159 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
162 if (!_dbus_string_init (&filename))
164 _dbus_string_free (&full_path);
165 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
166 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
169 if (!_dbus_string_append (&filename, "dbus-"))
171 _dbus_string_free (&full_path);
172 _dbus_string_free (&filename);
173 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
174 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
177 if (!_dbus_generate_random_ascii (&filename, 10, error))
179 _dbus_string_free (&full_path);
180 _dbus_string_free (&filename);
181 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
184 if (!_dbus_string_append (&full_path, dir) ||
185 !_dbus_concat_dir_and_file (&full_path, &filename))
187 _dbus_string_free (&full_path);
188 _dbus_string_free (&filename);
189 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
190 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
194 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
198 _dbus_string_free (&full_path);
199 _dbus_string_free (&filename);
204 *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
206 *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
209 if (*server_p != NULL)
211 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
212 return DBUS_SERVER_LISTEN_OK;
216 _DBUS_ASSERT_ERROR_IS_SET(error);
217 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
220 else if (strcmp (method, "systemd") == 0)
226 n = _dbus_listen_systemd_sockets (&fds, error);
229 _DBUS_ASSERT_ERROR_IS_SET (error);
230 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
233 if (!_dbus_string_init (&address))
236 for (i = 0; i < n; i++)
240 if (!_dbus_string_append (&address, ";"))
243 if (!_dbus_append_address_from_socket (fds[i], &address, error))
247 *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error);
248 if (*server_p == NULL)
252 _dbus_string_free (&address);
254 return DBUS_SERVER_LISTEN_OK;
257 _DBUS_SET_OOM (error);
259 for (i = 0; i < n; i++)
261 _dbus_close_socket (fds[i], NULL);
264 _dbus_string_free (&address);
266 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
268 #ifdef DBUS_ENABLE_LAUNCHD
269 else if (strcmp (method, "launchd") == 0)
271 const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
272 if (launchd_env_var == NULL)
274 _dbus_set_bad_address (error, "launchd", "env", NULL);
275 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
277 *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);
279 if (*server_p != NULL)
281 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
282 return DBUS_SERVER_LISTEN_OK;
286 _DBUS_ASSERT_ERROR_IS_SET(error);
287 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
293 /* If we don't handle the method, we return NULL with the
296 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
297 return DBUS_SERVER_LISTEN_NOT_HANDLED;
302 * Creates a new server listening on the given Unix domain socket.
304 * @param path the path for the domain socket.
305 * @param abstract #TRUE to use abstract socket namespace
306 * @param error location to store reason for failure.
307 * @returns the new server, or #NULL on failure.
310 _dbus_server_new_for_domain_socket (const char *path,
311 dbus_bool_t abstract,
315 DBusSocket listen_fd;
320 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
322 if (!_dbus_string_init (&address))
324 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
328 _dbus_string_init_const (&path_str, path);
330 !_dbus_string_append (&address, "unix:abstract=")) ||
332 !_dbus_string_append (&address, "unix:path=")) ||
333 !_dbus_address_append_escaped (&address, &path_str))
335 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
345 path_copy = _dbus_strdup (path);
346 if (path_copy == NULL)
348 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
353 listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
355 if (listen_fd.fd < 0)
357 _DBUS_ASSERT_ERROR_IS_SET (error);
361 server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
367 if (path_copy != NULL)
368 _dbus_server_socket_own_filename(server, path_copy);
370 _dbus_string_free (&address);
375 _dbus_close_socket (listen_fd, NULL);
377 dbus_free (path_copy);
379 _dbus_string_free (&address);