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