Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #if HAVE_VALGRIND_MEMCHECK_H
4 : : #include <valgrind/memcheck.h>
5 : : #endif
6 : :
7 : : #include <errno.h>
8 : : #include <stddef.h>
9 : :
10 : : #include "sd-bus.h"
11 : :
12 : : #include "alloc-util.h"
13 : : #include "bus-control.h"
14 : : #include "bus-internal.h"
15 : : #include "bus-message.h"
16 : : #include "bus-util.h"
17 : : #include "capability-util.h"
18 : : #include "process-util.h"
19 : : #include "stdio-util.h"
20 : : #include "string-util.h"
21 : : #include "strv.h"
22 : : #include "user-util.h"
23 : :
24 : 12 : _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
25 : : int r;
26 : :
27 [ - + - + ]: 12 : assert_return(bus, -EINVAL);
28 [ - + - + ]: 12 : assert_return(bus = bus_resolve(bus), -ENOPKG);
29 [ - + - + ]: 12 : assert_return(unique, -EINVAL);
30 [ - + - + ]: 12 : assert_return(!bus_pid_changed(bus), -ECHILD);
31 : :
32 [ - + ]: 12 : if (!bus->bus_client)
33 : 0 : return -EINVAL;
34 : :
35 : 12 : r = bus_ensure_running(bus);
36 [ - + ]: 12 : if (r < 0)
37 : 0 : return r;
38 : :
39 : 12 : *unique = bus->unique_name;
40 : 12 : return 0;
41 : : }
42 : :
43 : 8 : static int validate_request_name_parameters(
44 : : sd_bus *bus,
45 : : const char *name,
46 : : uint64_t flags,
47 : : uint32_t *ret_param) {
48 : :
49 : 8 : uint32_t param = 0;
50 : :
51 [ - + ]: 8 : assert(bus);
52 [ - + ]: 8 : assert(name);
53 [ - + ]: 8 : assert(ret_param);
54 : :
55 [ - + - + ]: 8 : assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
56 [ - + - + ]: 8 : assert_return(service_name_is_valid(name), -EINVAL);
57 [ - + - + ]: 8 : assert_return(name[0] != ':', -EINVAL);
58 : :
59 [ - + ]: 8 : if (!bus->bus_client)
60 : 0 : return -EINVAL;
61 : :
62 : : /* Don't allow requesting the special driver and local names */
63 [ - + ]: 8 : if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
64 : 0 : return -EINVAL;
65 : :
66 [ - + ]: 8 : if (!BUS_IS_OPEN(bus->state))
67 : 0 : return -ENOTCONN;
68 : :
69 [ - + ]: 8 : if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
70 : 0 : param |= BUS_NAME_ALLOW_REPLACEMENT;
71 [ - + ]: 8 : if (flags & SD_BUS_NAME_REPLACE_EXISTING)
72 : 0 : param |= BUS_NAME_REPLACE_EXISTING;
73 [ + - ]: 8 : if (!(flags & SD_BUS_NAME_QUEUE))
74 : 8 : param |= BUS_NAME_DO_NOT_QUEUE;
75 : :
76 : 8 : *ret_param = param;
77 : :
78 : 8 : return 0;
79 : : }
80 : :
81 : 4 : _public_ int sd_bus_request_name(
82 : : sd_bus *bus,
83 : : const char *name,
84 : : uint64_t flags) {
85 : :
86 : 4 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
87 : 4 : uint32_t ret, param = 0;
88 : : int r;
89 : :
90 [ - + - + ]: 4 : assert_return(bus, -EINVAL);
91 [ - + - + ]: 4 : assert_return(bus = bus_resolve(bus), -ENOPKG);
92 [ - + - + ]: 4 : assert_return(name, -EINVAL);
93 [ - + - + ]: 4 : assert_return(!bus_pid_changed(bus), -ECHILD);
94 : :
95 : 4 : r = validate_request_name_parameters(bus, name, flags, ¶m);
96 [ - + ]: 4 : if (r < 0)
97 : 0 : return r;
98 : :
99 : 4 : r = sd_bus_call_method(
100 : : bus,
101 : : "org.freedesktop.DBus",
102 : : "/org/freedesktop/DBus",
103 : : "org.freedesktop.DBus",
104 : : "RequestName",
105 : : NULL,
106 : : &reply,
107 : : "su",
108 : : name,
109 : : param);
110 [ - + ]: 4 : if (r < 0)
111 : 0 : return r;
112 : :
113 : 4 : r = sd_bus_message_read(reply, "u", &ret);
114 [ - + ]: 4 : if (r < 0)
115 : 0 : return r;
116 : :
117 [ - - - + : 4 : switch (ret) {
- ]
118 : :
119 : 0 : case BUS_NAME_ALREADY_OWNER:
120 : 0 : return -EALREADY;
121 : :
122 : 0 : case BUS_NAME_EXISTS:
123 : 0 : return -EEXIST;
124 : :
125 : 0 : case BUS_NAME_IN_QUEUE:
126 : 0 : return 0;
127 : :
128 : 4 : case BUS_NAME_PRIMARY_OWNER:
129 : 4 : return 1;
130 : : }
131 : :
132 : 0 : return -EIO;
133 : : }
134 : :
135 : 0 : static int default_request_name_handler(
136 : : sd_bus_message *m,
137 : : void *userdata,
138 : : sd_bus_error *ret_error) {
139 : :
140 : : uint32_t ret;
141 : : int r;
142 : :
143 [ # # ]: 0 : assert(m);
144 : :
145 [ # # ]: 0 : if (sd_bus_message_is_method_error(m, NULL)) {
146 [ # # ]: 0 : log_debug_errno(sd_bus_message_get_errno(m),
147 : : "Unable to request name, failing connection: %s",
148 : : sd_bus_message_get_error(m)->message);
149 : :
150 : 0 : bus_enter_closing(sd_bus_message_get_bus(m));
151 : 0 : return 1;
152 : : }
153 : :
154 : 0 : r = sd_bus_message_read(m, "u", &ret);
155 [ # # ]: 0 : if (r < 0)
156 : 0 : return r;
157 : :
158 [ # # # # : 0 : switch (ret) {
# ]
159 : :
160 : 0 : case BUS_NAME_ALREADY_OWNER:
161 [ # # ]: 0 : log_debug("Already owner of requested service name, ignoring.");
162 : 0 : return 1;
163 : :
164 : 0 : case BUS_NAME_IN_QUEUE:
165 [ # # ]: 0 : log_debug("In queue for requested service name.");
166 : 0 : return 1;
167 : :
168 : 0 : case BUS_NAME_PRIMARY_OWNER:
169 [ # # ]: 0 : log_debug("Successfully acquired requested service name.");
170 : 0 : return 1;
171 : :
172 : 0 : case BUS_NAME_EXISTS:
173 [ # # ]: 0 : log_debug("Requested service name already owned, failing connection.");
174 : 0 : bus_enter_closing(sd_bus_message_get_bus(m));
175 : 0 : return 1;
176 : : }
177 : :
178 [ # # ]: 0 : log_debug("Unexpected response from RequestName(), failing connection.");
179 : 0 : bus_enter_closing(sd_bus_message_get_bus(m));
180 : 0 : return 1;
181 : : }
182 : :
183 : 4 : _public_ int sd_bus_request_name_async(
184 : : sd_bus *bus,
185 : : sd_bus_slot **ret_slot,
186 : : const char *name,
187 : : uint64_t flags,
188 : : sd_bus_message_handler_t callback,
189 : : void *userdata) {
190 : :
191 : 4 : uint32_t param = 0;
192 : : int r;
193 : :
194 [ - + - + ]: 4 : assert_return(bus, -EINVAL);
195 [ - + - + ]: 4 : assert_return(bus = bus_resolve(bus), -ENOPKG);
196 [ - + - + ]: 4 : assert_return(name, -EINVAL);
197 [ - + - + ]: 4 : assert_return(!bus_pid_changed(bus), -ECHILD);
198 : :
199 : 4 : r = validate_request_name_parameters(bus, name, flags, ¶m);
200 [ - + ]: 4 : if (r < 0)
201 : 0 : return r;
202 : :
203 : 4 : return sd_bus_call_method_async(
204 : : bus,
205 : : ret_slot,
206 : : "org.freedesktop.DBus",
207 : : "/org/freedesktop/DBus",
208 : : "org.freedesktop.DBus",
209 : : "RequestName",
210 [ + - ]: 4 : callback ?: default_request_name_handler,
211 : : userdata,
212 : : "su",
213 : : name,
214 : : param);
215 : : }
216 : :
217 : 0 : static int validate_release_name_parameters(
218 : : sd_bus *bus,
219 : : const char *name) {
220 : :
221 [ # # ]: 0 : assert(bus);
222 [ # # ]: 0 : assert(name);
223 : :
224 [ # # # # ]: 0 : assert_return(service_name_is_valid(name), -EINVAL);
225 [ # # # # ]: 0 : assert_return(name[0] != ':', -EINVAL);
226 : :
227 [ # # ]: 0 : if (!bus->bus_client)
228 : 0 : return -EINVAL;
229 : :
230 : : /* Don't allow releasing the special driver and local names */
231 [ # # ]: 0 : if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
232 : 0 : return -EINVAL;
233 : :
234 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state))
235 : 0 : return -ENOTCONN;
236 : :
237 : 0 : return 0;
238 : : }
239 : :
240 : 0 : _public_ int sd_bus_release_name(
241 : : sd_bus *bus,
242 : : const char *name) {
243 : :
244 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
245 : : uint32_t ret;
246 : : int r;
247 : :
248 [ # # # # ]: 0 : assert_return(bus, -EINVAL);
249 [ # # # # ]: 0 : assert_return(bus = bus_resolve(bus), -ENOPKG);
250 [ # # # # ]: 0 : assert_return(name, -EINVAL);
251 [ # # # # ]: 0 : assert_return(!bus_pid_changed(bus), -ECHILD);
252 : :
253 : 0 : r = validate_release_name_parameters(bus, name);
254 [ # # ]: 0 : if (r < 0)
255 : 0 : return r;
256 : :
257 : 0 : r = sd_bus_call_method(
258 : : bus,
259 : : "org.freedesktop.DBus",
260 : : "/org/freedesktop/DBus",
261 : : "org.freedesktop.DBus",
262 : : "ReleaseName",
263 : : NULL,
264 : : &reply,
265 : : "s",
266 : : name);
267 [ # # ]: 0 : if (r < 0)
268 : 0 : return r;
269 : :
270 : 0 : r = sd_bus_message_read(reply, "u", &ret);
271 [ # # ]: 0 : if (r < 0)
272 : 0 : return r;
273 : :
274 [ # # # # ]: 0 : switch (ret) {
275 : :
276 : 0 : case BUS_NAME_NON_EXISTENT:
277 : 0 : return -ESRCH;
278 : :
279 : 0 : case BUS_NAME_NOT_OWNER:
280 : 0 : return -EADDRINUSE;
281 : :
282 : 0 : case BUS_NAME_RELEASED:
283 : 0 : return 0;
284 : : }
285 : :
286 : 0 : return -EIO;
287 : : }
288 : :
289 : 0 : static int default_release_name_handler(
290 : : sd_bus_message *m,
291 : : void *userdata,
292 : : sd_bus_error *ret_error) {
293 : :
294 : : uint32_t ret;
295 : : int r;
296 : :
297 [ # # ]: 0 : assert(m);
298 : :
299 [ # # ]: 0 : if (sd_bus_message_is_method_error(m, NULL)) {
300 [ # # ]: 0 : log_debug_errno(sd_bus_message_get_errno(m),
301 : : "Unable to release name, failing connection: %s",
302 : : sd_bus_message_get_error(m)->message);
303 : :
304 : 0 : bus_enter_closing(sd_bus_message_get_bus(m));
305 : 0 : return 1;
306 : : }
307 : :
308 : 0 : r = sd_bus_message_read(m, "u", &ret);
309 [ # # ]: 0 : if (r < 0)
310 : 0 : return r;
311 : :
312 [ # # # # ]: 0 : switch (ret) {
313 : :
314 : 0 : case BUS_NAME_NON_EXISTENT:
315 [ # # ]: 0 : log_debug("Name asked to release is not taken currently, ignoring.");
316 : 0 : return 1;
317 : :
318 : 0 : case BUS_NAME_NOT_OWNER:
319 [ # # ]: 0 : log_debug("Name asked to release is owned by somebody else, ignoring.");
320 : 0 : return 1;
321 : :
322 : 0 : case BUS_NAME_RELEASED:
323 [ # # ]: 0 : log_debug("Name successfully released.");
324 : 0 : return 1;
325 : : }
326 : :
327 [ # # ]: 0 : log_debug("Unexpected response from ReleaseName(), failing connection.");
328 : 0 : bus_enter_closing(sd_bus_message_get_bus(m));
329 : 0 : return 1;
330 : : }
331 : :
332 : 0 : _public_ int sd_bus_release_name_async(
333 : : sd_bus *bus,
334 : : sd_bus_slot **ret_slot,
335 : : const char *name,
336 : : sd_bus_message_handler_t callback,
337 : : void *userdata) {
338 : :
339 : : int r;
340 : :
341 [ # # # # ]: 0 : assert_return(bus, -EINVAL);
342 [ # # # # ]: 0 : assert_return(bus = bus_resolve(bus), -ENOPKG);
343 [ # # # # ]: 0 : assert_return(name, -EINVAL);
344 [ # # # # ]: 0 : assert_return(!bus_pid_changed(bus), -ECHILD);
345 : :
346 : 0 : r = validate_release_name_parameters(bus, name);
347 [ # # ]: 0 : if (r < 0)
348 : 0 : return r;
349 : :
350 : 0 : return sd_bus_call_method_async(
351 : : bus,
352 : : ret_slot,
353 : : "org.freedesktop.DBus",
354 : : "/org/freedesktop/DBus",
355 : : "org.freedesktop.DBus",
356 : : "ReleaseName",
357 [ # # ]: 0 : callback ?: default_release_name_handler,
358 : : userdata,
359 : : "s",
360 : : name);
361 : : }
362 : :
363 : 0 : _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
364 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
365 : 0 : _cleanup_strv_free_ char **x = NULL, **y = NULL;
366 : : int r;
367 : :
368 [ # # # # ]: 0 : assert_return(bus, -EINVAL);
369 [ # # # # ]: 0 : assert_return(bus = bus_resolve(bus), -ENOPKG);
370 [ # # # # : 0 : assert_return(acquired || activatable, -EINVAL);
# # ]
371 [ # # # # ]: 0 : assert_return(!bus_pid_changed(bus), -ECHILD);
372 : :
373 [ # # ]: 0 : if (!bus->bus_client)
374 : 0 : return -EINVAL;
375 : :
376 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state))
377 : 0 : return -ENOTCONN;
378 : :
379 [ # # ]: 0 : if (acquired) {
380 : 0 : r = sd_bus_call_method(
381 : : bus,
382 : : "org.freedesktop.DBus",
383 : : "/org/freedesktop/DBus",
384 : : "org.freedesktop.DBus",
385 : : "ListNames",
386 : : NULL,
387 : : &reply,
388 : : NULL);
389 [ # # ]: 0 : if (r < 0)
390 : 0 : return r;
391 : :
392 : 0 : r = sd_bus_message_read_strv(reply, &x);
393 [ # # ]: 0 : if (r < 0)
394 : 0 : return r;
395 : :
396 : 0 : reply = sd_bus_message_unref(reply);
397 : : }
398 : :
399 [ # # ]: 0 : if (activatable) {
400 : 0 : r = sd_bus_call_method(
401 : : bus,
402 : : "org.freedesktop.DBus",
403 : : "/org/freedesktop/DBus",
404 : : "org.freedesktop.DBus",
405 : : "ListActivatableNames",
406 : : NULL,
407 : : &reply,
408 : : NULL);
409 [ # # ]: 0 : if (r < 0)
410 : 0 : return r;
411 : :
412 : 0 : r = sd_bus_message_read_strv(reply, &y);
413 [ # # ]: 0 : if (r < 0)
414 : 0 : return r;
415 : :
416 : 0 : *activatable = TAKE_PTR(y);
417 : : }
418 : :
419 [ # # ]: 0 : if (acquired)
420 : 0 : *acquired = TAKE_PTR(x);
421 : :
422 : 0 : return 0;
423 : : }
424 : :
425 : 8 : _public_ int sd_bus_get_name_creds(
426 : : sd_bus *bus,
427 : : const char *name,
428 : : uint64_t mask,
429 : : sd_bus_creds **creds) {
430 : :
431 : 8 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
432 : 8 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
433 : : const char *unique;
434 : 8 : pid_t pid = 0;
435 : : int r;
436 : :
437 [ - + - + ]: 8 : assert_return(bus, -EINVAL);
438 [ - + - + ]: 8 : assert_return(bus = bus_resolve(bus), -ENOPKG);
439 [ - + - + ]: 8 : assert_return(name, -EINVAL);
440 [ - + - + ]: 8 : assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
441 [ - + # # : 8 : assert_return(mask == 0 || creds, -EINVAL);
- + ]
442 [ - + - + ]: 8 : assert_return(!bus_pid_changed(bus), -ECHILD);
443 [ - + - + ]: 8 : assert_return(service_name_is_valid(name), -EINVAL);
444 : :
445 [ - + ]: 8 : if (!bus->bus_client)
446 : 0 : return -EINVAL;
447 : :
448 : : /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
449 : : * going to match. */
450 [ - + ]: 8 : if (!bus->is_local)
451 : 0 : mask &= ~SD_BUS_CREDS_AUGMENT;
452 : :
453 [ - + ]: 8 : if (streq(name, "org.freedesktop.DBus.Local"))
454 : 0 : return -EINVAL;
455 : :
456 [ - + ]: 8 : if (streq(name, "org.freedesktop.DBus"))
457 : 0 : return sd_bus_get_owner_creds(bus, mask, creds);
458 : :
459 [ - + ]: 8 : if (!BUS_IS_OPEN(bus->state))
460 : 0 : return -ENOTCONN;
461 : :
462 : : /* If the name is unique anyway, we can use it directly */
463 [ + - ]: 8 : unique = name[0] == ':' ? name : NULL;
464 : :
465 : : /* Only query the owner if the caller wants to know it and the name is not unique anyway, or if the caller just
466 : : * wants to check whether a name exists */
467 [ - + # # : 8 : if ((FLAGS_SET(mask, SD_BUS_CREDS_UNIQUE_NAME) && !unique) || mask == 0) {
+ - ]
468 : 8 : r = sd_bus_call_method(
469 : : bus,
470 : : "org.freedesktop.DBus",
471 : : "/org/freedesktop/DBus",
472 : : "org.freedesktop.DBus",
473 : : "GetNameOwner",
474 : : NULL,
475 : : &reply_unique,
476 : : "s",
477 : : name);
478 [ - + ]: 8 : if (r < 0)
479 : 0 : return r;
480 : :
481 : 8 : r = sd_bus_message_read(reply_unique, "s", &unique);
482 [ - + ]: 8 : if (r < 0)
483 : 0 : return r;
484 : : }
485 : :
486 [ - + ]: 8 : if (mask != 0) {
487 [ # # ]: 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
488 : : bool need_pid, need_uid, need_selinux, need_separate_calls;
489 : :
490 : 0 : c = bus_creds_new();
491 [ # # ]: 0 : if (!c)
492 : 0 : return -ENOMEM;
493 : :
494 [ # # # # ]: 0 : if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
495 : 0 : c->unique_name = strdup(unique);
496 [ # # ]: 0 : if (!c->unique_name)
497 : 0 : return -ENOMEM;
498 : :
499 : 0 : c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
500 : : }
501 : :
502 [ # # ]: 0 : need_pid = (mask & SD_BUS_CREDS_PID) ||
503 [ # # ]: 0 : ((mask & SD_BUS_CREDS_AUGMENT) &&
504 [ # # ]: 0 : (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
505 : : SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
506 : : SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
507 : : SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
508 : : SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
509 : : SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
510 : : SD_BUS_CREDS_SELINUX_CONTEXT|
511 : : SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
512 : 0 : need_uid = mask & SD_BUS_CREDS_EUID;
513 : 0 : need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
514 : :
515 [ # # ]: 0 : if (need_pid + need_uid + need_selinux > 1) {
516 : :
517 : : /* If we need more than one of the credentials, then use GetConnectionCredentials() */
518 : :
519 : 0 : r = sd_bus_call_method(
520 : : bus,
521 : : "org.freedesktop.DBus",
522 : : "/org/freedesktop/DBus",
523 : : "org.freedesktop.DBus",
524 : : "GetConnectionCredentials",
525 : : &error,
526 : : &reply,
527 : : "s",
528 [ # # ]: 0 : unique ?: name);
529 : :
530 [ # # ]: 0 : if (r < 0) {
531 : :
532 [ # # ]: 0 : if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
533 : 0 : return r;
534 : :
535 : : /* If we got an unknown method error, fall back to the individual calls... */
536 : 0 : need_separate_calls = true;
537 : 0 : sd_bus_error_free(&error);
538 : :
539 : : } else {
540 : 0 : need_separate_calls = false;
541 : :
542 : 0 : r = sd_bus_message_enter_container(reply, 'a', "{sv}");
543 [ # # ]: 0 : if (r < 0)
544 : 0 : return r;
545 : :
546 : 0 : for (;;) {
547 : : const char *m;
548 : :
549 : 0 : r = sd_bus_message_enter_container(reply, 'e', "sv");
550 [ # # ]: 0 : if (r < 0)
551 : 0 : return r;
552 [ # # ]: 0 : if (r == 0)
553 : 0 : break;
554 : :
555 : 0 : r = sd_bus_message_read(reply, "s", &m);
556 [ # # ]: 0 : if (r < 0)
557 : 0 : return r;
558 : :
559 [ # # # # ]: 0 : if (need_uid && streq(m, "UnixUserID")) {
560 : : uint32_t u;
561 : :
562 : 0 : r = sd_bus_message_read(reply, "v", "u", &u);
563 [ # # ]: 0 : if (r < 0)
564 : 0 : return r;
565 : :
566 : 0 : c->euid = u;
567 : 0 : c->mask |= SD_BUS_CREDS_EUID;
568 : :
569 [ # # # # ]: 0 : } else if (need_pid && streq(m, "ProcessID")) {
570 : : uint32_t p;
571 : :
572 : 0 : r = sd_bus_message_read(reply, "v", "u", &p);
573 [ # # ]: 0 : if (r < 0)
574 : 0 : return r;
575 : :
576 : 0 : pid = p;
577 [ # # ]: 0 : if (mask & SD_BUS_CREDS_PID) {
578 : 0 : c->pid = p;
579 : 0 : c->mask |= SD_BUS_CREDS_PID;
580 : : }
581 : :
582 [ # # # # ]: 0 : } else if (need_selinux && streq(m, "LinuxSecurityLabel")) {
583 : 0 : const void *p = NULL;
584 : 0 : size_t sz = 0;
585 : :
586 : 0 : r = sd_bus_message_enter_container(reply, 'v', "ay");
587 [ # # ]: 0 : if (r < 0)
588 : 0 : return r;
589 : :
590 : 0 : r = sd_bus_message_read_array(reply, 'y', &p, &sz);
591 [ # # ]: 0 : if (r < 0)
592 : 0 : return r;
593 : :
594 : 0 : free(c->label);
595 : 0 : c->label = strndup(p, sz);
596 [ # # ]: 0 : if (!c->label)
597 : 0 : return -ENOMEM;
598 : :
599 : 0 : c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
600 : :
601 : 0 : r = sd_bus_message_exit_container(reply);
602 [ # # ]: 0 : if (r < 0)
603 : 0 : return r;
604 : : } else {
605 : 0 : r = sd_bus_message_skip(reply, "v");
606 [ # # ]: 0 : if (r < 0)
607 : 0 : return r;
608 : : }
609 : :
610 : 0 : r = sd_bus_message_exit_container(reply);
611 [ # # ]: 0 : if (r < 0)
612 : 0 : return r;
613 : : }
614 : :
615 : 0 : r = sd_bus_message_exit_container(reply);
616 [ # # ]: 0 : if (r < 0)
617 : 0 : return r;
618 : :
619 [ # # # # ]: 0 : if (need_pid && pid == 0)
620 : 0 : return -EPROTO;
621 : : }
622 : :
623 : : } else /* When we only need a single field, then let's use separate calls */
624 : 0 : need_separate_calls = true;
625 : :
626 [ # # ]: 0 : if (need_separate_calls) {
627 [ # # ]: 0 : if (need_pid) {
628 : : uint32_t u;
629 : :
630 : 0 : r = sd_bus_call_method(
631 : : bus,
632 : : "org.freedesktop.DBus",
633 : : "/org/freedesktop/DBus",
634 : : "org.freedesktop.DBus",
635 : : "GetConnectionUnixProcessID",
636 : : NULL,
637 : : &reply,
638 : : "s",
639 [ # # ]: 0 : unique ?: name);
640 [ # # ]: 0 : if (r < 0)
641 : 0 : return r;
642 : :
643 : 0 : r = sd_bus_message_read(reply, "u", &u);
644 [ # # ]: 0 : if (r < 0)
645 : 0 : return r;
646 : :
647 : 0 : pid = u;
648 [ # # ]: 0 : if (mask & SD_BUS_CREDS_PID) {
649 : 0 : c->pid = u;
650 : 0 : c->mask |= SD_BUS_CREDS_PID;
651 : : }
652 : :
653 : 0 : reply = sd_bus_message_unref(reply);
654 : : }
655 : :
656 [ # # ]: 0 : if (need_uid) {
657 : : uint32_t u;
658 : :
659 : 0 : r = sd_bus_call_method(
660 : : bus,
661 : : "org.freedesktop.DBus",
662 : : "/org/freedesktop/DBus",
663 : : "org.freedesktop.DBus",
664 : : "GetConnectionUnixUser",
665 : : NULL,
666 : : &reply,
667 : : "s",
668 [ # # ]: 0 : unique ?: name);
669 [ # # ]: 0 : if (r < 0)
670 : 0 : return r;
671 : :
672 : 0 : r = sd_bus_message_read(reply, "u", &u);
673 [ # # ]: 0 : if (r < 0)
674 : 0 : return r;
675 : :
676 : 0 : c->euid = u;
677 : 0 : c->mask |= SD_BUS_CREDS_EUID;
678 : :
679 : 0 : reply = sd_bus_message_unref(reply);
680 : : }
681 : :
682 [ # # ]: 0 : if (need_selinux) {
683 : 0 : const void *p = NULL;
684 : 0 : size_t sz = 0;
685 : :
686 : 0 : r = sd_bus_call_method(
687 : : bus,
688 : : "org.freedesktop.DBus",
689 : : "/org/freedesktop/DBus",
690 : : "org.freedesktop.DBus",
691 : : "GetConnectionSELinuxSecurityContext",
692 : : &error,
693 : : &reply,
694 : : "s",
695 [ # # ]: 0 : unique ?: name);
696 [ # # ]: 0 : if (r < 0) {
697 [ # # ]: 0 : if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
698 : 0 : return r;
699 : :
700 : : /* no data is fine */
701 : : } else {
702 : 0 : r = sd_bus_message_read_array(reply, 'y', &p, &sz);
703 [ # # ]: 0 : if (r < 0)
704 : 0 : return r;
705 : :
706 : 0 : c->label = memdup_suffix0(p, sz);
707 [ # # ]: 0 : if (!c->label)
708 : 0 : return -ENOMEM;
709 : :
710 : 0 : c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
711 : : }
712 : : }
713 : : }
714 : :
715 : 0 : r = bus_creds_add_more(c, mask, pid, 0);
716 [ # # ]: 0 : if (r < 0)
717 : 0 : return r;
718 : : }
719 : :
720 [ - + ]: 8 : if (creds)
721 : 0 : *creds = TAKE_PTR(c);
722 : :
723 : 8 : return 0;
724 : : }
725 : :
726 : 52 : _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
727 : 52 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
728 : : bool do_label, do_groups;
729 : 52 : pid_t pid = 0;
730 : : int r;
731 : :
732 [ - + - + ]: 52 : assert_return(bus, -EINVAL);
733 [ - + - + ]: 52 : assert_return(bus = bus_resolve(bus), -ENOPKG);
734 [ - + - + ]: 52 : assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
735 [ - + - + ]: 52 : assert_return(ret, -EINVAL);
736 [ - + - + ]: 52 : assert_return(!bus_pid_changed(bus), -ECHILD);
737 : :
738 [ - + ]: 52 : if (!BUS_IS_OPEN(bus->state))
739 : 0 : return -ENOTCONN;
740 : :
741 [ + - ]: 52 : if (!bus->is_local)
742 : 52 : mask &= ~SD_BUS_CREDS_AUGMENT;
743 : :
744 [ + - - + ]: 52 : do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
745 [ + - - + ]: 52 : do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
746 : :
747 : : /* Avoid allocating anything if we have no chance of returning useful data */
748 [ - + # # : 52 : if (!bus->ucred_valid && !do_label && !do_groups)
# # ]
749 : 0 : return -ENODATA;
750 : :
751 : 52 : c = bus_creds_new();
752 [ - + ]: 52 : if (!c)
753 : 0 : return -ENOMEM;
754 : :
755 [ + - ]: 52 : if (bus->ucred_valid) {
756 [ + - ]: 52 : if (pid_is_valid(bus->ucred.pid)) {
757 : 52 : pid = c->pid = bus->ucred.pid;
758 : 52 : c->mask |= SD_BUS_CREDS_PID & mask;
759 : : }
760 : :
761 [ + - ]: 52 : if (uid_is_valid(bus->ucred.uid)) {
762 : 52 : c->euid = bus->ucred.uid;
763 : 52 : c->mask |= SD_BUS_CREDS_EUID & mask;
764 : : }
765 : :
766 [ + - ]: 52 : if (gid_is_valid(bus->ucred.gid)) {
767 : 52 : c->egid = bus->ucred.gid;
768 : 52 : c->mask |= SD_BUS_CREDS_EGID & mask;
769 : : }
770 : : }
771 : :
772 [ - + ]: 52 : if (do_label) {
773 : 0 : c->label = strdup(bus->label);
774 [ # # ]: 0 : if (!c->label)
775 : 0 : return -ENOMEM;
776 : :
777 : 0 : c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
778 : : }
779 : :
780 [ - + ]: 52 : if (do_groups) {
781 : 0 : c->supplementary_gids = newdup(gid_t, bus->groups, bus->n_groups);
782 [ # # ]: 0 : if (!c->supplementary_gids)
783 : 0 : return -ENOMEM;
784 : :
785 : 0 : c->n_supplementary_gids = bus->n_groups;
786 : :
787 : 0 : c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
788 : : }
789 : :
790 : 52 : r = bus_creds_add_more(c, mask, pid, 0);
791 [ - + ]: 52 : if (r < 0)
792 : 0 : return r;
793 : :
794 : 52 : *ret = TAKE_PTR(c);
795 : :
796 : 52 : return 0;
797 : : }
798 : :
799 : : #define append_eavesdrop(bus, m) \
800 : : ((bus)->is_monitor \
801 : : ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
802 : : : (m))
803 : :
804 : 8 : int bus_add_match_internal(
805 : : sd_bus *bus,
806 : : const char *match,
807 : : uint64_t *ret_counter) {
808 : :
809 : 8 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
810 : : const char *e;
811 : : int r;
812 : :
813 [ - + ]: 8 : assert(bus);
814 : :
815 [ - + ]: 8 : if (!bus->bus_client)
816 : 0 : return -EINVAL;
817 : :
818 [ - + # # : 8 : e = append_eavesdrop(bus, match);
# # # # #
# # # # #
# # ]
819 : :
820 : 8 : r = sd_bus_call_method(
821 : : bus,
822 : : "org.freedesktop.DBus",
823 : : "/org/freedesktop/DBus",
824 : : "org.freedesktop.DBus",
825 : : "AddMatch",
826 : : NULL,
827 : : &reply,
828 : : "s",
829 : : e);
830 [ - + ]: 8 : if (r < 0)
831 : 0 : return r;
832 : :
833 : : /* If the caller asked for it, return the read counter of the reply */
834 [ + - ]: 8 : if (ret_counter)
835 : 8 : *ret_counter = reply->read_counter;
836 : :
837 : 8 : return r;
838 : : }
839 : :
840 : 60 : int bus_add_match_internal_async(
841 : : sd_bus *bus,
842 : : sd_bus_slot **ret_slot,
843 : : const char *match,
844 : : sd_bus_message_handler_t callback,
845 : : void *userdata) {
846 : :
847 : : const char *e;
848 : :
849 [ - + ]: 60 : assert(bus);
850 : :
851 [ - + ]: 60 : if (!bus->bus_client)
852 : 0 : return -EINVAL;
853 : :
854 [ - + # # : 60 : e = append_eavesdrop(bus, match);
# # # # #
# # # # #
# # ]
855 : :
856 : 60 : return sd_bus_call_method_async(
857 : : bus,
858 : : ret_slot,
859 : : "org.freedesktop.DBus",
860 : : "/org/freedesktop/DBus",
861 : : "org.freedesktop.DBus",
862 : : "AddMatch",
863 : : callback,
864 : : userdata,
865 : : "s",
866 : : e);
867 : : }
868 : :
869 : 68 : int bus_remove_match_internal(
870 : : sd_bus *bus,
871 : : const char *match) {
872 : :
873 : : const char *e;
874 : :
875 [ - + ]: 68 : assert(bus);
876 [ - + ]: 68 : assert(match);
877 : :
878 [ - + ]: 68 : if (!bus->bus_client)
879 : 0 : return -EINVAL;
880 : :
881 [ - + # # : 68 : e = append_eavesdrop(bus, match);
# # # # #
# # # # #
# # ]
882 : :
883 : : /* Fire and forget */
884 : :
885 : 68 : return sd_bus_call_method_async(
886 : : bus,
887 : : NULL,
888 : : "org.freedesktop.DBus",
889 : : "/org/freedesktop/DBus",
890 : : "org.freedesktop.DBus",
891 : : "RemoveMatch",
892 : : NULL,
893 : : NULL,
894 : : "s",
895 : : e);
896 : : }
897 : :
898 : 0 : _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
899 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
900 : : const char *mid;
901 : : int r;
902 : :
903 [ # # # # ]: 0 : assert_return(bus, -EINVAL);
904 [ # # # # ]: 0 : assert_return(bus = bus_resolve(bus), -ENOPKG);
905 [ # # # # ]: 0 : assert_return(name, -EINVAL);
906 [ # # # # ]: 0 : assert_return(machine, -EINVAL);
907 [ # # # # ]: 0 : assert_return(!bus_pid_changed(bus), -ECHILD);
908 [ # # # # ]: 0 : assert_return(service_name_is_valid(name), -EINVAL);
909 : :
910 [ # # ]: 0 : if (!bus->bus_client)
911 : 0 : return -EINVAL;
912 : :
913 [ # # ]: 0 : if (!BUS_IS_OPEN(bus->state))
914 : 0 : return -ENOTCONN;
915 : :
916 [ # # ]: 0 : if (streq_ptr(name, bus->unique_name))
917 : 0 : return sd_id128_get_machine(machine);
918 : :
919 : 0 : r = sd_bus_message_new_method_call(
920 : : bus,
921 : : &m,
922 : : name,
923 : : "/",
924 : : "org.freedesktop.DBus.Peer",
925 : : "GetMachineId");
926 [ # # ]: 0 : if (r < 0)
927 : 0 : return r;
928 : :
929 : 0 : r = sd_bus_message_set_auto_start(m, false);
930 [ # # ]: 0 : if (r < 0)
931 : 0 : return r;
932 : :
933 : 0 : r = sd_bus_call(bus, m, 0, NULL, &reply);
934 [ # # ]: 0 : if (r < 0)
935 : 0 : return r;
936 : :
937 : 0 : r = sd_bus_message_read(reply, "s", &mid);
938 [ # # ]: 0 : if (r < 0)
939 : 0 : return r;
940 : :
941 : 0 : return sd_id128_from_string(mid, machine);
942 : : }
|