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