]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-control.c
Add memcpy_safe
[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) {
4afd3348 94 _cleanup_(sd_bus_message_unrefp) 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 189static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
4afd3348 190 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
e7176abb 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) {
4afd3348 329 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
71f2ab46
LP
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
4afd3348 650 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
370d7a9c
DM
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
4afd3348
LP
756 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
757 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
e7176abb
LP
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) {
4afd3348 861 _cleanup_(sd_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) {
4afd3348 933 _cleanup_(sd_bus_creds_unrefp) 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) {
4afd3348 982 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
52cfc037 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
75f32f04 1136 memcpy_safe(item->name_change.name, name, l);
777d7a61 1137
006a0b87
LP
1138 /* If the old name is unset or empty, then
1139 * this can match against added names */
d41eee12 1140 if (isempty(old_owner)) {
73842d62 1141 item->type = KDBUS_ITEM_NAME_ADD;
777d7a61 1142
006a0b87
LP
1143 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1144 if (r < 0)
1145 return -errno;
1146 }
777d7a61 1147
006a0b87
LP
1148 /* If the new name is unset or empty, then
1149 * this can match against removed names */
d41eee12 1150 if (isempty(new_owner)) {
73842d62 1151 item->type = KDBUS_ITEM_NAME_REMOVE;
777d7a61 1152
006a0b87
LP
1153 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1154 if (r < 0)
1155 return -errno;
1156 }
777d7a61 1157
85a0aa17
LP
1158 /* The CHANGE match we need in either case, because
1159 * what is reported as a name change by the kernel
1160 * might just be an owner change between starter and
1161 * normal clients. For userspace such a change should
1162 * be considered a removal/addition, hence let's
1163 * subscribe to this unconditionally. */
1164 item->type = KDBUS_ITEM_NAME_CHANGE;
1165 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1166 if (r < 0)
1167 return -errno;
777d7a61
LP
1168 }
1169
1170 if (is_name_id != 0) {
006a0b87
LP
1171 struct kdbus_cmd_match *m;
1172 uint64_t sz;
777d7a61
LP
1173
1174 /* If the name argument is missing or is a unique
73842d62 1175 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
777d7a61
LP
1176 * for it */
1177
006a0b87
LP
1178 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
1179 offsetof(struct kdbus_item, id_change) +
1180 sizeof(struct kdbus_notify_id_change));
777d7a61 1181
7f3d3ba1 1182 m = alloca0_align(sz, 8);
006a0b87
LP
1183 m->size = sz;
1184 m->cookie = cookie;
777d7a61 1185
006a0b87 1186 item = m->items;
dff91e8b
LP
1187 item->size =
1188 offsetof(struct kdbus_item, id_change) +
1189 sizeof(struct kdbus_notify_id_change);
ff2ea192 1190 item->id_change.id = name_id;
777d7a61
LP
1191
1192 /* If the old name is unset or empty, then this can
1193 * match against added ids */
d41eee12 1194 if (isempty(old_owner)) {
73842d62 1195 item->type = KDBUS_ITEM_ID_ADD;
18458807
DH
1196 if (!isempty(new_owner))
1197 item->id_change.id = new_owner_id;
777d7a61
LP
1198
1199 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1200 if (r < 0)
1201 return -errno;
1202 }
1203
1204 /* If thew new name is unset or empty, then this can
73842d62 1205 * match against removed ids */
d41eee12 1206 if (isempty(new_owner)) {
73842d62 1207 item->type = KDBUS_ITEM_ID_REMOVE;
18458807
DH
1208 if (!isempty(old_owner))
1209 item->id_change.id = old_owner_id;
777d7a61
LP
1210
1211 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1212 if (r < 0)
1213 return -errno;
1214 }
1215 }
1216
1217 return 0;
1218}
1219
53461b74 1220int bus_add_match_internal_kernel(
c7819669 1221 sd_bus *bus,
c7819669
LP
1222 struct bus_match_component *components,
1223 unsigned n_components,
1224 uint64_t cookie) {
1225
e7176abb
LP
1226 struct kdbus_cmd_match *m;
1227 struct kdbus_item *item;
b28ff39f 1228 uint64_t *bloom;
e7176abb
LP
1229 size_t sz;
1230 const char *sender = NULL;
1231 size_t sender_length = 0;
e1141a96 1232 uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
e7176abb
LP
1233 bool using_bloom = false;
1234 unsigned i;
1235 bool matches_name_change = true;
1236 const char *name_change_arg[3] = {};
c7819669
LP
1237 int r;
1238
392d5b37 1239 assert(bus);
de1c301e 1240
96ceff42
LP
1241 /* Monitor streams don't support matches, make this a NOP */
1242 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1243 return 0;
1244
b28ff39f 1245 bloom = alloca0(bus->bloom_size);
c7819669 1246
85feb8e4 1247 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
c7819669 1248
e7176abb
LP
1249 for (i = 0; i < n_components; i++) {
1250 struct bus_match_component *c = &components[i];
777d7a61 1251
e7176abb 1252 switch (c->type) {
c7819669 1253
e7176abb
LP
1254 case BUS_MATCH_SENDER:
1255 if (!streq(c->value_str, "org.freedesktop.DBus"))
1256 matches_name_change = false;
777d7a61 1257
e7176abb
LP
1258 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
1259 if (r < 0)
1260 return r;
85feb8e4
LP
1261 else if (r > 0)
1262 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1263 else {
e7176abb
LP
1264 sender = c->value_str;
1265 sender_length = strlen(sender);
1266 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
1267 }
777d7a61 1268
e7176abb 1269 break;
c7819669 1270
e7176abb
LP
1271 case BUS_MATCH_MESSAGE_TYPE:
1272 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
1273 matches_name_change = false;
777d7a61 1274
b28ff39f 1275 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
e7176abb
LP
1276 using_bloom = true;
1277 break;
c7819669 1278
e7176abb
LP
1279 case BUS_MATCH_INTERFACE:
1280 if (!streq(c->value_str, "org.freedesktop.DBus"))
1281 matches_name_change = false;
c7819669 1282
b28ff39f 1283 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
e7176abb
LP
1284 using_bloom = true;
1285 break;
86312ab8 1286
e7176abb
LP
1287 case BUS_MATCH_MEMBER:
1288 if (!streq(c->value_str, "NameOwnerChanged"))
1289 matches_name_change = false;
777d7a61 1290
b28ff39f 1291 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
e7176abb
LP
1292 using_bloom = true;
1293 break;
86312ab8 1294
e7176abb
LP
1295 case BUS_MATCH_PATH:
1296 if (!streq(c->value_str, "/org/freedesktop/DBus"))
1297 matches_name_change = false;
86312ab8 1298
b28ff39f 1299 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
e7176abb
LP
1300 using_bloom = true;
1301 break;
1302
1303 case BUS_MATCH_PATH_NAMESPACE:
26589352
DH
1304 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
1305 using_bloom = true;
e7176abb 1306 break;
86312ab8 1307
e7176abb
LP
1308 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1309 char buf[sizeof("arg")-1 + 2 + 1];
86312ab8 1310
e7176abb
LP
1311 if (c->type - BUS_MATCH_ARG < 3)
1312 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
86312ab8 1313
5ffa8c81 1314 xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
b28ff39f 1315 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
e7176abb
LP
1316 using_bloom = true;
1317 break;
c7819669
LP
1318 }
1319
eccd47c5 1320 case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
19bee5c3 1321 char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
eccd47c5 1322
19bee5c3 1323 xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
eccd47c5
LP
1324 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
1325 using_bloom = true;
1326 break;
1327 }
1328
1329 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
a867b002
DH
1330 /*
1331 * XXX: DBus spec defines arg[0..63]path= matching to be
1332 * a two-way glob. That is, if either string is a prefix
1333 * of the other, it matches.
1334 * This is really hard to realize in bloom-filters, as
1335 * we would have to create a bloom-match for each prefix
1336 * of @c->value_str. This is excessive, hence we just
1337 * ignore all those matches and accept everything from
1338 * the kernel. People should really avoid those matches.
1339 * If they're used in real-life some day, we will have
1340 * to properly support multiple-matches here.
1341 */
e7176abb 1342 break;
c7819669 1343
e7176abb
LP
1344 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1345 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
c7819669 1346
5ffa8c81 1347 xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
b28ff39f 1348 bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
e7176abb
LP
1349 using_bloom = true;
1350 break;
c7819669
LP
1351 }
1352
eccd47c5 1353 case BUS_MATCH_DESTINATION:
e1141a96
DH
1354 /*
1355 * Kernel only supports matching on destination IDs, but
1356 * not on destination names. So just skip the
1357 * destination name restriction and verify it in
1358 * user-space on retrieval.
1359 */
1360 r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
1361 if (r < 0)
1362 return r;
1363 else if (r > 0)
1364 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
1365
1af5f746
DH
1366 /* if not a broadcast, it cannot be a name-change */
1367 if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
1368 matches_name_change = false;
1369
e7176abb
LP
1370 break;
1371
1372 case BUS_MATCH_ROOT:
1373 case BUS_MATCH_VALUE:
1374 case BUS_MATCH_LEAF:
1375 case _BUS_MATCH_NODE_TYPE_MAX:
1376 case _BUS_MATCH_NODE_TYPE_INVALID:
1377 assert_not_reached("Invalid match type?");
c7819669 1378 }
e7176abb
LP
1379 }
1380
1381 if (using_bloom)
b28ff39f 1382 sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
e7176abb 1383
7f3d3ba1 1384 m = alloca0_align(sz, 8);
e7176abb
LP
1385 m->size = sz;
1386 m->cookie = cookie;
e7176abb
LP
1387
1388 item = m->items;
1389
85feb8e4
LP
1390 if (src_id != KDBUS_MATCH_ID_ANY) {
1391 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1392 item->type = KDBUS_ITEM_ID;
1393 item->id = src_id;
73842d62 1394 item = KDBUS_ITEM_NEXT(item);
85feb8e4
LP
1395 }
1396
e1141a96
DH
1397 if (dst_id != KDBUS_MATCH_ID_ANY) {
1398 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1399 item->type = KDBUS_ITEM_DST_ID;
1400 item->id = dst_id;
1401 item = KDBUS_ITEM_NEXT(item);
1402 }
1403
85feb8e4 1404 if (using_bloom) {
b28ff39f 1405 item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
18a28147 1406 item->type = KDBUS_ITEM_BLOOM_MASK;
b28ff39f 1407 memcpy(item->data64, bloom, bus->bloom_size);
85feb8e4 1408 item = KDBUS_ITEM_NEXT(item);
e7176abb
LP
1409 }
1410
1411 if (sender) {
1412 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
73842d62 1413 item->type = KDBUS_ITEM_NAME;
e7176abb
LP
1414 memcpy(item->str, sender, sender_length + 1);
1415 }
1416
1417 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1418 if (r < 0)
1419 return -errno;
1420
1421 if (matches_name_change) {
1422
1423 /* If this match could theoretically match
1424 * NameOwnerChanged messages, we need to
1425 * install a second non-bloom filter explitly
1426 * for it */
c7819669 1427
e7176abb 1428 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
c7819669 1429 if (r < 0)
e7176abb
LP
1430 return r;
1431 }
c7819669 1432
e7176abb
LP
1433 return 0;
1434}
777d7a61 1435
09365592
LP
1436#define internal_match(bus, m) \
1437 ((bus)->hello_flags & KDBUS_HELLO_MONITOR \
63c372cb 1438 ? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
09365592
LP
1439 : (m))
1440
e7176abb
LP
1441static int bus_add_match_internal_dbus1(
1442 sd_bus *bus,
1443 const char *match) {
777d7a61 1444
09365592
LP
1445 const char *e;
1446
e7176abb
LP
1447 assert(bus);
1448 assert(match);
777d7a61 1449
09365592
LP
1450 e = internal_match(bus, match);
1451
e7176abb
LP
1452 return sd_bus_call_method(
1453 bus,
1454 "org.freedesktop.DBus",
cd789fdf 1455 "/org/freedesktop/DBus",
e7176abb
LP
1456 "org.freedesktop.DBus",
1457 "AddMatch",
1458 NULL,
1459 NULL,
1460 "s",
09365592 1461 e);
de1c301e
LP
1462}
1463
e7176abb
LP
1464int bus_add_match_internal(
1465 sd_bus *bus,
1466 const char *match,
1467 struct bus_match_component *components,
1468 unsigned n_components,
1469 uint64_t cookie) {
1470
1471 assert(bus);
e7176abb 1472
33c62dcb
LP
1473 if (!bus->bus_client)
1474 return -EINVAL;
1475
e7176abb 1476 if (bus->is_kernel)
26e376bf 1477 return bus_add_match_internal_kernel(bus, components, n_components, cookie);
e7176abb
LP
1478 else
1479 return bus_add_match_internal_dbus1(bus, match);
1480}
1481
53461b74 1482int bus_remove_match_internal_kernel(
c7819669 1483 sd_bus *bus,
c7819669
LP
1484 uint64_t cookie) {
1485
e044970a
LP
1486 struct kdbus_cmd_match m = {
1487 .size = offsetof(struct kdbus_cmd_match, items),
1488 .cookie = cookie,
1489 };
c7819669
LP
1490 int r;
1491
392d5b37 1492 assert(bus);
de1c301e 1493
96ceff42
LP
1494 /* Monitor streams don't support matches, make this a NOP */
1495 if (bus->hello_flags & KDBUS_HELLO_MONITOR)
1496 return 0;
1497
e7176abb
LP
1498 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1499 if (r < 0)
1500 return -errno;
c7819669 1501
e7176abb
LP
1502 return 0;
1503}
c7819669 1504
e7176abb
LP
1505static int bus_remove_match_internal_dbus1(
1506 sd_bus *bus,
1507 const char *match) {
777d7a61 1508
09365592
LP
1509 const char *e;
1510
e7176abb
LP
1511 assert(bus);
1512 assert(match);
1513
09365592
LP
1514 e = internal_match(bus, match);
1515
e7176abb
LP
1516 return sd_bus_call_method(
1517 bus,
1518 "org.freedesktop.DBus",
cd789fdf 1519 "/org/freedesktop/DBus",
e7176abb
LP
1520 "org.freedesktop.DBus",
1521 "RemoveMatch",
1522 NULL,
1523 NULL,
1524 "s",
09365592 1525 e);
e7176abb
LP
1526}
1527
1528int bus_remove_match_internal(
1529 sd_bus *bus,
1530 const char *match,
1531 uint64_t cookie) {
1532
1533 assert(bus);
e7176abb 1534
33c62dcb
LP
1535 if (!bus->bus_client)
1536 return -EINVAL;
1537
e7176abb 1538 if (bus->is_kernel)
26e376bf 1539 return bus_remove_match_internal_kernel(bus, cookie);
e7176abb
LP
1540 else
1541 return bus_remove_match_internal_dbus1(bus, match);
de1c301e 1542}
70666185 1543
056f95d0 1544_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
4afd3348 1545 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
1546 const char *mid;
1547 int r;
1548
8d162091
LP
1549 assert_return(bus, -EINVAL);
1550 assert_return(name, -EINVAL);
1551 assert_return(machine, -EINVAL);
8d162091 1552 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 1553 assert_return(service_name_is_valid(name), -EINVAL);
70666185 1554
33c62dcb
LP
1555 if (!bus->bus_client)
1556 return -EINVAL;
1557
a3d59cd1
LP
1558 if (!BUS_IS_OPEN(bus->state))
1559 return -ENOTCONN;
1560
70666185
LP
1561 if (streq_ptr(name, bus->unique_name))
1562 return sd_id128_get_machine(machine);
1563
8d162091
LP
1564 r = sd_bus_message_new_method_call(
1565 bus,
151b9b96 1566 &m,
8d162091
LP
1567 name,
1568 "/",
1569 "org.freedesktop.DBus.Peer",
151b9b96 1570 "GetMachineId");
8d162091
LP
1571 if (r < 0)
1572 return r;
1573
eee9ec0e 1574 r = sd_bus_message_set_auto_start(m, false);
8d162091
LP
1575 if (r < 0)
1576 return r;
70666185 1577
8d162091 1578 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
1579 if (r < 0)
1580 return r;
1581
1582 r = sd_bus_message_read(reply, "s", &mid);
1583 if (r < 0)
1584 return r;
1585
1586 return sd_id128_from_string(mid, machine);
1587}