]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-control.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-control.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <errno.h>
27 #include <stddef.h>
28
29 #include "sd-bus.h"
30
31 #include "alloc-util.h"
32 #include "bus-bloom.h"
33 #include "bus-control.h"
34 #include "bus-internal.h"
35 #include "bus-message.h"
36 #include "bus-util.h"
37 #include "capability-util.h"
38 #include "stdio-util.h"
39 #include "string-util.h"
40 #include "strv.h"
41 #include "user-util.h"
42
43 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
44 int r;
45
46 assert_return(bus, -EINVAL);
47 assert_return(unique, -EINVAL);
48 assert_return(!bus_pid_changed(bus), -ECHILD);
49
50 if (!bus->bus_client)
51 return -EINVAL;
52
53 r = bus_ensure_running(bus);
54 if (r < 0)
55 return r;
56
57 *unique = bus->unique_name;
58 return 0;
59 }
60
61 static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
62 struct kdbus_cmd *n;
63 size_t size, l;
64 int r;
65
66 assert(bus);
67 assert(name);
68
69 l = strlen(name) + 1;
70 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
71 n = alloca0_align(size, 8);
72 n->size = size;
73 n->flags = request_name_flags_to_kdbus(flags);
74
75 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
76 n->items[0].type = KDBUS_ITEM_NAME;
77 memcpy(n->items[0].str, name, l);
78
79 #ifdef HAVE_VALGRIND_MEMCHECK_H
80 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
81 #endif
82
83 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
84 if (r < 0)
85 return -errno;
86
87 if (n->return_flags & KDBUS_NAME_IN_QUEUE)
88 return 0;
89
90 return 1;
91 }
92
93 static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
94 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
95 uint32_t ret, param = 0;
96 int r;
97
98 assert(bus);
99 assert(name);
100
101 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
102 param |= BUS_NAME_ALLOW_REPLACEMENT;
103 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
104 param |= BUS_NAME_REPLACE_EXISTING;
105 if (!(flags & SD_BUS_NAME_QUEUE))
106 param |= BUS_NAME_DO_NOT_QUEUE;
107
108 r = sd_bus_call_method(
109 bus,
110 "org.freedesktop.DBus",
111 "/org/freedesktop/DBus",
112 "org.freedesktop.DBus",
113 "RequestName",
114 NULL,
115 &reply,
116 "su",
117 name,
118 param);
119 if (r < 0)
120 return r;
121
122 r = sd_bus_message_read(reply, "u", &ret);
123 if (r < 0)
124 return r;
125
126 if (ret == BUS_NAME_ALREADY_OWNER)
127 return -EALREADY;
128 else if (ret == BUS_NAME_EXISTS)
129 return -EEXIST;
130 else if (ret == BUS_NAME_IN_QUEUE)
131 return 0;
132 else if (ret == BUS_NAME_PRIMARY_OWNER)
133 return 1;
134
135 return -EIO;
136 }
137
138 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
139 assert_return(bus, -EINVAL);
140 assert_return(name, -EINVAL);
141 assert_return(!bus_pid_changed(bus), -ECHILD);
142 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
143 assert_return(service_name_is_valid(name), -EINVAL);
144 assert_return(name[0] != ':', -EINVAL);
145
146 if (!bus->bus_client)
147 return -EINVAL;
148
149 /* Don't allow requesting the special driver and local names */
150 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
151 return -EINVAL;
152
153 if (!BUS_IS_OPEN(bus->state))
154 return -ENOTCONN;
155
156 if (bus->is_kernel)
157 return bus_request_name_kernel(bus, name, flags);
158 else
159 return bus_request_name_dbus1(bus, name, flags);
160 }
161
162 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
163 struct kdbus_cmd *n;
164 size_t size, l;
165 int r;
166
167 assert(bus);
168 assert(name);
169
170 l = strlen(name) + 1;
171 size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
172 n = alloca0_align(size, 8);
173 n->size = size;
174
175 n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
176 n->items[0].type = KDBUS_ITEM_NAME;
177 memcpy(n->items[0].str, name, l);
178
179 #ifdef HAVE_VALGRIND_MEMCHECK_H
180 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
181 #endif
182 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
183 if (r < 0)
184 return -errno;
185
186 return 0;
187 }
188
189 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
190 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
191 uint32_t ret;
192 int r;
193
194 assert(bus);
195 assert(name);
196
197 r = sd_bus_call_method(
198 bus,
199 "org.freedesktop.DBus",
200 "/org/freedesktop/DBus",
201 "org.freedesktop.DBus",
202 "ReleaseName",
203 NULL,
204 &reply,
205 "s",
206 name);
207 if (r < 0)
208 return r;
209
210 r = sd_bus_message_read(reply, "u", &ret);
211 if (r < 0)
212 return r;
213 if (ret == BUS_NAME_NON_EXISTENT)
214 return -ESRCH;
215 if (ret == BUS_NAME_NOT_OWNER)
216 return -EADDRINUSE;
217 if (ret == BUS_NAME_RELEASED)
218 return 0;
219
220 return -EINVAL;
221 }
222
223 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
224 assert_return(bus, -EINVAL);
225 assert_return(name, -EINVAL);
226 assert_return(!bus_pid_changed(bus), -ECHILD);
227 assert_return(service_name_is_valid(name), -EINVAL);
228 assert_return(name[0] != ':', -EINVAL);
229
230 if (!bus->bus_client)
231 return -EINVAL;
232
233 /* Don't allow releasing the special driver and local names */
234 if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
235 return -EINVAL;
236
237 if (!BUS_IS_OPEN(bus->state))
238 return -ENOTCONN;
239
240 if (bus->is_kernel)
241 return bus_release_name_kernel(bus, name);
242 else
243 return bus_release_name_dbus1(bus, name);
244 }
245
246 static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
247 struct kdbus_cmd_list cmd = {
248 .size = sizeof(cmd),
249 .flags = flags,
250 };
251 struct kdbus_info *name_list, *name;
252 uint64_t previous_id = 0;
253 int r;
254
255 /* Caller will free half-constructed list on failure... */
256
257 r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
258 if (r < 0)
259 return -errno;
260
261 name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
262
263 KDBUS_FOREACH(name, name_list, cmd.list_size) {
264 struct kdbus_item *item;
265
266 if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) {
267 char *n;
268
269 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
270 r = -ENOMEM;
271 goto fail;
272 }
273
274 r = strv_consume(x, n);
275 if (r < 0)
276 goto fail;
277
278 previous_id = name->id;
279 }
280
281 KDBUS_ITEM_FOREACH(item, name, items) {
282 if (item->type == KDBUS_ITEM_OWNED_NAME) {
283 if (service_name_is_valid(item->name.name)) {
284 r = strv_extend(x, item->name.name);
285 if (r < 0) {
286 r = -ENOMEM;
287 goto fail;
288 }
289 }
290 }
291 }
292 }
293
294 r = 0;
295
296 fail:
297 bus_kernel_cmd_free(bus, cmd.offset);
298 return r;
299 }
300
301 static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
302 _cleanup_strv_free_ char **x = NULL, **y = NULL;
303 int r;
304
305 if (acquired) {
306 r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
307 if (r < 0)
308 return r;
309 }
310
311 if (activatable) {
312 r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
313 if (r < 0)
314 return r;
315
316 *activatable = y;
317 y = NULL;
318 }
319
320 if (acquired) {
321 *acquired = x;
322 x = NULL;
323 }
324
325 return 0;
326 }
327
328 static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
329 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
330 _cleanup_strv_free_ char **x = NULL, **y = NULL;
331 int r;
332
333 if (acquired) {
334 r = sd_bus_call_method(
335 bus,
336 "org.freedesktop.DBus",
337 "/org/freedesktop/DBus",
338 "org.freedesktop.DBus",
339 "ListNames",
340 NULL,
341 &reply,
342 NULL);
343 if (r < 0)
344 return r;
345
346 r = sd_bus_message_read_strv(reply, &x);
347 if (r < 0)
348 return r;
349
350 reply = sd_bus_message_unref(reply);
351 }
352
353 if (activatable) {
354 r = sd_bus_call_method(
355 bus,
356 "org.freedesktop.DBus",
357 "/org/freedesktop/DBus",
358 "org.freedesktop.DBus",
359 "ListActivatableNames",
360 NULL,
361 &reply,
362 NULL);
363 if (r < 0)
364 return r;
365
366 r = sd_bus_message_read_strv(reply, &y);
367 if (r < 0)
368 return r;
369
370 *activatable = y;
371 y = NULL;
372 }
373
374 if (acquired) {
375 *acquired = x;
376 x = NULL;
377 }
378
379 return 0;
380 }
381
382 _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
383 assert_return(bus, -EINVAL);
384 assert_return(acquired || activatable, -EINVAL);
385 assert_return(!bus_pid_changed(bus), -ECHILD);
386
387 if (!bus->bus_client)
388 return -EINVAL;
389
390 if (!BUS_IS_OPEN(bus->state))
391 return -ENOTCONN;
392
393 if (bus->is_kernel)
394 return bus_list_names_kernel(bus, acquired, activatable);
395 else
396 return bus_list_names_dbus1(bus, acquired, activatable);
397 }
398
399 static int bus_populate_creds_from_items(
400 sd_bus *bus,
401 struct kdbus_info *info,
402 uint64_t mask,
403 sd_bus_creds *c) {
404
405 struct kdbus_item *item;
406 uint64_t m;
407 int r;
408
409 assert(bus);
410 assert(info);
411 assert(c);
412
413 KDBUS_ITEM_FOREACH(item, info, items) {
414
415 switch (item->type) {
416
417 case KDBUS_ITEM_PIDS:
418
419 if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
420 c->pid = (pid_t) item->pids.pid;
421 c->mask |= SD_BUS_CREDS_PID;
422 }
423
424 if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
425 c->tid = (pid_t) item->pids.tid;
426 c->mask |= SD_BUS_CREDS_TID;
427 }
428
429 if (mask & SD_BUS_CREDS_PPID) {
430 if (item->pids.ppid > 0) {
431 c->ppid = (pid_t) item->pids.ppid;
432 c->mask |= SD_BUS_CREDS_PPID;
433 } else if (item->pids.pid == 1) {
434 /* The structure doesn't
435 * really distinguish the case
436 * where a process has no
437 * parent and where we don't
438 * know it because it could
439 * not be translated due to
440 * namespaces. However, we
441 * know that PID 1 has no
442 * parent process, hence let's
443 * patch that in, manually. */
444 c->ppid = 0;
445 c->mask |= SD_BUS_CREDS_PPID;
446 }
447 }
448
449 break;
450
451 case KDBUS_ITEM_CREDS:
452
453 if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
454 c->uid = (uid_t) item->creds.uid;
455 c->mask |= SD_BUS_CREDS_UID;
456 }
457
458 if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
459 c->euid = (uid_t) item->creds.euid;
460 c->mask |= SD_BUS_CREDS_EUID;
461 }
462
463 if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
464 c->suid = (uid_t) item->creds.suid;
465 c->mask |= SD_BUS_CREDS_SUID;
466 }
467
468 if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
469 c->fsuid = (uid_t) item->creds.fsuid;
470 c->mask |= SD_BUS_CREDS_FSUID;
471 }
472
473 if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
474 c->gid = (gid_t) item->creds.gid;
475 c->mask |= SD_BUS_CREDS_GID;
476 }
477
478 if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
479 c->egid = (gid_t) item->creds.egid;
480 c->mask |= SD_BUS_CREDS_EGID;
481 }
482
483 if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
484 c->sgid = (gid_t) item->creds.sgid;
485 c->mask |= SD_BUS_CREDS_SGID;
486 }
487
488 if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
489 c->fsgid = (gid_t) item->creds.fsgid;
490 c->mask |= SD_BUS_CREDS_FSGID;
491 }
492
493 break;
494
495 case KDBUS_ITEM_PID_COMM:
496 if (mask & SD_BUS_CREDS_COMM) {
497 r = free_and_strdup(&c->comm, item->str);
498 if (r < 0)
499 return r;
500
501 c->mask |= SD_BUS_CREDS_COMM;
502 }
503 break;
504
505 case KDBUS_ITEM_TID_COMM:
506 if (mask & SD_BUS_CREDS_TID_COMM) {
507 r = free_and_strdup(&c->tid_comm, item->str);
508 if (r < 0)
509 return r;
510
511 c->mask |= SD_BUS_CREDS_TID_COMM;
512 }
513 break;
514
515 case KDBUS_ITEM_EXE:
516 if (mask & SD_BUS_CREDS_EXE) {
517 r = free_and_strdup(&c->exe, item->str);
518 if (r < 0)
519 return r;
520
521 c->mask |= SD_BUS_CREDS_EXE;
522 }
523 break;
524
525 case KDBUS_ITEM_CMDLINE:
526 if (mask & SD_BUS_CREDS_CMDLINE) {
527 c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
528 c->cmdline = memdup(item->data, c->cmdline_size);
529 if (!c->cmdline)
530 return -ENOMEM;
531
532 c->mask |= SD_BUS_CREDS_CMDLINE;
533 }
534 break;
535
536 case KDBUS_ITEM_CGROUP:
537 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
538 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
539 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
540
541 if (m) {
542 r = free_and_strdup(&c->cgroup, item->str);
543 if (r < 0)
544 return r;
545
546 r = bus_get_root_path(bus);
547 if (r < 0)
548 return r;
549
550 r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
551 if (r < 0)
552 return r;
553
554 c->mask |= m;
555 }
556 break;
557
558 case KDBUS_ITEM_CAPS:
559 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
560 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
561
562 if (m) {
563 if (item->caps.last_cap != cap_last_cap() ||
564 item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
565 return -EBADMSG;
566
567 c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
568 if (!c->capability)
569 return -ENOMEM;
570
571 c->mask |= m;
572 }
573 break;
574
575 case KDBUS_ITEM_SECLABEL:
576 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
577 r = free_and_strdup(&c->label, item->str);
578 if (r < 0)
579 return r;
580
581 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
582 }
583 break;
584
585 case KDBUS_ITEM_AUDIT:
586 if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
587 c->audit_session_id = (uint32_t) item->audit.sessionid;
588 c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
589 }
590
591 if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
592 c->audit_login_uid = (uid_t) item->audit.loginuid;
593 c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
594 }
595 break;
596
597 case KDBUS_ITEM_OWNED_NAME:
598 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
599 r = strv_extend(&c->well_known_names, item->name.name);
600 if (r < 0)
601 return r;
602
603 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
604 }
605 break;
606
607 case KDBUS_ITEM_CONN_DESCRIPTION:
608 if (mask & SD_BUS_CREDS_DESCRIPTION) {
609 r = free_and_strdup(&c->description, item->str);
610 if (r < 0)
611 return r;
612
613 c->mask |= SD_BUS_CREDS_DESCRIPTION;
614 }
615 break;
616
617 case KDBUS_ITEM_AUXGROUPS:
618 if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
619 size_t i, n;
620 uid_t *g;
621
622 n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
623 g = new(gid_t, n);
624 if (!g)
625 return -ENOMEM;
626
627 for (i = 0; i < n; i++)
628 g[i] = item->data64[i];
629
630 free(c->supplementary_gids);
631 c->supplementary_gids = g;
632 c->n_supplementary_gids = n;
633
634 c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
635 }
636 break;
637 }
638 }
639
640 return 0;
641 }
642
643 int bus_get_name_creds_kdbus(
644 sd_bus *bus,
645 const char *name,
646 uint64_t mask,
647 bool allow_activator,
648 sd_bus_creds **creds) {
649
650 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
651 struct kdbus_cmd_info *cmd;
652 struct kdbus_info *conn_info;
653 size_t size, l;
654 uint64_t id;
655 int r;
656
657 if (streq(name, "org.freedesktop.DBus"))
658 return -EOPNOTSUPP;
659
660 r = bus_kernel_parse_unique_name(name, &id);
661 if (r < 0)
662 return r;
663 if (r > 0) {
664 size = offsetof(struct kdbus_cmd_info, items);
665 cmd = alloca0_align(size, 8);
666 cmd->id = id;
667 } else {
668 l = strlen(name) + 1;
669 size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
670 cmd = alloca0_align(size, 8);
671 cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
672 cmd->items[0].type = KDBUS_ITEM_NAME;
673 memcpy(cmd->items[0].str, name, l);
674 }
675
676 /* If augmentation is on, and the bus didn't provide us
677 * the bits we want, then ask for the PID/TID so that we
678 * can read the rest from /proc. */
679 if ((mask & SD_BUS_CREDS_AUGMENT) &&
680 (mask & (SD_BUS_CREDS_PPID|
681 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
682 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
683 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
684 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|
685 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
686 SD_BUS_CREDS_SELINUX_CONTEXT|
687 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
688 mask |= SD_BUS_CREDS_PID;
689
690 cmd->size = size;
691 cmd->attach_flags = attach_flags_to_kdbus(mask);
692
693 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
694 if (r < 0)
695 return -errno;
696
697 conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
698
699 /* Non-activated names are considered not available */
700 if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
701 if (name[0] == ':')
702 r = -ENXIO;
703 else
704 r = -ESRCH;
705 goto fail;
706 }
707
708 c = bus_creds_new();
709 if (!c) {
710 r = -ENOMEM;
711 goto fail;
712 }
713
714 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
715 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) {
716 r = -ENOMEM;
717 goto fail;
718 }
719
720 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
721 }
722
723 /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
724 them in case the service has no names. This does not mean
725 however that the list of owned names could not be
726 acquired. Hence, let's explicitly clarify that the data is
727 complete. */
728 c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
729
730 r = bus_populate_creds_from_items(bus, conn_info, mask, c);
731 if (r < 0)
732 goto fail;
733
734 r = bus_creds_add_more(c, mask, 0, 0);
735 if (r < 0)
736 goto fail;
737
738 if (creds) {
739 *creds = c;
740 c = NULL;
741 }
742
743 r = 0;
744
745 fail:
746 bus_kernel_cmd_free(bus, cmd->offset);
747 return r;
748 }
749
750 static int bus_get_name_creds_dbus1(
751 sd_bus *bus,
752 const char *name,
753 uint64_t mask,
754 sd_bus_creds **creds) {
755
756 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
757 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
758 const char *unique = NULL;
759 pid_t pid = 0;
760 int r;
761
762 /* Only query the owner if the caller wants to know it or if
763 * the caller just wants to check whether a name exists */
764 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
765 r = sd_bus_call_method(
766 bus,
767 "org.freedesktop.DBus",
768 "/org/freedesktop/DBus",
769 "org.freedesktop.DBus",
770 "GetNameOwner",
771 NULL,
772 &reply_unique,
773 "s",
774 name);
775 if (r < 0)
776 return r;
777
778 r = sd_bus_message_read(reply_unique, "s", &unique);
779 if (r < 0)
780 return r;
781 }
782
783 if (mask != 0) {
784 c = bus_creds_new();
785 if (!c)
786 return -ENOMEM;
787
788 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
789 c->unique_name = strdup(unique);
790 if (!c->unique_name)
791 return -ENOMEM;
792
793 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
794 }
795
796 if ((mask & SD_BUS_CREDS_PID) ||
797 ((mask & SD_BUS_CREDS_AUGMENT) &&
798 (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
799 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
800 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
801 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|
802 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
803 SD_BUS_CREDS_SELINUX_CONTEXT|
804 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
805
806 uint32_t u;
807
808 r = sd_bus_call_method(
809 bus,
810 "org.freedesktop.DBus",
811 "/org/freedesktop/DBus",
812 "org.freedesktop.DBus",
813 "GetConnectionUnixProcessID",
814 NULL,
815 &reply,
816 "s",
817 unique ? unique : name);
818 if (r < 0)
819 return r;
820
821 r = sd_bus_message_read(reply, "u", &u);
822 if (r < 0)
823 return r;
824
825 pid = u;
826 if (mask & SD_BUS_CREDS_PID) {
827 c->pid = u;
828 c->mask |= SD_BUS_CREDS_PID;
829 }
830
831 reply = sd_bus_message_unref(reply);
832 }
833
834 if (mask & SD_BUS_CREDS_EUID) {
835 uint32_t u;
836
837 r = sd_bus_call_method(
838 bus,
839 "org.freedesktop.DBus",
840 "/org/freedesktop/DBus",
841 "org.freedesktop.DBus",
842 "GetConnectionUnixUser",
843 NULL,
844 &reply,
845 "s",
846 unique ? unique : name);
847 if (r < 0)
848 return r;
849
850 r = sd_bus_message_read(reply, "u", &u);
851 if (r < 0)
852 return r;
853
854 c->euid = u;
855 c->mask |= SD_BUS_CREDS_EUID;
856
857 reply = sd_bus_message_unref(reply);
858 }
859
860 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
861 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
862 const void *p = NULL;
863 size_t sz = 0;
864
865 r = sd_bus_call_method(
866 bus,
867 "org.freedesktop.DBus",
868 "/org/freedesktop/DBus",
869 "org.freedesktop.DBus",
870 "GetConnectionSELinuxSecurityContext",
871 &error,
872 &reply,
873 "s",
874 unique ? unique : name);
875 if (r < 0) {
876 if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
877 return r;
878 } else {
879 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
880 if (r < 0)
881 return r;
882
883 c->label = strndup(p, sz);
884 if (!c->label)
885 return -ENOMEM;
886
887 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
888 }
889 }
890
891 r = bus_creds_add_more(c, mask, pid, 0);
892 if (r < 0)
893 return r;
894 }
895
896 if (creds) {
897 *creds = c;
898 c = NULL;
899 }
900
901 return 0;
902 }
903
904 _public_ int sd_bus_get_name_creds(
905 sd_bus *bus,
906 const char *name,
907 uint64_t mask,
908 sd_bus_creds **creds) {
909
910 assert_return(bus, -EINVAL);
911 assert_return(name, -EINVAL);
912 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
913 assert_return(mask == 0 || creds, -EINVAL);
914 assert_return(!bus_pid_changed(bus), -ECHILD);
915 assert_return(service_name_is_valid(name), -EINVAL);
916
917 if (!bus->bus_client)
918 return -EINVAL;
919
920 if (streq(name, "org.freedesktop.DBus.Local"))
921 return -EINVAL;
922
923 if (!BUS_IS_OPEN(bus->state))
924 return -ENOTCONN;
925
926 if (bus->is_kernel)
927 return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
928 else
929 return bus_get_name_creds_dbus1(bus, name, mask, creds);
930 }
931
932 static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
933 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
934 struct kdbus_cmd_info cmd = {
935 .size = sizeof(struct kdbus_cmd_info),
936 };
937 struct kdbus_info *creator_info;
938 pid_t pid = 0;
939 int r;
940
941 c = bus_creds_new();
942 if (!c)
943 return -ENOMEM;
944
945 /* If augmentation is on, and the bus doesn't didn't allow us
946 * to get the bits we want, then ask for the PID/TID so that we
947 * can read the rest from /proc. */
948 if ((mask & SD_BUS_CREDS_AUGMENT) &&
949 (mask & (SD_BUS_CREDS_PPID|
950 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
951 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
952 SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
953 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|
954 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
955 SD_BUS_CREDS_SELINUX_CONTEXT|
956 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
957 mask |= SD_BUS_CREDS_PID;
958
959 cmd.attach_flags = attach_flags_to_kdbus(mask);
960
961 r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
962 if (r < 0)
963 return -errno;
964
965 creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
966
967 r = bus_populate_creds_from_items(bus, creator_info, mask, c);
968 bus_kernel_cmd_free(bus, cmd.offset);
969 if (r < 0)
970 return r;
971
972 r = bus_creds_add_more(c, mask, pid, 0);
973 if (r < 0)
974 return r;
975
976 *ret = c;
977 c = NULL;
978 return 0;
979 }
980
981 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
982 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
983 pid_t pid = 0;
984 bool do_label;
985 int r;
986
987 assert(bus);
988
989 do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
990
991 /* Avoid allocating anything if we have no chance of returning useful data */
992 if (!bus->ucred_valid && !do_label)
993 return -ENODATA;
994
995 c = bus_creds_new();
996 if (!c)
997 return -ENOMEM;
998
999 if (bus->ucred_valid) {
1000 if (bus->ucred.pid > 0) {
1001 pid = c->pid = bus->ucred.pid;
1002 c->mask |= SD_BUS_CREDS_PID & mask;
1003 }
1004
1005 if (bus->ucred.uid != UID_INVALID) {
1006 c->euid = bus->ucred.uid;
1007 c->mask |= SD_BUS_CREDS_EUID & mask;
1008 }
1009
1010 if (bus->ucred.gid != GID_INVALID) {
1011 c->egid = bus->ucred.gid;
1012 c->mask |= SD_BUS_CREDS_EGID & mask;
1013 }
1014 }
1015
1016 if (do_label) {
1017 c->label = strdup(bus->label);
1018 if (!c->label)
1019 return -ENOMEM;
1020
1021 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1022 }
1023
1024 r = bus_creds_add_more(c, mask, pid, 0);
1025 if (r < 0)
1026 return r;
1027
1028 *ret = c;
1029 c = NULL;
1030 return 0;
1031 }
1032
1033 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1034 assert_return(bus, -EINVAL);
1035 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1036 assert_return(ret, -EINVAL);
1037 assert_return(!bus_pid_changed(bus), -ECHILD);
1038
1039 if (!BUS_IS_OPEN(bus->state))
1040 return -ENOTCONN;
1041
1042 if (bus->is_kernel)
1043 return bus_get_owner_creds_kdbus(bus, mask, ret);
1044 else
1045 return bus_get_owner_creds_dbus1(bus, mask, ret);
1046 }
1047
1048 static int add_name_change_match(sd_bus *bus,
1049 uint64_t cookie,
1050 const char *name,
1051 const char *old_owner,
1052 const char *new_owner) {
1053
1054 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1055 int is_name_id = -1, r;
1056 struct kdbus_item *item;
1057
1058 assert(bus);
1059
1060 /* If we encounter a match that could match against
1061 * NameOwnerChanged messages, then we need to create
1062 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1063 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1064 * multiple if the match is underspecified.
1065 *
1066 * The NameOwnerChanged signals take three parameters with
1067 * unique or well-known names, but only some forms actually
1068 * exist:
1069 *
1070 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1071 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1072 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1073 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1074 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1075 *
1076 * For the latter two the two unique names must be identical.
1077 *
1078 * */
1079
1080 if (name) {
1081 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1082 if (is_name_id < 0)
1083 return 0;
1084 }
1085
1086 if (!isempty(old_owner)) {
1087 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1088 if (r < 0)
1089 return 0;
1090 if (r == 0)
1091 return 0;
1092 if (is_name_id > 0 && old_owner_id != name_id)
1093 return 0;
1094 } else
1095 old_owner_id = KDBUS_MATCH_ID_ANY;
1096
1097 if (!isempty(new_owner)) {
1098 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1099 if (r < 0)
1100 return r;
1101 if (r == 0)
1102 return 0;
1103 if (is_name_id > 0 && new_owner_id != name_id)
1104 return 0;
1105 } else
1106 new_owner_id = KDBUS_MATCH_ID_ANY;
1107
1108 if (is_name_id <= 0) {
1109 struct kdbus_cmd_match *m;
1110 size_t sz, l;
1111
1112 /* If the name argument is missing or is a well-known
1113 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1114 * matches for it */
1115
1116 l = name ? strlen(name) + 1 : 0;
1117
1118 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1119 offsetof(struct kdbus_item, name_change) +
1120 offsetof(struct kdbus_notify_name_change, name) +
1121 l);
1122
1123 m = alloca0_align(sz, 8);
1124 m->size = sz;
1125 m->cookie = cookie;
1126
1127 item = m->items;
1128 item->size =
1129 offsetof(struct kdbus_item, name_change) +
1130 offsetof(struct kdbus_notify_name_change, name) +
1131 l;
1132
1133 item->name_change.old_id.id = old_owner_id;
1134 item->name_change.new_id.id = new_owner_id;
1135
1136 if (name)
1137 memcpy(item->name_change.name, name, l);
1138
1139 /* If the old name is unset or empty, then
1140 * this can match against added names */
1141 if (isempty(old_owner)) {
1142 item->type = KDBUS_ITEM_NAME_ADD;
1143
1144 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1145 if (r < 0)
1146 return -errno;
1147 }
1148
1149 /* If the new name is unset or empty, then
1150 * this can match against removed names */
1151 if (isempty(new_owner)) {
1152 item->type = KDBUS_ITEM_NAME_REMOVE;
1153
1154 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1155 if (r < 0)
1156 return -errno;
1157 }
1158
1159 /* The CHANGE match we need in either case, because
1160 * what is reported as a name change by the kernel
1161 * might just be an owner change between starter and
1162 * normal clients. For userspace such a change should
1163 * be considered a removal/addition, hence let's
1164 * subscribe to this unconditionally. */
1165 item->type = KDBUS_ITEM_NAME_CHANGE;
1166 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1167 if (r < 0)
1168 return -errno;
1169 }
1170
1171 if (is_name_id != 0) {
1172 struct kdbus_cmd_match *m;
1173 uint64_t sz;
1174
1175 /* If the name argument is missing or is a unique
1176 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1177 * for it */
1178
1179 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1180 offsetof(struct kdbus_item, id_change) +
1181 sizeof(struct kdbus_notify_id_change));
1182
1183 m = alloca0_align(sz, 8);
1184 m->size = sz;
1185 m->cookie = cookie;
1186
1187 item = m->items;
1188 item->size =
1189 offsetof(struct kdbus_item, id_change) +
1190 sizeof(struct kdbus_notify_id_change);
1191 item->id_change.id = name_id;
1192
1193 /* If the old name is unset or empty, then this can
1194 * match against added ids */
1195 if (isempty(old_owner)) {
1196 item->type = KDBUS_ITEM_ID_ADD;
1197 if (!isempty(new_owner))
1198 item->id_change.id = new_owner_id;
1199
1200 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1201 if (r < 0)
1202 return -errno;
1203 }
1204
1205 /* If thew new name is unset or empty, then this can
1206 * match against removed ids */
1207 if (isempty(new_owner)) {
1208 item->type = KDBUS_ITEM_ID_REMOVE;
1209 if (!isempty(old_owner))
1210 item->id_change.id = old_owner_id;
1211
1212 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1213 if (r < 0)
1214 return -errno;
1215 }
1216 }
1217
1218 return 0;
1219 }
1220
1221 int bus_add_match_internal_kernel(
1222 sd_bus *bus,
1223 struct bus_match_component *components,
1224 unsigned n_components,
1225 uint64_t cookie) {
1226
1227 struct kdbus_cmd_match *m;
1228 struct kdbus_item *item;
1229 uint64_t *bloom;
1230 size_t sz;
1231 const char *sender = NULL;
1232 size_t sender_length = 0;
1233 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1234 bool using_bloom = false;
1235 unsigned i;
1236 bool matches_name_change = true;
1237 const char *name_change_arg[3] = {};
1238 int r;
1239
1240 assert(bus);
1241
1242 /* Monitor streams don't support matches, make this a NOP */
1243 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1244 return 0;
1245
1246 bloom = alloca0(bus->bloom_size);
1247
1248 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1249
1250 for (i = 0; i < n_components; i++) {
1251 struct bus_match_component *c = &components[i];
1252
1253 switch (c->type) {
1254
1255 case BUS_MATCH_SENDER:
1256 if (!streq(c->value_str, "org.freedesktop.DBus"))
1257 matches_name_change = false;
1258
1259 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1260 if (r < 0)
1261 return r;
1262 else if (r > 0)
1263 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1264 else {
1265 sender = c->value_str;
1266 sender_length = strlen(sender);
1267 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1268 }
1269
1270 break;
1271
1272 case BUS_MATCH_MESSAGE_TYPE:
1273 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1274 matches_name_change = false;
1275
1276 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1277 using_bloom = true;
1278 break;
1279
1280 case BUS_MATCH_INTERFACE:
1281 if (!streq(c->value_str, "org.freedesktop.DBus"))
1282 matches_name_change = false;
1283
1284 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1285 using_bloom = true;
1286 break;
1287
1288 case BUS_MATCH_MEMBER:
1289 if (!streq(c->value_str, "NameOwnerChanged"))
1290 matches_name_change = false;
1291
1292 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1293 using_bloom = true;
1294 break;
1295
1296 case BUS_MATCH_PATH:
1297 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1298 matches_name_change = false;
1299
1300 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1301 using_bloom = true;
1302 break;
1303
1304 case BUS_MATCH_PATH_NAMESPACE:
1305 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1306 using_bloom = true;
1307 break;
1308
1309 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1310 char buf[sizeof("arg")-1 + 2 + 1];
1311
1312 if (c->type - BUS_MATCH_ARG < 3)
1313 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1314
1315 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1316 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1317 using_bloom = true;
1318 break;
1319 }
1320
1321 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1322 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1323
1324 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1325 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1326 using_bloom = true;
1327 break;
1328 }
1329
1330 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1331 /*
1332 * XXX: DBus spec defines arg[0..63]path= matching to be
1333 * a two-way glob. That is, if either string is a prefix
1334 * of the other, it matches.
1335 * This is really hard to realize in bloom-filters, as
1336 * we would have to create a bloom-match for each prefix
1337 * of @c->value_str. This is excessive, hence we just
1338 * ignore all those matches and accept everything from
1339 * the kernel. People should really avoid those matches.
1340 * If they're used in real-life some day, we will have
1341 * to properly support multiple-matches here.
1342 */
1343 break;
1344
1345 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1346 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1347
1348 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1349 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1350 using_bloom = true;
1351 break;
1352 }
1353
1354 case BUS_MATCH_DESTINATION:
1355 /*
1356 * Kernel only supports matching on destination IDs, but
1357 * not on destination names. So just skip the
1358 * destination name restriction and verify it in
1359 * user-space on retrieval.
1360 */
1361 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1362 if (r < 0)
1363 return r;
1364 else if (r > 0)
1365 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1366
1367 /* if not a broadcast, it cannot be a name-change */
1368 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1369 matches_name_change = false;
1370
1371 break;
1372
1373 case BUS_MATCH_ROOT:
1374 case BUS_MATCH_VALUE:
1375 case BUS_MATCH_LEAF:
1376 case _BUS_MATCH_NODE_TYPE_MAX:
1377 case _BUS_MATCH_NODE_TYPE_INVALID:
1378 assert_not_reached("Invalid match type?");
1379 }
1380 }
1381
1382 if (using_bloom)
1383 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1384
1385 m = alloca0_align(sz, 8);
1386 m->size = sz;
1387 m->cookie = cookie;
1388
1389 item = m->items;
1390
1391 if (src_id != KDBUS_MATCH_ID_ANY) {
1392 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1393 item->type = KDBUS_ITEM_ID;
1394 item->id = src_id;
1395 item = KDBUS_ITEM_NEXT(item);
1396 }
1397
1398 if (dst_id != KDBUS_MATCH_ID_ANY) {
1399 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1400 item->type = KDBUS_ITEM_DST_ID;
1401 item->id = dst_id;
1402 item = KDBUS_ITEM_NEXT(item);
1403 }
1404
1405 if (using_bloom) {
1406 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1407 item->type = KDBUS_ITEM_BLOOM_MASK;
1408 memcpy(item->data64, bloom, bus->bloom_size);
1409 item = KDBUS_ITEM_NEXT(item);
1410 }
1411
1412 if (sender) {
1413 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1414 item->type = KDBUS_ITEM_NAME;
1415 memcpy(item->str, sender, sender_length + 1);
1416 }
1417
1418 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1419 if (r < 0)
1420 return -errno;
1421
1422 if (matches_name_change) {
1423
1424 /* If this match could theoretically match
1425 * NameOwnerChanged messages, we need to
1426 * install a second non-bloom filter explitly
1427 * for it */
1428
1429 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1430 if (r < 0)
1431 return r;
1432 }
1433
1434 return 0;
1435 }
1436
1437 #define internal_match(bus, m) \
1438 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1439 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1440 : (m))
1441
1442 static int bus_add_match_internal_dbus1(
1443 sd_bus *bus,
1444 const char *match) {
1445
1446 const char *e;
1447
1448 assert(bus);
1449 assert(match);
1450
1451 e = internal_match(bus, match);
1452
1453 return sd_bus_call_method(
1454 bus,
1455 "org.freedesktop.DBus",
1456 "/org/freedesktop/DBus",
1457 "org.freedesktop.DBus",
1458 "AddMatch",
1459 NULL,
1460 NULL,
1461 "s",
1462 e);
1463 }
1464
1465 int bus_add_match_internal(
1466 sd_bus *bus,
1467 const char *match,
1468 struct bus_match_component *components,
1469 unsigned n_components,
1470 uint64_t cookie) {
1471
1472 assert(bus);
1473
1474 if (!bus->bus_client)
1475 return -EINVAL;
1476
1477 if (bus->is_kernel)
1478 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1479 else
1480 return bus_add_match_internal_dbus1(bus, match);
1481 }
1482
1483 int bus_remove_match_internal_kernel(
1484 sd_bus *bus,
1485 uint64_t cookie) {
1486
1487 struct kdbus_cmd_match m = {
1488 .size = offsetof(struct kdbus_cmd_match, items),
1489 .cookie = cookie,
1490 };
1491 int r;
1492
1493 assert(bus);
1494
1495 /* Monitor streams don't support matches, make this a NOP */
1496 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1497 return 0;
1498
1499 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1500 if (r < 0)
1501 return -errno;
1502
1503 return 0;
1504 }
1505
1506 static int bus_remove_match_internal_dbus1(
1507 sd_bus *bus,
1508 const char *match) {
1509
1510 const char *e;
1511
1512 assert(bus);
1513 assert(match);
1514
1515 e = internal_match(bus, match);
1516
1517 return sd_bus_call_method(
1518 bus,
1519 "org.freedesktop.DBus",
1520 "/org/freedesktop/DBus",
1521 "org.freedesktop.DBus",
1522 "RemoveMatch",
1523 NULL,
1524 NULL,
1525 "s",
1526 e);
1527 }
1528
1529 int bus_remove_match_internal(
1530 sd_bus *bus,
1531 const char *match,
1532 uint64_t cookie) {
1533
1534 assert(bus);
1535
1536 if (!bus->bus_client)
1537 return -EINVAL;
1538
1539 if (bus->is_kernel)
1540 return bus_remove_match_internal_kernel(bus, cookie);
1541 else
1542 return bus_remove_match_internal_dbus1(bus, match);
1543 }
1544
1545 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1546 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1547 const char *mid;
1548 int r;
1549
1550 assert_return(bus, -EINVAL);
1551 assert_return(name, -EINVAL);
1552 assert_return(machine, -EINVAL);
1553 assert_return(!bus_pid_changed(bus), -ECHILD);
1554 assert_return(service_name_is_valid(name), -EINVAL);
1555
1556 if (!bus->bus_client)
1557 return -EINVAL;
1558
1559 if (!BUS_IS_OPEN(bus->state))
1560 return -ENOTCONN;
1561
1562 if (streq_ptr(name, bus->unique_name))
1563 return sd_id128_get_machine(machine);
1564
1565 r = sd_bus_message_new_method_call(
1566 bus,
1567 &m,
1568 name,
1569 "/",
1570 "org.freedesktop.DBus.Peer",
1571 "GetMachineId");
1572 if (r < 0)
1573 return r;
1574
1575 r = sd_bus_message_set_auto_start(m, false);
1576 if (r < 0)
1577 return r;
1578
1579 r = sd_bus_call(bus, m, 0, NULL, &reply);
1580 if (r < 0)
1581 return r;
1582
1583 r = sd_bus_message_read(reply, "s", &mid);
1584 if (r < 0)
1585 return r;
1586
1587 return sd_id128_from_string(mid, machine);
1588 }