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