Merge branch 'dbus-1.10'
[platform/upstream/dbus.git] / dbus / dbus-server-unix.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-server-unix.c Server implementation for Unix network protocols.
3  *
4  * Copyright (C) 2002, 2003, 2004  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #include <config.h>
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"
33
34 /**
35  * @defgroup DBusServerUnix DBusServer implementations for UNIX
36  * @ingroup  DBusInternals
37  * @brief Implementation details of DBusServer on UNIX
38  *
39  * @{
40  */
41
42 /**
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.
46  *
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
51  *
52  */
53 DBusServerListenResult
54 _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
55                                        DBusServer      **server_p,
56                                        DBusError        *error)
57 {
58   const char *method;
59
60   *server_p = NULL;
61
62   method = dbus_address_entry_get_method (entry);
63
64   if (strcmp (method, "unix") == 0)
65     {
66       const char *path = dbus_address_entry_get_value (entry, "path");
67       const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
68       const char *abstract = dbus_address_entry_get_value (entry, "abstract");
69       const char *runtime = dbus_address_entry_get_value (entry, "runtime");
70       int mutually_exclusive_modes = 0;
71
72       mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
73         (abstract != NULL) + (runtime != NULL);
74
75       if (mutually_exclusive_modes < 1)
76         {
77           _dbus_set_bad_address(error, "unix",
78                                 "path or tmpdir or abstract or runtime",
79                                 NULL);
80           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
81         }
82
83       if (mutually_exclusive_modes > 1)
84         {
85           _dbus_set_bad_address(error, NULL, NULL,
86                                 "cannot specify two of \"path\", \"tmpdir\", \"abstract\" and \"runtime\" at the same time");
87           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
88         }
89
90       if (runtime != NULL)
91         {
92           DBusString full_path;
93           DBusString filename;
94           const char *runtimedir;
95
96           if (strcmp (runtime, "yes") != 0)
97             {
98               _dbus_set_bad_address(error, NULL, NULL,
99                   "if given, the only value allowed for \"runtime\" is \"yes\"");
100               return DBUS_SERVER_LISTEN_BAD_ADDRESS;
101             }
102
103           runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
104
105           if (runtimedir == NULL)
106             {
107               dbus_set_error (error,
108                   DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
109               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
110             }
111
112           _dbus_string_init_const (&filename, "bus");
113
114           if (!_dbus_string_init (&full_path))
115             {
116               _DBUS_SET_OOM (error);
117               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
118             }
119
120           if (!_dbus_string_append (&full_path, runtimedir) ||
121               !_dbus_concat_dir_and_file (&full_path, &filename))
122             {
123               _dbus_string_free (&full_path);
124               _DBUS_SET_OOM (error);
125               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
126             }
127
128           /* We can safely use filesystem sockets in the runtime directory,
129            * and they are preferred because they can be bind-mounted between
130            * Linux containers. */
131           *server_p = _dbus_server_new_for_domain_socket (
132               _dbus_string_get_const_data (&full_path),
133               FALSE, error);
134
135           _dbus_string_free (&full_path);
136         }
137       else if (tmpdir != NULL)
138         {
139           DBusString full_path;
140           DBusString filename;
141
142           if (!_dbus_string_init (&full_path))
143             {
144               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
145               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
146             }
147
148           if (!_dbus_string_init (&filename))
149             {
150               _dbus_string_free (&full_path);
151               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
152               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
153             }
154
155           if (!_dbus_string_append (&filename, "dbus-"))
156             {
157               _dbus_string_free (&full_path);
158               _dbus_string_free (&filename);
159               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
160               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
161             }
162
163           if (!_dbus_generate_random_ascii (&filename, 10, error))
164             {
165               _dbus_string_free (&full_path);
166               _dbus_string_free (&filename);
167               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
168             }
169
170           if (!_dbus_string_append (&full_path, tmpdir) ||
171               !_dbus_concat_dir_and_file (&full_path, &filename))
172             {
173               _dbus_string_free (&full_path);
174               _dbus_string_free (&filename);
175               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
176               return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
177             }
178
179           /* Always use abstract namespace if possible with tmpdir */
180
181           *server_p =
182             _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
183 #ifdef HAVE_ABSTRACT_SOCKETS
184                                                 TRUE,
185 #else
186                                                 FALSE,
187 #endif
188                                                 error);
189
190           _dbus_string_free (&full_path);
191           _dbus_string_free (&filename);
192         }
193       else
194         {
195           if (path)
196             *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
197           else
198             *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
199         }
200
201       if (*server_p != NULL)
202         {
203           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
204           return DBUS_SERVER_LISTEN_OK;
205         }
206       else
207         {
208           _DBUS_ASSERT_ERROR_IS_SET(error);
209           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
210         }
211     }
212   else if (strcmp (method, "systemd") == 0)
213     {
214       int i, n;
215       DBusSocket *fds;
216       DBusString address;
217
218       n = _dbus_listen_systemd_sockets (&fds, error);
219       if (n < 0)
220         {
221           _DBUS_ASSERT_ERROR_IS_SET (error);
222           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
223         }
224
225       if (!_dbus_string_init (&address))
226           goto systemd_oom;
227
228       for (i = 0; i < n; i++)
229         {
230           if (i > 0)
231             {
232               if (!_dbus_string_append (&address, ";"))
233                 goto systemd_oom;
234             }
235           if (!_dbus_append_address_from_socket (fds[i], &address, error))
236             goto systemd_err;
237         }
238
239       *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error);
240       if (*server_p == NULL)
241         goto systemd_err;
242
243       dbus_free (fds);
244
245       return DBUS_SERVER_LISTEN_OK;
246
247   systemd_oom:
248       _DBUS_SET_OOM (error);
249   systemd_err:
250       for (i = 0; i < n; i++)
251         {
252           _dbus_close_socket (fds[i], NULL);
253         }
254       dbus_free (fds);
255       _dbus_string_free (&address);
256
257       return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
258     }
259 #ifdef DBUS_ENABLE_LAUNCHD
260   else if (strcmp (method, "launchd") == 0)
261     {
262       const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
263       if (launchd_env_var == NULL)
264         {
265           _dbus_set_bad_address (error, "launchd", "env", NULL);
266           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
267         }
268       *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);
269
270       if (*server_p != NULL)
271         {
272           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
273           return DBUS_SERVER_LISTEN_OK;
274         }
275       else
276         {
277           _DBUS_ASSERT_ERROR_IS_SET(error);
278           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
279         }
280     }
281 #endif
282   else
283     {
284       /* If we don't handle the method, we return NULL with the
285        * error unset
286        */
287       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
288       return DBUS_SERVER_LISTEN_NOT_HANDLED;
289     }
290 }
291
292 /**
293  * Creates a new server listening on the given Unix domain socket.
294  *
295  * @param path the path for the domain socket.
296  * @param abstract #TRUE to use abstract socket namespace
297  * @param error location to store reason for failure.
298  * @returns the new server, or #NULL on failure.
299  */
300 DBusServer*
301 _dbus_server_new_for_domain_socket (const char     *path,
302                                     dbus_bool_t     abstract,
303                                     DBusError      *error)
304 {
305   DBusServer *server;
306   DBusSocket listen_fd;
307   DBusString address;
308   char *path_copy;
309   DBusString path_str;
310
311   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
312
313   if (!_dbus_string_init (&address))
314     {
315       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
316       return NULL;
317     }
318
319   _dbus_string_init_const (&path_str, path);
320   if ((abstract &&
321        !_dbus_string_append (&address, "unix:abstract=")) ||
322       (!abstract &&
323        !_dbus_string_append (&address, "unix:path=")) ||
324       !_dbus_address_append_escaped (&address, &path_str))
325     {
326       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
327       goto failed_0;
328     }
329
330   if (abstract)
331     {
332       path_copy = NULL;
333     }
334   else
335     {
336       path_copy = _dbus_strdup (path);
337       if (path_copy == NULL)
338         {
339           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
340           goto failed_0;
341         }
342     }
343
344   listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
345
346   if (listen_fd.fd < 0)
347     {
348       _DBUS_ASSERT_ERROR_IS_SET (error);
349       goto failed_1;
350     }
351
352   server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
353   if (server == NULL)
354     {
355       goto failed_2;
356     }
357
358   if (path_copy != NULL)
359     _dbus_server_socket_own_filename(server, path_copy);
360
361   _dbus_string_free (&address);
362
363   return server;
364
365  failed_2:
366   _dbus_close_socket (listen_fd, NULL);
367  failed_1:
368   dbus_free (path_copy);
369  failed_0:
370   _dbus_string_free (&address);
371
372   return NULL;
373 }
374
375 /** @} */