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