]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-control.c
bus: make sd_bus_request_name() and sd_bus_release_name() behave more like other...
[thirdparty/systemd.git] / src / libsystemd-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
31 #include "sd-bus.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35 #include "bus-bloom.h"
36 #include "bus-util.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, unsigned flags) {
54 struct kdbus_cmd_name *n;
55 size_t l;
56 int r;
57
58 assert(bus);
59 assert(name);
60
61 l = strlen(name);
62 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
63 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
64 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
65 memcpy(n->name, name, l+1);
66
67 #ifdef HAVE_VALGRIND_MEMCHECK_H
68 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
69 #endif
70
71 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
72 if (r < 0)
73 return -errno;
74
75 if (n->flags & KDBUS_NAME_IN_QUEUE)
76 return 0;
77
78 return 1;
79 }
80
81 static int bus_request_name_dbus1(sd_bus *bus, const char *name, unsigned flags) {
82 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
83 uint32_t ret;
84 int r;
85
86 assert(bus);
87 assert(name);
88
89 r = sd_bus_call_method(
90 bus,
91 "org.freedesktop.DBus",
92 "/",
93 "org.freedesktop.DBus",
94 "RequestName",
95 NULL,
96 &reply,
97 "su",
98 name,
99 flags);
100 if (r < 0)
101 return r;
102
103 r = sd_bus_message_read(reply, "u", &ret);
104 if (r < 0)
105 return r;
106
107 if (ret == SD_BUS_NAME_ALREADY_OWNER)
108 return -EALREADY;
109 else if (ret == SD_BUS_NAME_EXISTS)
110 return -EEXIST;
111 else if (ret == SD_BUS_NAME_IN_QUEUE)
112 return 0;
113 else
114 return -EIO;
115
116 return 1;
117 }
118
119 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, unsigned flags) {
120 assert_return(bus, -EINVAL);
121 assert_return(name, -EINVAL);
122 assert_return(bus->bus_client, -EINVAL);
123 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
124 assert_return(!bus_pid_changed(bus), -ECHILD);
125 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_DO_NOT_QUEUE)), -EINVAL);
126
127 if (bus->is_kernel)
128 return bus_request_name_kernel(bus, name, flags);
129 else
130 return bus_request_name_dbus1(bus, name, flags);
131 }
132
133 static int bus_release_name_kernel(sd_bus *bus, const char *name) {
134 struct kdbus_cmd_name *n;
135 size_t l;
136 int r;
137
138 assert(bus);
139 assert(name);
140
141 l = strlen(name);
142 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
143 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
144 memcpy(n->name, name, l+1);
145
146 #ifdef HAVE_VALGRIND_MEMCHECK_H
147 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
148 #endif
149 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
150 if (r < 0)
151 return -errno;
152
153 return n->flags;
154 }
155
156 static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
157 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
158 uint32_t ret;
159 int r;
160
161 assert(bus);
162 assert(name);
163
164 r = sd_bus_call_method(
165 bus,
166 "org.freedesktop.DBus",
167 "/",
168 "org.freedesktop.DBus",
169 "ReleaseName",
170 NULL,
171 &reply,
172 "s",
173 name);
174 if (r < 0)
175 return r;
176
177 r = sd_bus_message_read(reply, "u", &ret);
178 if (r < 0)
179 return r;
180 if (ret == SD_BUS_NAME_NON_EXISTENT)
181 return -ENOENT;
182 if (ret == SD_BUS_NAME_NOT_OWNER)
183 return -EADDRNOTAVAIL;
184 if (ret == SD_BUS_NAME_RELEASED)
185 return 0;
186
187 return -EINVAL;
188 }
189
190 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
191 assert_return(bus, -EINVAL);
192 assert_return(name, -EINVAL);
193 assert_return(bus->bus_client, -EINVAL);
194 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
195 assert_return(!bus_pid_changed(bus), -ECHILD);
196
197 if (bus->is_kernel)
198 return bus_release_name_kernel(bus, name);
199 else
200 return bus_release_name_dbus1(bus, name);
201 }
202
203 static int bus_list_names_kernel(sd_bus *bus, char ***l) {
204 _cleanup_free_ struct kdbus_cmd_name_list *cmd = NULL;
205 struct kdbus_name_list *name_list;
206 struct kdbus_cmd_name *name;
207 char **x = NULL;
208 int r;
209
210 cmd = malloc0(sizeof(struct kdbus_cmd_name_list));
211 if (!cmd)
212 return -ENOMEM;
213
214 cmd->size = sizeof(struct kdbus_cmd_name_list);
215 cmd->flags = KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES;
216
217 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, cmd);
218 if (r < 0)
219 return -errno;
220
221 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
222
223 KDBUS_PART_FOREACH(name, name_list, names) {
224 char *n;
225
226 if (name->size > sizeof(*name))
227 n = name->name;
228 else
229 asprintf(&n, ":1.%llu", (unsigned long long) name->id);
230
231 r = strv_extend(&x, n);
232 if (r < 0)
233 return -ENOMEM;
234 }
235
236 r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd->offset);
237 if (r < 0)
238 return -errno;
239
240 *l = x;
241 return 0;
242 }
243
244 static int bus_list_names_dbus1(sd_bus *bus, char ***l) {
245 _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
246 char **x = NULL;
247 int r;
248
249 r = sd_bus_call_method(
250 bus,
251 "org.freedesktop.DBus",
252 "/",
253 "org.freedesktop.DBus",
254 "ListNames",
255 NULL,
256 &reply1,
257 NULL);
258 if (r < 0)
259 return r;
260
261 r = sd_bus_call_method(
262 bus,
263 "org.freedesktop.DBus",
264 "/",
265 "org.freedesktop.DBus",
266 "ListActivatableNames",
267 NULL,
268 &reply2,
269 NULL);
270 if (r < 0)
271 return r;
272
273 r = bus_message_read_strv_extend(reply1, &x);
274 if (r < 0) {
275 strv_free(x);
276 return r;
277 }
278
279 r = bus_message_read_strv_extend(reply2, &x);
280 if (r < 0) {
281 strv_free(x);
282 return r;
283 }
284
285 *l = strv_uniq(x);
286 return 0;
287 }
288
289 _public_ int sd_bus_list_names(sd_bus *bus, char ***l) {
290 assert_return(bus, -EINVAL);
291 assert_return(l, -EINVAL);
292 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
293 assert_return(!bus_pid_changed(bus), -ECHILD);
294
295 if (bus->is_kernel)
296 return bus_list_names_kernel(bus, l);
297 else
298 return bus_list_names_dbus1(bus, l);
299 }
300
301 static int bus_get_owner_kdbus(
302 sd_bus *bus,
303 const char *name,
304 uint64_t mask,
305 sd_bus_creds **creds) {
306
307 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
308 struct kdbus_cmd_conn_info *cmd;
309 struct kdbus_conn_info *conn_info;
310 struct kdbus_item *item;
311 size_t size;
312 uint64_t m, id;
313 int r;
314
315 r = bus_kernel_parse_unique_name(name, &id);
316 if (r < 0)
317 return r;
318 if (r > 0) {
319 size = offsetof(struct kdbus_cmd_conn_info, name);
320 cmd = alloca0(size);
321 cmd->id = id;
322 } else {
323 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
324 cmd = alloca0(size);
325 strcpy(cmd->name, name);
326 }
327
328 cmd->size = size;
329 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
330 if (r < 0)
331 return -errno;
332
333 conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
334
335 c = bus_creds_new();
336 if (!c)
337 return -ENOMEM;
338
339 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
340 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
341 return -ENOMEM;
342
343 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
344 }
345
346 KDBUS_PART_FOREACH(item, conn_info, items) {
347
348 switch (item->type) {
349
350 case KDBUS_ITEM_CREDS:
351 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID |
352 SD_BUS_CREDS_TID | SD_BUS_CREDS_PID_STARTTIME) & mask;
353
354 if (m) {
355 c->uid = item->creds.uid;
356 c->pid = item->creds.pid;
357 c->gid = item->creds.gid;
358 c->tid = item->creds.tid;
359 c->pid_starttime = item->creds.starttime;
360 c->mask |= m;
361 }
362 break;
363
364 case KDBUS_ITEM_PID_COMM:
365 if (mask & SD_BUS_CREDS_COMM) {
366 c->comm = strdup(item->str);
367 if (!c->comm) {
368 r = -ENOMEM;
369 goto fail;
370 }
371
372 c->mask |= SD_BUS_CREDS_COMM;
373 }
374 break;
375
376 case KDBUS_ITEM_TID_COMM:
377 if (mask & SD_BUS_CREDS_TID_COMM) {
378 c->tid_comm = strdup(item->str);
379 if (!c->tid_comm) {
380 r = -ENOMEM;
381 goto fail;
382 }
383
384 c->mask |= SD_BUS_CREDS_TID_COMM;
385 }
386 break;
387
388 case KDBUS_ITEM_EXE:
389 if (mask & SD_BUS_CREDS_EXE) {
390 c->exe = strdup(item->str);
391 if (!c->exe) {
392 r = -ENOMEM;
393 goto fail;
394 }
395
396 c->mask |= SD_BUS_CREDS_EXE;
397 }
398 break;
399
400 case KDBUS_ITEM_CMDLINE:
401 if (mask & SD_BUS_CREDS_CMDLINE) {
402 c->cmdline_size = item->size - KDBUS_PART_HEADER_SIZE;
403 c->cmdline = memdup(item->data, c->cmdline_size);
404 if (!c->cmdline) {
405 r = -ENOMEM;
406 goto fail;
407 }
408
409 c->mask |= SD_BUS_CREDS_CMDLINE;
410 }
411 break;
412
413 case KDBUS_ITEM_CGROUP:
414 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
415 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
416 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
417
418 if (m) {
419 c->cgroup = strdup(item->str);
420 if (!c->cgroup) {
421 r = -ENOMEM;
422 goto fail;
423 }
424
425 c->mask |= m;
426 }
427 break;
428
429 case KDBUS_ITEM_CAPS:
430 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
431 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
432
433 if (m) {
434 c->capability_size = item->size - KDBUS_PART_HEADER_SIZE;
435 c->capability = memdup(item->data, c->capability_size);
436 if (!c->capability) {
437 r = -ENOMEM;
438 goto fail;
439 }
440
441 c->mask |= m;
442 }
443 break;
444
445 case KDBUS_ITEM_SECLABEL:
446 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
447 c->label = strdup(item->str);
448 if (!c->label) {
449 r = -ENOMEM;
450 goto fail;
451 }
452
453 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
454 }
455 break;
456
457 case KDBUS_ITEM_AUDIT:
458 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
459
460 if (m) {
461 c->audit_session_id = item->audit.sessionid;
462 c->audit_login_uid = item->audit.loginuid;
463 c->mask |= m;
464 }
465 break;
466
467 case KDBUS_ITEM_NAMES:
468 if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
469 c->well_known_names_size = item->size - KDBUS_PART_HEADER_SIZE;
470 c->well_known_names = memdup(item->data, c->well_known_names_size);
471 if (!c->well_known_names) {
472 r = -ENOMEM;
473 goto fail;
474 }
475
476 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
477 }
478 break;
479 }
480 }
481
482 if (creds) {
483 *creds = c;
484 c = NULL;
485 }
486
487 r = 0;
488
489 fail:
490 ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
491 return r;
492 }
493
494 static int bus_get_owner_dbus1(
495 sd_bus *bus,
496 const char *name,
497 uint64_t mask,
498 sd_bus_creds **creds) {
499
500 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
501 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
502 const char *unique = NULL;
503 pid_t pid = 0;
504 int r;
505
506 /* Only query the owner if the caller wants to know it or if
507 * the caller just wants to check whether a name exists */
508 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
509 r = sd_bus_call_method(
510 bus,
511 "org.freedesktop.DBus",
512 "/",
513 "org.freedesktop.DBus",
514 "GetNameOwner",
515 NULL,
516 &reply_unique,
517 "s",
518 name);
519 if (r < 0)
520 return r;
521
522 r = sd_bus_message_read(reply_unique, "s", &unique);
523 if (r < 0)
524 return r;
525 }
526
527 if (mask != 0) {
528 c = bus_creds_new();
529 if (!c)
530 return -ENOMEM;
531
532 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
533 c->unique_name = strdup(unique);
534 if (!c->unique_name)
535 return -ENOMEM;
536
537 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
538 }
539
540 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
541 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
542 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|
543 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
544 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
545 uint32_t u;
546
547 r = sd_bus_call_method(
548 bus,
549 "org.freedesktop.DBus",
550 "/",
551 "org.freedesktop.DBus",
552 "GetConnectionUnixProcessID",
553 NULL,
554 &reply,
555 "s",
556 unique ? unique : name);
557 if (r < 0)
558 return r;
559
560 r = sd_bus_message_read(reply, "u", &u);
561 if (r < 0)
562 return r;
563
564 pid = u;
565 if (mask & SD_BUS_CREDS_PID) {
566 c->pid = u;
567 c->mask |= SD_BUS_CREDS_PID;
568 }
569
570 reply = sd_bus_message_unref(reply);
571 }
572
573 if (mask & SD_BUS_CREDS_UID) {
574 uint32_t u;
575
576 r = sd_bus_call_method(
577 bus,
578 "org.freedesktop.DBus",
579 "/",
580 "org.freedesktop.DBus",
581 "GetConnectionUnixUser",
582 NULL,
583 &reply,
584 "s",
585 unique ? unique : name);
586 if (r < 0)
587 return r;
588
589 r = sd_bus_message_read(reply, "u", &u);
590 if (r < 0)
591 return r;
592
593 c->uid = u;
594 c->mask |= SD_BUS_CREDS_UID;
595
596 reply = sd_bus_message_unref(reply);
597 }
598
599 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
600 const void *p;
601 size_t sz;
602
603 r = sd_bus_call_method(
604 bus,
605 "org.freedesktop.DBus",
606 "/",
607 "org.freedesktop.DBus",
608 "GetConnectionSELinuxSecurityContext",
609 NULL,
610 &reply,
611 "s",
612 unique ? unique : name);
613 if (r < 0)
614 return r;
615
616 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
617 if (r < 0)
618 return r;
619
620 c->label = strndup(p, sz);
621 if (!c->label)
622 return -ENOMEM;
623
624 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
625 }
626
627 r = bus_creds_add_more(c, mask, pid, 0);
628 if (r < 0)
629 return r;
630 }
631
632 if (creds) {
633 *creds = c;
634 c = NULL;
635 }
636
637 return 0;
638 }
639
640 _public_ int sd_bus_get_owner(
641 sd_bus *bus,
642 const char *name,
643 uint64_t mask,
644 sd_bus_creds **creds) {
645
646 assert_return(bus, -EINVAL);
647 assert_return(name, -EINVAL);
648 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
649 assert_return(mask == 0 || creds, -EINVAL);
650 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
651 assert_return(!bus_pid_changed(bus), -ECHILD);
652
653 if (bus->is_kernel)
654 return bus_get_owner_kdbus(bus, name, mask, creds);
655 else
656 return bus_get_owner_dbus1(bus, name, mask, creds);
657 }
658
659 static int add_name_change_match(sd_bus *bus,
660 uint64_t cookie,
661 const char *name,
662 const char *old_owner,
663 const char *new_owner) {
664
665 uint64_t name_id = 0, old_owner_id = 0, new_owner_id = 0;
666 int is_name_id = -1, r;
667 struct kdbus_item *item;
668
669 assert(bus);
670
671 /* If we encounter a match that could match against
672 * NameOwnerChanged messages, then we need to create
673 * KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE} and
674 * KDBUS_MATCH_ID_{ADD,REMOVE} matches for it, possibly
675 * multiple if the match is underspecified.
676 *
677 * The NameOwnerChanged signals take three parameters with
678 * unique or well-known names, but only some forms actually
679 * exist:
680 *
681 * WELLKNOWN, "", UNIQUE → KDBUS_MATCH_NAME_ADD
682 * WELLKNOWN, UNIQUE, "" → KDBUS_MATCH_NAME_REMOVE
683 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_MATCH_NAME_CHANGE
684 * UNIQUE, "", UNIQUE → KDBUS_MATCH_ID_ADD
685 * UNIQUE, UNIQUE, "" → KDBUS_MATCH_ID_REMOVE
686 *
687 * For the latter two the two unique names must be identical.
688 *
689 * */
690
691 if (name) {
692 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
693 if (is_name_id < 0)
694 return 0;
695 }
696
697 if (old_owner) {
698 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
699 if (r < 0)
700 return 0;
701 if (r == 0)
702 return 0;
703 if (is_name_id > 0 && old_owner_id != name_id)
704 return 0;
705 }
706
707 if (new_owner) {
708 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
709 if (r < 0)
710 return r;
711 if (r == 0)
712 return 0;
713 if (is_name_id > 0 && new_owner_id != name_id)
714 return 0;
715 }
716
717 if (is_name_id <= 0) {
718 struct kdbus_cmd_match *m;
719 size_t sz, l;
720
721 /* If the name argument is missing or is a well-known
722 * name, then add KDBUS_MATCH_NAME_{ADD,REMOVE,CHANGE}
723 * matches for it */
724
725 l = name ? strlen(name) : 0;
726
727 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
728 offsetof(struct kdbus_item, name_change) +
729 offsetof(struct kdbus_notify_name_change, name) +
730 l+1);
731
732 m = alloca0(sz);
733 m->size = sz;
734 m->cookie = cookie;
735 m->src_id = KDBUS_SRC_ID_KERNEL;
736
737 item = m->items;
738 item->size =
739 offsetof(struct kdbus_item, name_change) +
740 offsetof(struct kdbus_notify_name_change, name) +
741 l+1;
742
743 item->name_change.old_id = old_owner_id;
744 item->name_change.new_id = new_owner_id;
745
746 if (name)
747 strcpy(item->name_change.name, name);
748
749 /* If the old name is unset or empty, then
750 * this can match against added names */
751 if (!old_owner || old_owner[0] == 0) {
752 item->type = KDBUS_MATCH_NAME_ADD;
753
754 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
755 if (r < 0)
756 return -errno;
757 }
758
759 /* If the new name is unset or empty, then
760 * this can match against removed names */
761 if (!new_owner || new_owner[0] == 0) {
762 item->type = KDBUS_MATCH_NAME_REMOVE;
763
764 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
765 if (r < 0)
766 return -errno;
767 }
768
769 /* If the neither name is explicitly set to
770 * the empty string, then this can match
771 * agains changed names */
772 if (!(old_owner && old_owner[0] == 0) &&
773 !(new_owner && new_owner[0] == 0)) {
774 item->type = KDBUS_MATCH_NAME_CHANGE;
775
776 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
777 if (r < 0)
778 return -errno;
779 }
780 }
781
782 if (is_name_id != 0) {
783 struct kdbus_cmd_match *m;
784 uint64_t sz;
785
786 /* If the name argument is missing or is a unique
787 * name, then add KDBUS_MATCH_ID_{ADD,REMOVE} matches
788 * for it */
789
790 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
791 offsetof(struct kdbus_item, id_change) +
792 sizeof(struct kdbus_notify_id_change));
793
794 m = alloca0(sz);
795 m->size = sz;
796 m->cookie = cookie;
797 m->src_id = KDBUS_SRC_ID_KERNEL;
798
799 item = m->items;
800 item->size = offsetof(struct kdbus_item, id_change) + sizeof(struct kdbus_notify_id_change);
801 item->id_change.id = name_id;
802
803 /* If the old name is unset or empty, then this can
804 * match against added ids */
805 if (!old_owner || old_owner[0] == 0) {
806 item->type = KDBUS_MATCH_ID_ADD;
807
808 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
809 if (r < 0)
810 return -errno;
811 }
812
813 /* If thew new name is unset or empty, then this can
814 match against removed ids */
815 if (!new_owner || new_owner[0] == 0) {
816 item->type = KDBUS_MATCH_ID_REMOVE;
817
818 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
819 if (r < 0)
820 return -errno;
821 }
822 }
823
824 return 0;
825 }
826
827 static int bus_add_match_internal_kernel(
828 sd_bus *bus,
829 const char *match,
830 struct bus_match_component *components,
831 unsigned n_components,
832 uint64_t cookie) {
833
834 struct kdbus_cmd_match *m;
835 struct kdbus_item *item;
836 uint64_t bloom[BLOOM_SIZE/8];
837 size_t sz;
838 const char *sender = NULL;
839 size_t sender_length = 0;
840 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
841 bool using_bloom = false;
842 unsigned i;
843 bool matches_name_change = true;
844 const char *name_change_arg[3] = {};
845 int r;
846
847 assert(bus);
848 assert(match);
849
850 zero(bloom);
851
852 sz = offsetof(struct kdbus_cmd_match, items);
853
854 for (i = 0; i < n_components; i++) {
855 struct bus_match_component *c = &components[i];
856
857 switch (c->type) {
858
859 case BUS_MATCH_SENDER:
860 if (!streq(c->value_str, "org.freedesktop.DBus"))
861 matches_name_change = false;
862
863 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
864 if (r < 0)
865 return r;
866
867 if (r > 0) {
868 sender = c->value_str;
869 sender_length = strlen(sender);
870 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
871 }
872
873 break;
874
875 case BUS_MATCH_MESSAGE_TYPE:
876 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
877 matches_name_change = false;
878
879 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
880 using_bloom = true;
881 break;
882
883 case BUS_MATCH_INTERFACE:
884 if (!streq(c->value_str, "org.freedesktop.DBus"))
885 matches_name_change = false;
886
887 bloom_add_pair(bloom, "interface", c->value_str);
888 using_bloom = true;
889 break;
890
891 case BUS_MATCH_MEMBER:
892 if (!streq(c->value_str, "NameOwnerChanged"))
893 matches_name_change = false;
894
895 bloom_add_pair(bloom, "member", c->value_str);
896 using_bloom = true;
897 break;
898
899 case BUS_MATCH_PATH:
900 if (!streq(c->value_str, "/org/freedesktop/DBus"))
901 matches_name_change = false;
902
903 bloom_add_pair(bloom, "path", c->value_str);
904 using_bloom = true;
905 break;
906
907 case BUS_MATCH_PATH_NAMESPACE:
908 if (!streq(c->value_str, "/")) {
909 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
910 using_bloom = true;
911 }
912 break;
913
914 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
915 char buf[sizeof("arg")-1 + 2 + 1];
916
917 if (c->type - BUS_MATCH_ARG < 3)
918 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
919
920 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
921 bloom_add_pair(bloom, buf, c->value_str);
922 using_bloom = true;
923 break;
924 }
925
926 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
927 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
928
929 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
930 bloom_add_pair(bloom, buf, c->value_str);
931 using_bloom = true;
932 break;
933 }
934
935 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
936 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
937
938 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
939 bloom_add_pair(bloom, buf, c->value_str);
940 using_bloom = true;
941 break;
942 }
943
944 case BUS_MATCH_DESTINATION:
945 /* The bloom filter does not include
946 the destination, since it is only
947 available for broadcast messages
948 which do not carry a destination
949 since they are undirected. */
950 break;
951
952 case BUS_MATCH_ROOT:
953 case BUS_MATCH_VALUE:
954 case BUS_MATCH_LEAF:
955 case _BUS_MATCH_NODE_TYPE_MAX:
956 case _BUS_MATCH_NODE_TYPE_INVALID:
957 assert_not_reached("Invalid match type?");
958 }
959 }
960
961 if (using_bloom)
962 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
963
964 m = alloca0(sz);
965 m->size = sz;
966 m->cookie = cookie;
967 m->src_id = src_id;
968
969 item = m->items;
970
971 if (using_bloom) {
972 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
973 item->type = KDBUS_MATCH_BLOOM;
974 memcpy(item->data64, bloom, BLOOM_SIZE);
975
976 item = KDBUS_PART_NEXT(item);
977 }
978
979 if (sender) {
980 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
981 item->type = KDBUS_MATCH_SRC_NAME;
982 memcpy(item->str, sender, sender_length + 1);
983 }
984
985 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
986 if (r < 0)
987 return -errno;
988
989 if (matches_name_change) {
990
991 /* If this match could theoretically match
992 * NameOwnerChanged messages, we need to
993 * install a second non-bloom filter explitly
994 * for it */
995
996 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
997 if (r < 0)
998 return r;
999 }
1000
1001 return 0;
1002 }
1003
1004 static int bus_add_match_internal_dbus1(
1005 sd_bus *bus,
1006 const char *match) {
1007
1008 assert(bus);
1009 assert(match);
1010
1011 return sd_bus_call_method(
1012 bus,
1013 "org.freedesktop.DBus",
1014 "/",
1015 "org.freedesktop.DBus",
1016 "AddMatch",
1017 NULL,
1018 NULL,
1019 "s",
1020 match);
1021 }
1022
1023 int bus_add_match_internal(
1024 sd_bus *bus,
1025 const char *match,
1026 struct bus_match_component *components,
1027 unsigned n_components,
1028 uint64_t cookie) {
1029
1030 assert(bus);
1031 assert(match);
1032
1033 if (bus->is_kernel)
1034 return bus_add_match_internal_kernel(bus, match, components, n_components, cookie);
1035 else
1036 return bus_add_match_internal_dbus1(bus, match);
1037 }
1038
1039 static int bus_remove_match_internal_kernel(
1040 sd_bus *bus,
1041 const char *match,
1042 uint64_t cookie) {
1043
1044 struct kdbus_cmd_match m;
1045 int r;
1046
1047 assert(bus);
1048 assert(match);
1049
1050 zero(m);
1051 m.size = offsetof(struct kdbus_cmd_match, items);
1052 m.cookie = cookie;
1053
1054 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1055 if (r < 0)
1056 return -errno;
1057
1058 return 0;
1059 }
1060
1061 static int bus_remove_match_internal_dbus1(
1062 sd_bus *bus,
1063 const char *match) {
1064
1065 assert(bus);
1066 assert(match);
1067
1068 return sd_bus_call_method(
1069 bus,
1070 "org.freedesktop.DBus",
1071 "/",
1072 "org.freedesktop.DBus",
1073 "RemoveMatch",
1074 NULL,
1075 NULL,
1076 "s",
1077 match);
1078 }
1079
1080 int bus_remove_match_internal(
1081 sd_bus *bus,
1082 const char *match,
1083 uint64_t cookie) {
1084
1085 assert(bus);
1086 assert(match);
1087
1088 if (bus->is_kernel)
1089 return bus_remove_match_internal_kernel(bus, match, cookie);
1090 else
1091 return bus_remove_match_internal_dbus1(bus, match);
1092 }
1093
1094 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
1095 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
1096 const char *mid;
1097 int r;
1098
1099 assert_return(bus, -EINVAL);
1100 assert_return(name, -EINVAL);
1101 assert_return(machine, -EINVAL);
1102 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1103 assert_return(!bus_pid_changed(bus), -ECHILD);
1104
1105 if (streq_ptr(name, bus->unique_name))
1106 return sd_id128_get_machine(machine);
1107
1108 r = sd_bus_message_new_method_call(
1109 bus,
1110 name,
1111 "/",
1112 "org.freedesktop.DBus.Peer",
1113 "GetMachineId", &m);
1114 if (r < 0)
1115 return r;
1116
1117 r = sd_bus_message_set_no_auto_start(m, true);
1118 if (r < 0)
1119 return r;
1120
1121 r = sd_bus_call(bus, m, 0, NULL, &reply);
1122 if (r < 0)
1123 return r;
1124
1125 r = sd_bus_message_read(reply, "s", &mid);
1126 if (r < 0)
1127 return r;
1128
1129 return sd_id128_from_string(mid, machine);
1130 }