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