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