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