D-Bus 1.14.8
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#ifdef HAVE_PDPLINUX
35#include <parsec/pdp.h>
36//#include <parsec/cap.h>
37#include <parsec/parsec_cap.h>
38
39int pdplinux_capability_set_socket_from_current_process(const char *path, int sockfd);
40int pdplinux_capability_set_apply_socket(parsec_cap_t set, int sockfd);
41
42#endif
43
63DBusServerListenResult
65 DBusServer **server_p,
66 DBusError *error)
67{
68 const char *method;
69
70 *server_p = NULL;
71
72 method = dbus_address_entry_get_method (entry);
73
74 if (strcmp (method, "unix") == 0)
75 {
76 const char *path = dbus_address_entry_get_value (entry, "path");
77 const char *dir = dbus_address_entry_get_value (entry, "dir");
78 const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
79 const char *abstract = dbus_address_entry_get_value (entry, "abstract");
80 const char *runtime = dbus_address_entry_get_value (entry, "runtime");
81 int mutually_exclusive_modes = 0;
82
83 mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
84 (abstract != NULL) + (runtime != NULL) + (dir != NULL);
85
86 if (mutually_exclusive_modes < 1)
87 {
88 _dbus_set_bad_address(error, "unix",
89 "path or tmpdir or abstract or runtime or dir",
90 NULL);
91 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
92 }
93
94 if (mutually_exclusive_modes > 1)
95 {
97 "cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time");
98 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
99 }
100
101 if (runtime != NULL)
102 {
103 DBusString full_path;
104 DBusString filename;
105 const char *runtimedir;
106
107 if (strcmp (runtime, "yes") != 0)
108 {
110 "if given, the only value allowed for \"runtime\" is \"yes\"");
111 return DBUS_SERVER_LISTEN_BAD_ADDRESS;
112 }
113
114 runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
115
116 if (runtimedir == NULL)
117 {
118 dbus_set_error (error,
119 DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
120 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
121 }
122
123 _dbus_string_init_const (&filename, "bus");
124
125 if (!_dbus_string_init (&full_path))
126 {
127 _DBUS_SET_OOM (error);
128 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
129 }
130
131 if (!_dbus_string_append (&full_path, runtimedir) ||
132 !_dbus_concat_dir_and_file (&full_path, &filename))
133 {
134 _dbus_string_free (&full_path);
135 _DBUS_SET_OOM (error);
136 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
137 }
138
139 /* We can safely use filesystem sockets in the runtime directory,
140 * and they are preferred because they can be bind-mounted between
141 * Linux containers. */
143 _dbus_string_get_const_data (&full_path),
144 FALSE, error);
145
146 _dbus_string_free (&full_path);
147 }
148 else if (tmpdir != NULL || dir != NULL)
149 {
150 DBusString full_path;
151 DBusString filename;
152
153 /* tmpdir is now equivalent to dir. Previously it would try to
154 * use an abstract socket. */
155 if (tmpdir != NULL)
156 dir = tmpdir;
157
158 if (!_dbus_string_init (&full_path))
159 {
161 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
162 }
163
164 if (!_dbus_string_init (&filename))
165 {
166 _dbus_string_free (&full_path);
168 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
169 }
170
171 if (!_dbus_string_append (&filename, "dbus-"))
172 {
173 _dbus_string_free (&full_path);
174 _dbus_string_free (&filename);
176 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
177 }
178
179 if (!_dbus_generate_random_ascii (&filename, 10, error))
180 {
181 _dbus_string_free (&full_path);
182 _dbus_string_free (&filename);
183 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
184 }
185
186 if (!_dbus_string_append (&full_path, dir) ||
187 !_dbus_concat_dir_and_file (&full_path, &filename))
188 {
189 _dbus_string_free (&full_path);
190 _dbus_string_free (&filename);
192 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
193 }
194
195 *server_p =
196 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
197 FALSE,
198 error);
199
200 _dbus_string_free (&full_path);
201 _dbus_string_free (&filename);
202 }
203 else
204 {
205 if (path)
206 *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
207 else
208 *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
209 }
210
211 if (*server_p != NULL)
212 {
213 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
214 return DBUS_SERVER_LISTEN_OK;
215 }
216 else
217 {
218 _DBUS_ASSERT_ERROR_IS_SET(error);
219 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
220 }
221 }
222 else if (strcmp (method, "systemd") == 0)
223 {
224 int i, n;
225 DBusSocket *fds;
226 DBusString address;
227
228 n = _dbus_listen_systemd_sockets (&fds, error);
229 if (n < 0)
230 {
231 _DBUS_ASSERT_ERROR_IS_SET (error);
232 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
233 }
234
235 if (!_dbus_string_init (&address))
236 goto systemd_oom;
237
238 for (i = 0; i < n; i++)
239 {
240 if (i > 0)
241 {
242 if (!_dbus_string_append (&address, ";"))
243 goto systemd_oom;
244 }
245 if (!_dbus_append_address_from_socket (fds[i], &address, error))
246 goto systemd_err;
247#ifdef HAVE_PDPLINUX
248 _dbus_verbose("parsec privsock: process to set Special label: fds[i] = %d (%d of %d) address=%s (NSP)\n",
249 fds[i].fd, i, n, _dbus_string_get_const_data(&address));
250 pdplinux_capability_set_socket_from_current_process(_dbus_string_get_const_data(&address),fds[i].fd);
251#endif
252 }
253
254 *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL, error);
255 if (*server_p == NULL)
256 goto systemd_err;
257
258 dbus_free (fds);
259 _dbus_string_free (&address);
260
261 return DBUS_SERVER_LISTEN_OK;
262
263 systemd_oom:
264 _DBUS_SET_OOM (error);
265 systemd_err:
266 for (i = 0; i < n; i++)
267 {
268 _dbus_close_socket (fds[i], NULL);
269 }
270 dbus_free (fds);
271 _dbus_string_free (&address);
272
273 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
274 }
275#ifdef DBUS_ENABLE_LAUNCHD
276 else if (strcmp (method, "launchd") == 0)
277 {
278 const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
279 if (launchd_env_var == NULL)
280 {
281 _dbus_set_bad_address (error, "launchd", "env", NULL);
282 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
283 }
284 *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);
285
286 if (*server_p != NULL)
287 {
288 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
289 return DBUS_SERVER_LISTEN_OK;
290 }
291 else
292 {
293 _DBUS_ASSERT_ERROR_IS_SET(error);
294 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
295 }
296 }
297#endif
298 else
299 {
300 /* If we don't handle the method, we return NULL with the
301 * error unset
302 */
303 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
304 return DBUS_SERVER_LISTEN_NOT_HANDLED;
305 }
306}
307
318 dbus_bool_t abstract,
319 DBusError *error)
320{
321 DBusServer *server;
322 DBusSocket listen_fd;
323 DBusString address;
324 char *path_copy;
325 DBusString path_str;
326
327 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
328
329 if (!_dbus_string_init (&address))
330 {
332 return NULL;
333 }
334
335 _dbus_string_init_const (&path_str, path);
336 if ((abstract &&
337 !_dbus_string_append (&address, "unix:abstract=")) ||
338 (!abstract &&
339 !_dbus_string_append (&address, "unix:path=")) ||
340 !_dbus_address_append_escaped (&address, &path_str))
341 {
343 goto failed_0;
344 }
345
346 if (abstract)
347 {
348 path_copy = NULL;
349 }
350 else
351 {
352 path_copy = _dbus_strdup (path);
353 if (path_copy == NULL)
354 {
356 goto failed_0;
357 }
358 }
359
360 listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
361
362 if (listen_fd.fd < 0)
363 {
364 _DBUS_ASSERT_ERROR_IS_SET (error);
365 goto failed_1;
366 }
367#ifdef HAVE_PDPLINUX
368 else{
369 _dbus_verbose("parsec privsock: process to set Special label: path %s, fd=%d (NSP)\n",path,listen_fd.fd);
370 pdplinux_capability_set_socket_from_current_process(path,listen_fd.fd);
371 }
372#endif
373
374 server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
375 if (server == NULL)
376 {
377 goto failed_2;
378 }
379
380 if (path_copy != NULL)
381 _dbus_server_socket_own_filename(server, path_copy);
382
383 _dbus_string_free (&address);
384
385 return server;
386
387 failed_2:
388 _dbus_close_socket (listen_fd, NULL);
389 failed_1:
390 dbus_free (path_copy);
391 failed_0:
392 _dbus_string_free (&address);
393
394 return NULL;
395}
396
397#ifdef HAVE_PDPLINUX
398
399//-----------------------------------------------------------------------------------------------
400int pdplinux_capability_set_socket_from_current_process(const char* path, int sockfd){
401 int r=0;
402 int found=0;
403 dbus_bool_t flFind;
404
405 parsec_caps_t capsproc;
406 DBusString dsPath;
407
408 memset(&capsproc,0,sizeof(capsproc));
409 r=parsec_capget(0,&capsproc);
410
411 _dbus_string_init_const(&dsPath,path);
412
413 flFind=_dbus_string_find(&dsPath,0,"system_bus_socket",&found);
414
415 if (flFind){
416 if (r==0)
417 r=pdplinux_capability_set_apply_socket(capsproc.cap_effective,sockfd);
418 else
419 _dbus_verbose("parsec privsock: parsec_capget failed with %d\n",r);
420 }
421 else
422 _dbus_verbose("parsec privsock: _dbus_string_find cannot find system_bus_socket in path so skip set_apply_socket\n");
423
424 _dbus_verbose("parsec privsock: pdplinux_capability_set_apply_socket returned %d\n",r);
425 return r;
426}
427
428//-----------------------------------------------------------------------------------------------
429int pdplinux_capability_set_apply_socket(parsec_cap_t set, int sockfd){
430 int r=0;
431 int pdpi=0;
432
433 unsigned int caps=set;
434 _dbus_verbose("parsec privsock: Capability is %x\n",caps);
435 //pdpi=pdp_init();
436
437 if (pdpi != 0){
438 _dbus_verbose("parsec privsock: Error pdp_init %m\n");
439 r=-1;
440 return r;
441 }
442
443 if (set & PARSEC_CAP_TO_MASK(PARSEC_CAP_PRIV_SOCK)){
444 PDPL_T* pdpl = NULL;
445 PDP_TYPE_T type = PDPT_EHOLE;
446
447 _dbus_verbose("parsec privsock: Processing 'PARSEC_CAP_PRIV_SOCK' socket...\n");
448
449 pdpl=pdp_get_fd(sockfd);
450
451 if (pdpl){
452 pdpl_or_type(pdpl,type);
453
454 if ( pdp_set_fd(sockfd,pdpl)!=0 ){
455 r=-2;
456 _dbus_verbose("parsec privsock: Failed pdp_set_fd: %m\n");
457 }
458 else{
459 _dbus_verbose("parsec privsock: Parsec privsock set successful\n");
460 }
461 pdpl_put(pdpl);
462 }
463 else{
464 r=-3;
465 _dbus_verbose("parsec privsock: Failed pdp_get_fd: %m\n");
466 }
467 }
468 else{
469 _dbus_verbose("parsec privsock: Parsec privsock skipped because of no PARSEC_CAP_PRIV_SOCK\n");
470 r=0;
471 }
472
473 //pdpi=pdp_release();
474 if (pdpi != 0){
475 _dbus_verbose("parsec privsock: Error pdp_release %m\n");
476 r=-4;
477 }
478 return r;
479}
480#endif
481
dbus_bool_t _dbus_address_append_escaped(DBusString *escaped, const DBusString *unescaped)
Appends an escaped version of one string to another string, using the D-Bus address escaping mechanis...
Definition: dbus-address.c:107
void _dbus_set_bad_address(DBusError *error, const char *address_problem_type, const char *address_problem_field, const char *address_problem_other)
Sets DBUS_ERROR_BAD_ADDRESS.
Definition: dbus-address.c:68
const char * dbus_address_entry_get_method(DBusAddressEntry *entry)
Returns the method string of an address entry.
Definition: dbus-address.c:230
const char * dbus_address_entry_get_value(DBusAddressEntry *entry, const char *key)
Returns a value from a key of an entry.
Definition: dbus-address.c:247
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
char * _dbus_strdup(const char *str)
Duplicates a string.
dbus_bool_t _dbus_generate_random_ascii(DBusString *str, int n_bytes, DBusError *error)
Generates the given number of random bytes, where the bytes are chosen from the alphanumeric ASCII su...
Definition: dbus-sysdeps.c:559
#define NULL
A null pointer, defined appropriately for C or C++.
#define TRUE
Expands to "1".
#define FALSE
Expands to "0".
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:692
#define DBUS_ERROR_NOT_SUPPORTED
Requested operation isn't supported (like ENOSYS on UNIX).
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
DBusServer * _dbus_server_new_for_launchd(const char *launchd_env_var, DBusError *error)
Creates a new server from launchd.
DBusServer * _dbus_server_new_for_socket(DBusSocket *fds, int n_fds, const DBusString *address, DBusNonceFile *noncefile, DBusError *error)
Creates a new server listening on the given file descriptor.
void _dbus_server_socket_own_filename(DBusServer *server, char *filename)
This is a bad hack since it's really unix domain socket specific.
DBusServer * _dbus_server_new_for_domain_socket(const char *path, dbus_bool_t abstract, DBusError *error)
Creates a new server listening on the given Unix domain socket.
DBusServerListenResult _dbus_server_listen_platform_specific(DBusAddressEntry *entry, DBusServer **server_p, DBusError *error)
Tries to interpret the address entry in a platform-specific way, creating a platform-specific server ...
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
Definition: dbus-string.c:966
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:182
void _dbus_string_init_const(DBusString *str, const char *value)
Initializes a constant string.
Definition: dbus-string.c:197
dbus_bool_t _dbus_string_find(const DBusString *str, int start, const char *substr, int *found)
Finds the given substring in the string, returning TRUE and filling in the byte index where the subst...
Definition: dbus-string.c:1664
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as #_DBUS_STRING_I...
Definition: dbus-string.c:278
int _dbus_listen_unix_socket(const char *path, dbus_bool_t abstract, DBusError *error)
Creates a socket and binds it to the given path, then listens on the socket.
int _dbus_listen_systemd_sockets(DBusSocket **fds, DBusError *error)
Acquires one or more sockets passed in from systemd.
dbus_bool_t _dbus_append_address_from_socket(DBusSocket fd, DBusString *address, DBusError *error)
Read the address from the socket and append it to the string.
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket.
const char * _dbus_getenv(const char *varname)
Wrapper for getenv().
Definition: dbus-sysdeps.c:195
dbus_bool_t _dbus_concat_dir_and_file(DBusString *dir, const DBusString *next_component)
Appends the given filename to the given directory.
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
Internals of DBusAddressEntry.
Definition: dbus-address.c:47
Object representing an exception.
Definition: dbus-errors.h:49
Internals of DBusServer object.
Socket interface.
Definition: dbus-sysdeps.h:187