]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-control.c
util-lib: split out allocation calls into alloc-util.[ch]
[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 "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 int r;
985 bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
986
987 /* Avoid allocating anything if we have no chance of returning useful data */
988 if (!bus->ucred_valid && !do_label)
989 return -ENODATA;
990
991 c = bus_creds_new();
992 if (!c)
993 return -ENOMEM;
994
995 if (bus->ucred_valid) {
996 if (bus->ucred.pid > 0) {
997 pid = c->pid = bus->ucred.pid;
998 c->mask |= SD_BUS_CREDS_PID & mask;
999 }
1000
1001 if (bus->ucred.uid != UID_INVALID) {
1002 c->euid = bus->ucred.uid;
1003 c->mask |= SD_BUS_CREDS_EUID & mask;
1004 }
1005
1006 if (bus->ucred.gid != GID_INVALID) {
1007 c->egid = bus->ucred.gid;
1008 c->mask |= SD_BUS_CREDS_EGID & mask;
1009 }
1010 }
1011
1012 if (do_label) {
1013 c->label = strdup(bus->label);
1014 if (!c->label)
1015 return -ENOMEM;
1016
1017 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
1018 }
1019
1020 r = bus_creds_add_more(c, mask, pid, 0);
1021 if (r < 0)
1022 return r;
1023
1024 *ret = c;
1025 c = NULL;
1026 return 0;
1027 }
1028
1029 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
1030 assert_return(bus, -EINVAL);
1031 assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
1032 assert_return(ret, -EINVAL);
1033 assert_return(!bus_pid_changed(bus), -ECHILD);
1034
1035 if (!BUS_IS_OPEN(bus->state))
1036 return -ENOTCONN;
1037
1038 if (bus->is_kernel)
1039 return bus_get_owner_creds_kdbus(bus, mask, ret);
1040 else
1041 return bus_get_owner_creds_dbus1(bus, mask, ret);
1042 }
1043
1044 static int add_name_change_match(sd_bus *bus,
1045 uint64_t cookie,
1046 const char *name,
1047 const char *old_owner,
1048 const char *new_owner) {
1049
1050 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
1051 int is_name_id = -1, r;
1052 struct kdbus_item *item;
1053
1054 assert(bus);
1055
1056 /* If we encounter a match that could match against
1057 * NameOwnerChanged messages, then we need to create
1058 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
1059 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
1060 * multiple if the match is underspecified.
1061 *
1062 * The NameOwnerChanged signals take three parameters with
1063 * unique or well-known names, but only some forms actually
1064 * exist:
1065 *
1066 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
1067 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
1068 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
1069 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
1070 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
1071 *
1072 * For the latter two the two unique names must be identical.
1073 *
1074 * */
1075
1076 if (name) {
1077 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
1078 if (is_name_id < 0)
1079 return 0;
1080 }
1081
1082 if (!isempty(old_owner)) {
1083 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
1084 if (r < 0)
1085 return 0;
1086 if (r == 0)
1087 return 0;
1088 if (is_name_id > 0 && old_owner_id != name_id)
1089 return 0;
1090 } else
1091 old_owner_id = KDBUS_MATCH_ID_ANY;
1092
1093 if (!isempty(new_owner)) {
1094 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
1095 if (r < 0)
1096 return r;
1097 if (r == 0)
1098 return 0;
1099 if (is_name_id > 0 && new_owner_id != name_id)
1100 return 0;
1101 } else
1102 new_owner_id = KDBUS_MATCH_ID_ANY;
1103
1104 if (is_name_id <= 0) {
1105 struct kdbus_cmd_match *m;
1106 size_t sz, l;
1107
1108 /* If the name argument is missing or is a well-known
1109 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
1110 * matches for it */
1111
1112 l = name ? strlen(name) + 1 : 0;
1113
1114 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1115 offsetof(struct kdbus_item, name_change) +
1116 offsetof(struct kdbus_notify_name_change, name) +
1117 l);
1118
1119 m = alloca0_align(sz, 8);
1120 m->size = sz;
1121 m->cookie = cookie;
1122
1123 item = m->items;
1124 item->size =
1125 offsetof(struct kdbus_item, name_change) +
1126 offsetof(struct kdbus_notify_name_change, name) +
1127 l;
1128
1129 item->name_change.old_id.id = old_owner_id;
1130 item->name_change.new_id.id = new_owner_id;
1131
1132 if (name)
1133 memcpy(item->name_change.name, name, l);
1134
1135 /* If the old name is unset or empty, then
1136 * this can match against added names */
1137 if (isempty(old_owner)) {
1138 item->type = KDBUS_ITEM_NAME_ADD;
1139
1140 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1141 if (r < 0)
1142 return -errno;
1143 }
1144
1145 /* If the new name is unset or empty, then
1146 * this can match against removed names */
1147 if (isempty(new_owner)) {
1148 item->type = KDBUS_ITEM_NAME_REMOVE;
1149
1150 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1151 if (r < 0)
1152 return -errno;
1153 }
1154
1155 /* The CHANGE match we need in either case, because
1156 * what is reported as a name change by the kernel
1157 * might just be an owner change between starter and
1158 * normal clients. For userspace such a change should
1159 * be considered a removal/addition, hence let's
1160 * subscribe to this unconditionally. */
1161 item->type = KDBUS_ITEM_NAME_CHANGE;
1162 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1163 if (r < 0)
1164 return -errno;
1165 }
1166
1167 if (is_name_id != 0) {
1168 struct kdbus_cmd_match *m;
1169 uint64_t sz;
1170
1171 /* If the name argument is missing or is a unique
1172 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
1173 * for it */
1174
1175 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1176 offsetof(struct kdbus_item, id_change) +
1177 sizeof(struct kdbus_notify_id_change));
1178
1179 m = alloca0_align(sz, 8);
1180 m->size = sz;
1181 m->cookie = cookie;
1182
1183 item = m->items;
1184 item->size =
1185 offsetof(struct kdbus_item, id_change) +
1186 sizeof(struct kdbus_notify_id_change);
1187 item->id_change.id = name_id;
1188
1189 /* If the old name is unset or empty, then this can
1190 * match against added ids */
1191 if (isempty(old_owner)) {
1192 item->type = KDBUS_ITEM_ID_ADD;
1193 if (!isempty(new_owner))
1194 item->id_change.id = new_owner_id;
1195
1196 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1197 if (r < 0)
1198 return -errno;
1199 }
1200
1201 /* If thew new name is unset or empty, then this can
1202 * match against removed ids */
1203 if (isempty(new_owner)) {
1204 item->type = KDBUS_ITEM_ID_REMOVE;
1205 if (!isempty(old_owner))
1206 item->id_change.id = old_owner_id;
1207
1208 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1209 if (r < 0)
1210 return -errno;
1211 }
1212 }
1213
1214 return 0;
1215 }
1216
1217 int bus_add_match_internal_kernel(
1218 sd_bus *bus,
1219 struct bus_match_component *components,
1220 unsigned n_components,
1221 uint64_t cookie) {
1222
1223 struct kdbus_cmd_match *m;
1224 struct kdbus_item *item;
1225 uint64_t *bloom;
1226 size_t sz;
1227 const char *sender = NULL;
1228 size_t sender_length = 0;
1229 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
1230 bool using_bloom = false;
1231 unsigned i;
1232 bool matches_name_change = true;
1233 const char *name_change_arg[3] = {};
1234 int r;
1235
1236 assert(bus);
1237
1238 /* Monitor streams don't support matches, make this a NOP */
1239 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1240 return 0;
1241
1242 bloom = alloca0(bus->bloom_size);
1243
1244 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
1245
1246 for (i = 0; i < n_components; i++) {
1247 struct bus_match_component *c = &components[i];
1248
1249 switch (c->type) {
1250
1251 case BUS_MATCH_SENDER:
1252 if (!streq(c->value_str, "org.freedesktop.DBus"))
1253 matches_name_change = false;
1254
1255 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1256 if (r < 0)
1257 return r;
1258 else if (r > 0)
1259 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1260 else {
1261 sender = c->value_str;
1262 sender_length = strlen(sender);
1263 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1264 }
1265
1266 break;
1267
1268 case BUS_MATCH_MESSAGE_TYPE:
1269 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1270 matches_name_change = false;
1271
1272 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
1273 using_bloom = true;
1274 break;
1275
1276 case BUS_MATCH_INTERFACE:
1277 if (!streq(c->value_str, "org.freedesktop.DBus"))
1278 matches_name_change = false;
1279
1280 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
1281 using_bloom = true;
1282 break;
1283
1284 case BUS_MATCH_MEMBER:
1285 if (!streq(c->value_str, "NameOwnerChanged"))
1286 matches_name_change = false;
1287
1288 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
1289 using_bloom = true;
1290 break;
1291
1292 case BUS_MATCH_PATH:
1293 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1294 matches_name_change = false;
1295
1296 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
1297 using_bloom = true;
1298 break;
1299
1300 case BUS_MATCH_PATH_NAMESPACE:
1301 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1302 using_bloom = true;
1303 break;
1304
1305 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1306 char buf[sizeof("arg")-1 + 2 + 1];
1307
1308 if (c->type - BUS_MATCH_ARG < 3)
1309 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
1310
1311 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
1312 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1313 using_bloom = true;
1314 break;
1315 }
1316
1317 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
1318 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
1319
1320 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
1321 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1322 using_bloom = true;
1323 break;
1324 }
1325
1326 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
1327 /*
1328 * XXX: DBus spec defines arg[0..63]path= matching to be
1329 * a two-way glob. That is, if either string is a prefix
1330 * of the other, it matches.
1331 * This is really hard to realize in bloom-filters, as
1332 * we would have to create a bloom-match for each prefix
1333 * of @c->value_str. This is excessive, hence we just
1334 * ignore all those matches and accept everything from
1335 * the kernel. People should really avoid those matches.
1336 * If they're used in real-life some day, we will have
1337 * to properly support multiple-matches here.
1338 */
1339 break;
1340
1341 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1342 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
1343
1344 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1345 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1346 using_bloom = true;
1347 break;
1348 }
1349
1350 case BUS_MATCH_DESTINATION:
1351 /*
1352 * Kernel only supports matching on destination IDs, but
1353 * not on destination names. So just skip the
1354 * destination name restriction and verify it in
1355 * user-space on retrieval.
1356 */
1357 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1358 if (r < 0)
1359 return r;
1360 else if (r > 0)
1361 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1362
1363 /* if not a broadcast, it cannot be a name-change */
1364 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1365 matches_name_change = false;
1366
1367 break;
1368
1369 case BUS_MATCH_ROOT:
1370 case BUS_MATCH_VALUE:
1371 case BUS_MATCH_LEAF:
1372 case _BUS_MATCH_NODE_TYPE_MAX:
1373 case _BUS_MATCH_NODE_TYPE_INVALID:
1374 assert_not_reached("Invalid match type?");
1375 }
1376 }
1377
1378 if (using_bloom)
1379 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
1380
1381 m = alloca0_align(sz, 8);
1382 m->size = sz;
1383 m->cookie = cookie;
1384
1385 item = m->items;
1386
1387 if (src_id != KDBUS_MATCH_ID_ANY) {
1388 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1389 item->type = KDBUS_ITEM_ID;
1390 item->id = src_id;
1391 item = KDBUS_ITEM_NEXT(item);
1392 }
1393
1394 if (dst_id != KDBUS_MATCH_ID_ANY) {
1395 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1396 item->type = KDBUS_ITEM_DST_ID;
1397 item->id = dst_id;
1398 item = KDBUS_ITEM_NEXT(item);
1399 }
1400
1401 if (using_bloom) {
1402 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
1403 item->type = KDBUS_ITEM_BLOOM_MASK;
1404 memcpy(item->data64, bloom, bus->bloom_size);
1405 item = KDBUS_ITEM_NEXT(item);
1406 }
1407
1408 if (sender) {
1409 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
1410 item->type = KDBUS_ITEM_NAME;
1411 memcpy(item->str, sender, sender_length + 1);
1412 }
1413
1414 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1415 if (r < 0)
1416 return -errno;
1417
1418 if (matches_name_change) {
1419
1420 /* If this match could theoretically match
1421 * NameOwnerChanged messages, we need to
1422 * install a second non-bloom filter explitly
1423 * for it */
1424
1425 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
1426 if (r < 0)
1427 return r;
1428 }
1429
1430 return 0;
1431 }
1432
1433 #define internal_match(bus, m) \
1434 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
1435 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
1436 : (m))
1437
1438 static int bus_add_match_internal_dbus1(
1439 sd_bus *bus,
1440 const char *match) {
1441
1442 const char *e;
1443
1444 assert(bus);
1445 assert(match);
1446
1447 e = internal_match(bus, match);
1448
1449 return sd_bus_call_method(
1450 bus,
1451 "org.freedesktop.DBus",
1452 "/org/freedesktop/DBus",
1453 "org.freedesktop.DBus",
1454 "AddMatch",
1455 NULL,
1456 NULL,
1457 "s",
1458 e);
1459 }
1460
1461 int bus_add_match_internal(
1462 sd_bus *bus,
1463 const char *match,
1464 struct bus_match_component *components,
1465 unsigned n_components,
1466 uint64_t cookie) {
1467
1468 assert(bus);
1469
1470 if (!bus->bus_client)
1471 return -EINVAL;
1472
1473 if (bus->is_kernel)
1474 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
1475 else
1476 return bus_add_match_internal_dbus1(bus, match);
1477 }
1478
1479 int bus_remove_match_internal_kernel(
1480 sd_bus *bus,
1481 uint64_t cookie) {
1482
1483 struct kdbus_cmd_match m = {
1484 .size = offsetof(struct kdbus_cmd_match, items),
1485 .cookie = cookie,
1486 };
1487 int r;
1488
1489 assert(bus);
1490
1491 /* Monitor streams don't support matches, make this a NOP */
1492 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1493 return 0;
1494
1495 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1496 if (r < 0)
1497 return -errno;
1498
1499 return 0;
1500 }
1501
1502 static int bus_remove_match_internal_dbus1(
1503 sd_bus *bus,
1504 const char *match) {
1505
1506 const char *e;
1507
1508 assert(bus);
1509 assert(match);
1510
1511 e = internal_match(bus, match);
1512
1513 return sd_bus_call_method(
1514 bus,
1515 "org.freedesktop.DBus",
1516 "/org/freedesktop/DBus",
1517 "org.freedesktop.DBus",
1518 "RemoveMatch",
1519 NULL,
1520 NULL,
1521 "s",
1522 e);
1523 }
1524
1525 int bus_remove_match_internal(
1526 sd_bus *bus,
1527 const char *match,
1528 uint64_t cookie) {
1529
1530 assert(bus);
1531
1532 if (!bus->bus_client)
1533 return -EINVAL;
1534
1535 if (bus->is_kernel)
1536 return bus_remove_match_internal_kernel(bus, cookie);
1537 else
1538 return bus_remove_match_internal_dbus1(bus, match);
1539 }
1540
1541 _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1542 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1543 const char *mid;
1544 int r;
1545
1546 assert_return(bus, -EINVAL);
1547 assert_return(name, -EINVAL);
1548 assert_return(machine, -EINVAL);
1549 assert_return(!bus_pid_changed(bus), -ECHILD);
1550 assert_return(service_name_is_valid(name), -EINVAL);
1551
1552 if (!bus->bus_client)
1553 return -EINVAL;
1554
1555 if (!BUS_IS_OPEN(bus->state))
1556 return -ENOTCONN;
1557
1558 if (streq_ptr(name, bus->unique_name))
1559 return sd_id128_get_machine(machine);
1560
1561 r = sd_bus_message_new_method_call(
1562 bus,
1563 &m,
1564 name,
1565 "/",
1566 "org.freedesktop.DBus.Peer",
1567 "GetMachineId");
1568 if (r < 0)
1569 return r;
1570
1571 r = sd_bus_message_set_auto_start(m, false);
1572 if (r < 0)
1573 return r;
1574
1575 r = sd_bus_call(bus, m, 0, NULL, &reply);
1576 if (r < 0)
1577 return r;
1578
1579 r = sd_bus_message_read(reply, "s", &mid);
1580 if (r < 0)
1581 return r;
1582
1583 return sd_id128_from_string(mid, machine);
1584 }