]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-control.c
update TODO
[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"
751bc6ac 36#include "cgroup-util.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) {
e7176abb 54 struct kdbus_cmd_name *n;
45fd5e4d 55 size_t size, l;
de1c301e
LP
56 int r;
57
e7176abb
LP
58 assert(bus);
59 assert(name);
f08838da 60
e7176abb 61 l = strlen(name);
45fd5e4d
LP
62 size = offsetof(struct kdbus_cmd_name, name) + l + 1;
63 n = alloca0(size);
64 n->size = size;
e7176abb
LP
65 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
66 memcpy(n->name, name, l+1);
f08838da 67
75722f1d 68#ifdef HAVE_VALGRIND_MEMCHECK_H
e7176abb 69 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
75722f1d
LP
70#endif
71
e7176abb
LP
72 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
73 if (r < 0)
74 return -errno;
f08838da 75
e7176abb
LP
76 if (n->flags & KDBUS_NAME_IN_QUEUE)
77 return 0;
f08838da 78
e7176abb 79 return 1;
de1c301e
LP
80}
81
29a07cdb 82static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
d4100e24 83 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
29a07cdb 84 uint32_t ret, param = 0;
de1c301e
LP
85 int r;
86
e7176abb
LP
87 assert(bus);
88 assert(name);
89
29a07cdb
LP
90 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
91 param |= BUS_NAME_ALLOW_REPLACEMENT;
92 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
93 param |= BUS_NAME_REPLACE_EXISTING;
94 if (!(flags & SD_BUS_NAME_QUEUE))
95 param |= BUS_NAME_DO_NOT_QUEUE;
96
e7176abb
LP
97 r = sd_bus_call_method(
98 bus,
99 "org.freedesktop.DBus",
cd789fdf 100 "/org/freedesktop/DBus",
e7176abb
LP
101 "org.freedesktop.DBus",
102 "RequestName",
103 NULL,
104 &reply,
105 "su",
106 name,
29a07cdb 107 param);
e7176abb
LP
108 if (r < 0)
109 return r;
110
111 r = sd_bus_message_read(reply, "u", &ret);
112 if (r < 0)
113 return r;
114
0461f8cd 115 if (ret == BUS_NAME_ALREADY_OWNER)
e7176abb 116 return -EALREADY;
0461f8cd 117 else if (ret == BUS_NAME_EXISTS)
e7176abb 118 return -EEXIST;
0461f8cd 119 else if (ret == BUS_NAME_IN_QUEUE)
e7176abb 120 return 0;
c0a09132
LP
121 else if (ret == BUS_NAME_PRIMARY_OWNER)
122 return 1;
e7176abb 123
c0a09132 124 return -EIO;
e7176abb
LP
125}
126
29a07cdb 127_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
9bb058a1
LS
128 assert_return(bus, -EINVAL);
129 assert_return(name, -EINVAL);
130 assert_return(bus->bus_client, -EINVAL);
131 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
132 assert_return(!bus_pid_changed(bus), -ECHILD);
29a07cdb 133 assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
45fd5e4d
LP
134 assert_return(service_name_is_valid(name), -EINVAL);
135 assert_return(name[0] != ':', -EINVAL);
de1c301e 136
e7176abb
LP
137 if (bus->is_kernel)
138 return bus_request_name_kernel(bus, name, flags);
139 else
140 return bus_request_name_dbus1(bus, name, flags);
141}
f08838da 142
e7176abb
LP
143static int bus_release_name_kernel(sd_bus *bus, const char *name) {
144 struct kdbus_cmd_name *n;
145 size_t l;
146 int r;
f08838da 147
e7176abb
LP
148 assert(bus);
149 assert(name);
f08838da 150
e7176abb
LP
151 l = strlen(name);
152 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
153 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
154 memcpy(n->name, name, l+1);
f08838da 155
e7176abb
LP
156#ifdef HAVE_VALGRIND_MEMCHECK_H
157 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
158#endif
159 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
160 if (r < 0)
161 return -errno;
de1c301e 162
e7176abb 163 return n->flags;
de1c301e
LP
164}
165
e7176abb
LP
166static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
167 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
168 uint32_t ret;
de1c301e
LP
169 int r;
170
e7176abb
LP
171 assert(bus);
172 assert(name);
173
174 r = sd_bus_call_method(
175 bus,
176 "org.freedesktop.DBus",
cd789fdf 177 "/org/freedesktop/DBus",
e7176abb
LP
178 "org.freedesktop.DBus",
179 "ReleaseName",
180 NULL,
181 &reply,
182 "s",
183 name);
184 if (r < 0)
185 return r;
186
187 r = sd_bus_message_read(reply, "u", &ret);
188 if (r < 0)
189 return r;
0461f8cd 190 if (ret == BUS_NAME_NON_EXISTENT)
043ccd83 191 return -ESRCH;
0461f8cd 192 if (ret == BUS_NAME_NOT_OWNER)
043ccd83 193 return -EADDRINUSE;
0461f8cd 194 if (ret == BUS_NAME_RELEASED)
e7176abb
LP
195 return 0;
196
197 return -EINVAL;
198}
199
200_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
9bb058a1 201 assert_return(bus, -EINVAL);
e7176abb
LP
202 assert_return(name, -EINVAL);
203 assert_return(bus->bus_client, -EINVAL);
9bb058a1
LS
204 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
205 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d
LP
206 assert_return(service_name_is_valid(name), -EINVAL);
207 assert_return(name[0] != ':', -EINVAL);
de1c301e 208
e7176abb
LP
209 if (bus->is_kernel)
210 return bus_release_name_kernel(bus, name);
211 else
212 return bus_release_name_dbus1(bus, name);
213}
de1c301e 214
71f2ab46
LP
215static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
216 struct kdbus_cmd_name_list cmd = {};
e7176abb
LP
217 struct kdbus_name_list *name_list;
218 struct kdbus_cmd_name *name;
7f7030e2 219 uint64_t previous_id = 0;
e7176abb 220 int r;
b1473984 221
71f2ab46 222 /* Caller will free half-constructed list on failure... */
b1473984 223
71f2ab46 224 cmd.flags = flags;
b1473984 225
71f2ab46 226 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
e7176abb
LP
227 if (r < 0)
228 return -errno;
b1473984 229
71f2ab46 230 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
b6bd53c1 231
a8d4cac5 232 KDBUS_ITEM_FOREACH(name, name_list, names) {
b6bd53c1 233
98531b57 234 if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) {
71f2ab46
LP
235 char *n;
236
98531b57 237 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0)
71f2ab46
LP
238 return -ENOMEM;
239
240 r = strv_push(x, n);
241 if (r < 0) {
242 free(n);
243 return -ENOMEM;
244 }
7f7030e2 245
98531b57 246 previous_id = name->owner_id;
71f2ab46 247 }
b1473984 248
45fd5e4d 249 if (name->size > sizeof(*name) && service_name_is_valid(name->name)) {
7f7030e2
LP
250 r = strv_extend(x, name->name);
251 if (r < 0)
252 return -ENOMEM;
253 }
89ffcd2a 254 }
de1c301e 255
45fd5e4d 256 r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
e7176abb
LP
257 if (r < 0)
258 return -errno;
259
de1c301e
LP
260 return 0;
261}
262
71f2ab46
LP
263static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
264 _cleanup_strv_free_ char **x = NULL, **y = NULL;
de1c301e
LP
265 int r;
266
71f2ab46
LP
267 if (acquired) {
268 r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x);
269 if (r < 0)
270 return r;
271 }
a4297f08 272
71f2ab46 273 if (activatable) {
07442eff 274 r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y);
71f2ab46
LP
275 if (r < 0)
276 return r;
5b12334d 277
71f2ab46
LP
278 *activatable = y;
279 y = NULL;
5b12334d 280 }
de1c301e 281
71f2ab46
LP
282 if (acquired) {
283 *acquired = x;
284 x = NULL;
285 }
286
287 return 0;
288}
289
290static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
291 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
292 _cleanup_strv_free_ char **x = NULL, **y = NULL;
293 int r;
294
295 if (acquired) {
296 r = sd_bus_call_method(
297 bus,
298 "org.freedesktop.DBus",
cd789fdf 299 "/org/freedesktop/DBus",
71f2ab46
LP
300 "org.freedesktop.DBus",
301 "ListNames",
302 NULL,
303 &reply,
304 NULL);
305 if (r < 0)
306 return r;
307
308 r = sd_bus_message_read_strv(reply, &x);
309 if (r < 0)
310 return r;
311
312 reply = sd_bus_message_unref(reply);
313 }
314
315 if (activatable) {
316 r = sd_bus_call_method(
317 bus,
318 "org.freedesktop.DBus",
cd789fdf 319 "/org/freedesktop/DBus",
71f2ab46
LP
320 "org.freedesktop.DBus",
321 "ListActivatableNames",
322 NULL,
323 &reply,
324 NULL);
325 if (r < 0)
326 return r;
327
328 r = sd_bus_message_read_strv(reply, &y);
329 if (r < 0)
330 return r;
331
332 *activatable = y;
333 y = NULL;
334 }
335
336 if (acquired) {
337 *acquired = x;
338 x = NULL;
a4297f08 339 }
de1c301e 340
49b832c5
LP
341 return 0;
342}
343
71f2ab46 344_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) {
e7176abb 345 assert_return(bus, -EINVAL);
71f2ab46 346 assert_return(acquired || activatable, -EINVAL);
e7176abb
LP
347 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
348 assert_return(!bus_pid_changed(bus), -ECHILD);
349
350 if (bus->is_kernel)
71f2ab46 351 return bus_list_names_kernel(bus, acquired, activatable);
e7176abb 352 else
71f2ab46 353 return bus_list_names_dbus1(bus, acquired, activatable);
e7176abb
LP
354}
355
49b832c5
LP
356static int bus_get_owner_kdbus(
357 sd_bus *bus,
358 const char *name,
359 uint64_t mask,
360 sd_bus_creds **creds) {
361
49b832c5 362 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
c85a5a24
DM
363 struct kdbus_cmd_conn_info *cmd;
364 struct kdbus_conn_info *conn_info;
49b832c5
LP
365 struct kdbus_item *item;
366 size_t size;
367 uint64_t m, id;
368 int r;
369
370 r = bus_kernel_parse_unique_name(name, &id);
371 if (r < 0)
372 return r;
373 if (r > 0) {
c85a5a24 374 size = offsetof(struct kdbus_cmd_conn_info, name);
49b832c5
LP
375 cmd = alloca0(size);
376 cmd->id = id;
377 } else {
c85a5a24 378 size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
49b832c5
LP
379 cmd = alloca0(size);
380 strcpy(cmd->name, name);
a4297f08 381 }
de1c301e 382
49b832c5 383 cmd->size = size;
cccb0b2c
LP
384 kdbus_translate_attach_flags(mask, (uint64_t*) &cmd->flags);
385
c85a5a24 386 r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
49b832c5
LP
387 if (r < 0)
388 return -errno;
389
c85a5a24 390 conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
49b832c5 391
c2073383
LP
392 /* Non-activated names are considered not available */
393 if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
394 return name[0] == ':' ? -ENXIO : -ENOENT;
395
49b832c5
LP
396 c = bus_creds_new();
397 if (!c)
398 return -ENOMEM;
399
400 if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
c85a5a24 401 if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
49b832c5
LP
402 return -ENOMEM;
403
404 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
405 }
406
a8d4cac5 407 KDBUS_ITEM_FOREACH(item, conn_info, items) {
49b832c5
LP
408
409 switch (item->type) {
410
411 case KDBUS_ITEM_CREDS:
2dc9970b 412 m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
49b832c5
LP
413
414 if (m) {
693eb9a2
LP
415 c->uid = (uid_t) item->creds.uid;
416 c->pid = (pid_t) item->creds.pid;
417 c->gid = (gid_t) item->creds.gid;
2dc9970b
LP
418 c->mask |= m;
419 }
420
421 if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
693eb9a2 422 c->tid = (pid_t) item->creds.tid;
2dc9970b
LP
423 c->mask |= SD_BUS_CREDS_TID;
424 }
425
426 if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
49b832c5 427 c->pid_starttime = item->creds.starttime;
2dc9970b 428 c->mask |= SD_BUS_CREDS_PID_STARTTIME;
49b832c5 429 }
2dc9970b 430
49b832c5
LP
431 break;
432
433 case KDBUS_ITEM_PID_COMM:
434 if (mask & SD_BUS_CREDS_COMM) {
435 c->comm = strdup(item->str);
436 if (!c->comm) {
437 r = -ENOMEM;
438 goto fail;
439 }
440
441 c->mask |= SD_BUS_CREDS_COMM;
442 }
443 break;
444
445 case KDBUS_ITEM_TID_COMM:
446 if (mask & SD_BUS_CREDS_TID_COMM) {
447 c->tid_comm = strdup(item->str);
448 if (!c->tid_comm) {
449 r = -ENOMEM;
450 goto fail;
451 }
452
453 c->mask |= SD_BUS_CREDS_TID_COMM;
454 }
455 break;
456
457 case KDBUS_ITEM_EXE:
458 if (mask & SD_BUS_CREDS_EXE) {
459 c->exe = strdup(item->str);
460 if (!c->exe) {
461 r = -ENOMEM;
462 goto fail;
463 }
464
465 c->mask |= SD_BUS_CREDS_EXE;
466 }
467 break;
468
469 case KDBUS_ITEM_CMDLINE:
470 if (mask & SD_BUS_CREDS_CMDLINE) {
a8d4cac5 471 c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
49b832c5
LP
472 c->cmdline = memdup(item->data, c->cmdline_size);
473 if (!c->cmdline) {
474 r = -ENOMEM;
475 goto fail;
476 }
477
e7176abb
LP
478 c->mask |= SD_BUS_CREDS_CMDLINE;
479 }
480 break;
481
482 case KDBUS_ITEM_CGROUP:
483 m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
484 SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
485 SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
486
487 if (m) {
488 c->cgroup = strdup(item->str);
489 if (!c->cgroup) {
490 r = -ENOMEM;
491 goto fail;
492 }
493
751bc6ac
LP
494 if (!bus->cgroup_root) {
495 r = cg_get_root_path(&bus->cgroup_root);
496 if (r < 0)
497 goto fail;
498 }
499
500 c->cgroup_root = strdup(bus->cgroup_root);
501 if (!c->cgroup_root) {
502 r = -ENOMEM;
503 goto fail;
504 }
505
e7176abb
LP
506 c->mask |= m;
507 }
508 break;
509
510 case KDBUS_ITEM_CAPS:
511 m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
512 SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
513
514 if (m) {
a8d4cac5 515 c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE;
e7176abb
LP
516 c->capability = memdup(item->data, c->capability_size);
517 if (!c->capability) {
518 r = -ENOMEM;
519 goto fail;
520 }
521
522 c->mask |= m;
523 }
524 break;
525
526 case KDBUS_ITEM_SECLABEL:
527 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
528 c->label = strdup(item->str);
529 if (!c->label) {
530 r = -ENOMEM;
531 goto fail;
532 }
533
534 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
535 }
536 break;
537
538 case KDBUS_ITEM_AUDIT:
539 m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
540
541 if (m) {
542 c->audit_session_id = item->audit.sessionid;
543 c->audit_login_uid = item->audit.loginuid;
544 c->mask |= m;
545 }
546 break;
547
65dae17a 548 case KDBUS_ITEM_NAME:
45fd5e4d 549 if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
65dae17a
KS
550 r = strv_extend(&c->well_known_names, item->name.name);
551 if (r < 0)
e7176abb 552 goto fail;
e7176abb
LP
553
554 c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
555 }
556 break;
cccb0b2c
LP
557
558 case KDBUS_ITEM_CONN_NAME:
559 if ((mask & SD_BUS_CREDS_CONNECTION_NAME)) {
560 c->conn_name = strdup(item->str);
561 if (!c->conn_name) {
562 r = -ENOMEM;
563 goto fail;
564 }
565
566 c->mask |= SD_BUS_CREDS_CONNECTION_NAME;
567 }
568 break;
e7176abb
LP
569 }
570 }
571
572 if (creds) {
573 *creds = c;
574 c = NULL;
575 }
576
577 r = 0;
578
579fail:
580 ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset);
581 return r;
582}
583
584static int bus_get_owner_dbus1(
585 sd_bus *bus,
586 const char *name,
587 uint64_t mask,
588 sd_bus_creds **creds) {
589
590 _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL;
591 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
592 const char *unique = NULL;
593 pid_t pid = 0;
594 int r;
595
596 /* Only query the owner if the caller wants to know it or if
597 * the caller just wants to check whether a name exists */
598 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
599 r = sd_bus_call_method(
600 bus,
601 "org.freedesktop.DBus",
cd789fdf 602 "/org/freedesktop/DBus",
e7176abb
LP
603 "org.freedesktop.DBus",
604 "GetNameOwner",
605 NULL,
606 &reply_unique,
607 "s",
608 name);
609 if (r < 0)
610 return r;
611
612 r = sd_bus_message_read(reply_unique, "s", &unique);
613 if (r < 0)
614 return r;
615 }
616
617 if (mask != 0) {
618 c = bus_creds_new();
619 if (!c)
620 return -ENOMEM;
621
622 if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) {
623 c->unique_name = strdup(unique);
624 if (!c->unique_name)
625 return -ENOMEM;
626
627 c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
628 }
49b832c5 629
e7176abb
LP
630 if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
631 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
632 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|
633 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
634 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
635 uint32_t u;
49b832c5 636
e7176abb
LP
637 r = sd_bus_call_method(
638 bus,
639 "org.freedesktop.DBus",
cd789fdf 640 "/org/freedesktop/DBus",
e7176abb
LP
641 "org.freedesktop.DBus",
642 "GetConnectionUnixProcessID",
643 NULL,
644 &reply,
645 "s",
646 unique ? unique : name);
647 if (r < 0)
648 return r;
49b832c5 649
e7176abb
LP
650 r = sd_bus_message_read(reply, "u", &u);
651 if (r < 0)
652 return r;
653
654 pid = u;
655 if (mask & SD_BUS_CREDS_PID) {
656 c->pid = u;
657 c->mask |= SD_BUS_CREDS_PID;
49b832c5 658 }
49b832c5 659
e7176abb
LP
660 reply = sd_bus_message_unref(reply);
661 }
49b832c5 662
e7176abb
LP
663 if (mask & SD_BUS_CREDS_UID) {
664 uint32_t u;
49b832c5 665
e7176abb
LP
666 r = sd_bus_call_method(
667 bus,
668 "org.freedesktop.DBus",
cd789fdf 669 "/org/freedesktop/DBus",
e7176abb
LP
670 "org.freedesktop.DBus",
671 "GetConnectionUnixUser",
672 NULL,
673 &reply,
674 "s",
675 unique ? unique : name);
676 if (r < 0)
677 return r;
49b832c5 678
e7176abb
LP
679 r = sd_bus_message_read(reply, "u", &u);
680 if (r < 0)
681 return r;
49b832c5 682
e7176abb
LP
683 c->uid = u;
684 c->mask |= SD_BUS_CREDS_UID;
49b832c5 685
e7176abb
LP
686 reply = sd_bus_message_unref(reply);
687 }
49b832c5 688
e7176abb
LP
689 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
690 const void *p;
691 size_t sz;
49b832c5 692
e7176abb
LP
693 r = sd_bus_call_method(
694 bus,
695 "org.freedesktop.DBus",
cd789fdf 696 "/org/freedesktop/DBus",
e7176abb
LP
697 "org.freedesktop.DBus",
698 "GetConnectionSELinuxSecurityContext",
699 NULL,
700 &reply,
701 "s",
702 unique ? unique : name);
703 if (r < 0)
704 return r;
49b832c5 705
e7176abb
LP
706 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
707 if (r < 0)
708 return r;
709
710 c->label = strndup(p, sz);
711 if (!c->label)
712 return -ENOMEM;
713
714 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
49b832c5 715 }
e7176abb
LP
716
717 r = bus_creds_add_more(c, mask, pid, 0);
718 if (r < 0)
719 return r;
49b832c5
LP
720 }
721
722 if (creds) {
723 *creds = c;
724 c = NULL;
725 }
726
e7176abb 727 return 0;
49b832c5
LP
728}
729
730_public_ int sd_bus_get_owner(
731 sd_bus *bus,
732 const char *name,
733 uint64_t mask,
734 sd_bus_creds **creds) {
735
736 assert_return(bus, -EINVAL);
737 assert_return(name, -EINVAL);
95c4fe82 738 assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
49b832c5
LP
739 assert_return(mask == 0 || creds, -EINVAL);
740 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
741 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 742 assert_return(service_name_is_valid(name), -EINVAL);
0721804f 743 assert_return(bus->bus_client, -ENODATA);
49b832c5
LP
744
745 if (bus->is_kernel)
746 return bus_get_owner_kdbus(bus, name, mask, creds);
747 else
e7176abb 748 return bus_get_owner_dbus1(bus, name, mask, creds);
de1c301e
LP
749}
750
777d7a61
LP
751static int add_name_change_match(sd_bus *bus,
752 uint64_t cookie,
753 const char *name,
754 const char *old_owner,
755 const char *new_owner) {
756
5a884f93 757 uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
777d7a61
LP
758 int is_name_id = -1, r;
759 struct kdbus_item *item;
760
761 assert(bus);
762
763 /* If we encounter a match that could match against
764 * NameOwnerChanged messages, then we need to create
73842d62
DM
765 * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
766 * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
777d7a61
LP
767 * multiple if the match is underspecified.
768 *
769 * The NameOwnerChanged signals take three parameters with
770 * unique or well-known names, but only some forms actually
771 * exist:
772 *
73842d62
DM
773 * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
774 * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
775 * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
776 * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
777 * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
777d7a61
LP
778 *
779 * For the latter two the two unique names must be identical.
780 *
781 * */
782
783 if (name) {
784 is_name_id = bus_kernel_parse_unique_name(name, &name_id);
785 if (is_name_id < 0)
786 return 0;
787 }
788
33cb6e79 789 if (!isempty(old_owner)) {
777d7a61
LP
790 r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
791 if (r < 0)
792 return 0;
793 if (r == 0)
794 return 0;
795 if (is_name_id > 0 && old_owner_id != name_id)
796 return 0;
73842d62
DM
797 } else
798 old_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61 799
33cb6e79 800 if (!isempty(new_owner)) {
777d7a61
LP
801 r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
802 if (r < 0)
803 return r;
804 if (r == 0)
805 return 0;
806 if (is_name_id > 0 && new_owner_id != name_id)
807 return 0;
73842d62
DM
808 } else
809 new_owner_id = KDBUS_MATCH_ID_ANY;
777d7a61
LP
810
811 if (is_name_id <= 0) {
006a0b87 812 struct kdbus_cmd_match *m;
777d7a61
LP
813 size_t sz, l;
814
815 /* If the name argument is missing or is a well-known
73842d62 816 * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
777d7a61
LP
817 * matches for it */
818
8da4de03 819 l = name ? strlen(name) + 1 : 0;
777d7a61
LP
820
821 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
822 offsetof(struct kdbus_item, name_change) +
823 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 824 l);
777d7a61 825
006a0b87
LP
826 m = alloca0(sz);
827 m->size = sz;
828 m->cookie = cookie;
777d7a61 829
006a0b87
LP
830 item = m->items;
831 item->size =
832 offsetof(struct kdbus_item, name_change) +
833 offsetof(struct kdbus_notify_name_change, name) +
8da4de03 834 l;
777d7a61 835
ceceaf09
DM
836 item->name_change.old.id = old_owner_id;
837 item->name_change.new.id = new_owner_id;
777d7a61 838
006a0b87 839 if (name)
dff91e8b 840 memcpy(item->name_change.name, name, l);
777d7a61 841
006a0b87
LP
842 /* If the old name is unset or empty, then
843 * this can match against added names */
844 if (!old_owner || old_owner[0] == 0) {
73842d62 845 item->type = KDBUS_ITEM_NAME_ADD;
777d7a61 846
006a0b87
LP
847 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
848 if (r < 0)
849 return -errno;
850 }
777d7a61 851
006a0b87
LP
852 /* If the new name is unset or empty, then
853 * this can match against removed names */
854 if (!new_owner || new_owner[0] == 0) {
73842d62 855 item->type = KDBUS_ITEM_NAME_REMOVE;
777d7a61 856
006a0b87
LP
857 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
858 if (r < 0)
859 return -errno;
860 }
777d7a61 861
85a0aa17
LP
862 /* The CHANGE match we need in either case, because
863 * what is reported as a name change by the kernel
864 * might just be an owner change between starter and
865 * normal clients. For userspace such a change should
866 * be considered a removal/addition, hence let's
867 * subscribe to this unconditionally. */
868 item->type = KDBUS_ITEM_NAME_CHANGE;
869 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
870 if (r < 0)
871 return -errno;
777d7a61
LP
872 }
873
874 if (is_name_id != 0) {
006a0b87
LP
875 struct kdbus_cmd_match *m;
876 uint64_t sz;
777d7a61
LP
877
878 /* If the name argument is missing or is a unique
73842d62 879 * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
777d7a61
LP
880 * for it */
881
006a0b87
LP
882 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
883 offsetof(struct kdbus_item, id_change) +
884 sizeof(struct kdbus_notify_id_change));
777d7a61 885
006a0b87
LP
886 m = alloca0(sz);
887 m->size = sz;
888 m->cookie = cookie;
777d7a61 889
006a0b87 890 item = m->items;
dff91e8b
LP
891 item->size =
892 offsetof(struct kdbus_item, id_change) +
893 sizeof(struct kdbus_notify_id_change);
ff2ea192 894 item->id_change.id = name_id;
777d7a61
LP
895
896 /* If the old name is unset or empty, then this can
897 * match against added ids */
898 if (!old_owner || old_owner[0] == 0) {
73842d62 899 item->type = KDBUS_ITEM_ID_ADD;
777d7a61
LP
900
901 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
902 if (r < 0)
903 return -errno;
904 }
905
906 /* If thew new name is unset or empty, then this can
73842d62 907 * match against removed ids */
777d7a61 908 if (!new_owner || new_owner[0] == 0) {
73842d62 909 item->type = KDBUS_ITEM_ID_REMOVE;
777d7a61
LP
910
911 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
912 if (r < 0)
913 return -errno;
914 }
915 }
916
917 return 0;
918}
919
53461b74 920int bus_add_match_internal_kernel(
c7819669 921 sd_bus *bus,
53461b74 922 uint64_t id,
c7819669
LP
923 struct bus_match_component *components,
924 unsigned n_components,
925 uint64_t cookie) {
926
e7176abb
LP
927 struct kdbus_cmd_match *m;
928 struct kdbus_item *item;
929 uint64_t bloom[BLOOM_SIZE/8];
930 size_t sz;
931 const char *sender = NULL;
932 size_t sender_length = 0;
73842d62 933 uint64_t src_id = KDBUS_MATCH_ID_ANY;
e7176abb
LP
934 bool using_bloom = false;
935 unsigned i;
936 bool matches_name_change = true;
937 const char *name_change_arg[3] = {};
c7819669
LP
938 int r;
939
392d5b37 940 assert(bus);
de1c301e 941
e7176abb 942 zero(bloom);
c7819669 943
85feb8e4 944 sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
c7819669 945
e7176abb
LP
946 for (i = 0; i < n_components; i++) {
947 struct bus_match_component *c = &components[i];
777d7a61 948
e7176abb 949 switch (c->type) {
c7819669 950
e7176abb
LP
951 case BUS_MATCH_SENDER:
952 if (!streq(c->value_str, "org.freedesktop.DBus"))
953 matches_name_change = false;
777d7a61 954
e7176abb
LP
955 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
956 if (r < 0)
957 return r;
85feb8e4
LP
958 else if (r > 0)
959 sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
960 else {
e7176abb
LP
961 sender = c->value_str;
962 sender_length = strlen(sender);
963 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
964 }
777d7a61 965
e7176abb 966 break;
c7819669 967
e7176abb
LP
968 case BUS_MATCH_MESSAGE_TYPE:
969 if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
970 matches_name_change = false;
777d7a61 971
e7176abb
LP
972 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
973 using_bloom = true;
974 break;
c7819669 975
e7176abb
LP
976 case BUS_MATCH_INTERFACE:
977 if (!streq(c->value_str, "org.freedesktop.DBus"))
978 matches_name_change = false;
c7819669 979
e7176abb
LP
980 bloom_add_pair(bloom, "interface", c->value_str);
981 using_bloom = true;
982 break;
86312ab8 983
e7176abb
LP
984 case BUS_MATCH_MEMBER:
985 if (!streq(c->value_str, "NameOwnerChanged"))
986 matches_name_change = false;
777d7a61 987
e7176abb
LP
988 bloom_add_pair(bloom, "member", c->value_str);
989 using_bloom = true;
990 break;
86312ab8 991
e7176abb
LP
992 case BUS_MATCH_PATH:
993 if (!streq(c->value_str, "/org/freedesktop/DBus"))
994 matches_name_change = false;
86312ab8 995
e7176abb
LP
996 bloom_add_pair(bloom, "path", c->value_str);
997 using_bloom = true;
998 break;
999
1000 case BUS_MATCH_PATH_NAMESPACE:
1001 if (!streq(c->value_str, "/")) {
1002 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
86312ab8 1003 using_bloom = true;
86312ab8 1004 }
e7176abb 1005 break;
86312ab8 1006
e7176abb
LP
1007 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
1008 char buf[sizeof("arg")-1 + 2 + 1];
86312ab8 1009
e7176abb
LP
1010 if (c->type - BUS_MATCH_ARG < 3)
1011 name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
86312ab8 1012
e7176abb
LP
1013 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
1014 bloom_add_pair(bloom, buf, c->value_str);
1015 using_bloom = true;
1016 break;
c7819669
LP
1017 }
1018
e7176abb
LP
1019 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
1020 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
c7819669 1021
e7176abb
LP
1022 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
1023 bloom_add_pair(bloom, buf, c->value_str);
1024 using_bloom = true;
1025 break;
1026 }
c7819669 1027
e7176abb
LP
1028 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
1029 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
c7819669 1030
e7176abb
LP
1031 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
1032 bloom_add_pair(bloom, buf, c->value_str);
1033 using_bloom = true;
1034 break;
c7819669
LP
1035 }
1036
e7176abb
LP
1037 case BUS_MATCH_DESTINATION:
1038 /* The bloom filter does not include
1039 the destination, since it is only
1040 available for broadcast messages
1041 which do not carry a destination
1042 since they are undirected. */
1043 break;
1044
1045 case BUS_MATCH_ROOT:
1046 case BUS_MATCH_VALUE:
1047 case BUS_MATCH_LEAF:
1048 case _BUS_MATCH_NODE_TYPE_MAX:
1049 case _BUS_MATCH_NODE_TYPE_INVALID:
1050 assert_not_reached("Invalid match type?");
c7819669 1051 }
e7176abb
LP
1052 }
1053
1054 if (using_bloom)
1055 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
1056
1057 m = alloca0(sz);
1058 m->size = sz;
1059 m->cookie = cookie;
98531b57 1060 m->owner_id = id;
e7176abb
LP
1061
1062 item = m->items;
1063
85feb8e4
LP
1064 if (src_id != KDBUS_MATCH_ID_ANY) {
1065 item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
1066 item->type = KDBUS_ITEM_ID;
1067 item->id = src_id;
73842d62 1068 item = KDBUS_ITEM_NEXT(item);
85feb8e4
LP
1069 }
1070
1071 if (using_bloom) {
e7176abb 1072 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
73842d62 1073 item->type = KDBUS_ITEM_BLOOM;
e7176abb 1074 memcpy(item->data64, bloom, BLOOM_SIZE);
85feb8e4 1075 item = KDBUS_ITEM_NEXT(item);
e7176abb
LP
1076 }
1077
1078 if (sender) {
1079 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
73842d62 1080 item->type = KDBUS_ITEM_NAME;
e7176abb
LP
1081 memcpy(item->str, sender, sender_length + 1);
1082 }
1083
1084 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
1085 if (r < 0)
1086 return -errno;
1087
1088 if (matches_name_change) {
1089
1090 /* If this match could theoretically match
1091 * NameOwnerChanged messages, we need to
1092 * install a second non-bloom filter explitly
1093 * for it */
c7819669 1094
e7176abb 1095 r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
c7819669 1096 if (r < 0)
e7176abb
LP
1097 return r;
1098 }
c7819669 1099
e7176abb
LP
1100 return 0;
1101}
777d7a61 1102
e7176abb
LP
1103static int bus_add_match_internal_dbus1(
1104 sd_bus *bus,
1105 const char *match) {
777d7a61 1106
e7176abb
LP
1107 assert(bus);
1108 assert(match);
777d7a61 1109
e7176abb
LP
1110 return sd_bus_call_method(
1111 bus,
1112 "org.freedesktop.DBus",
cd789fdf 1113 "/org/freedesktop/DBus",
e7176abb
LP
1114 "org.freedesktop.DBus",
1115 "AddMatch",
1116 NULL,
1117 NULL,
1118 "s",
1119 match);
de1c301e
LP
1120}
1121
e7176abb
LP
1122int bus_add_match_internal(
1123 sd_bus *bus,
1124 const char *match,
1125 struct bus_match_component *components,
1126 unsigned n_components,
1127 uint64_t cookie) {
1128
1129 assert(bus);
1130 assert(match);
1131
1132 if (bus->is_kernel)
53461b74 1133 return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie);
e7176abb
LP
1134 else
1135 return bus_add_match_internal_dbus1(bus, match);
1136}
1137
53461b74 1138int bus_remove_match_internal_kernel(
c7819669 1139 sd_bus *bus,
53461b74 1140 uint64_t id,
c7819669
LP
1141 uint64_t cookie) {
1142
e7176abb 1143 struct kdbus_cmd_match m;
c7819669
LP
1144 int r;
1145
392d5b37 1146 assert(bus);
de1c301e 1147
e7176abb
LP
1148 zero(m);
1149 m.size = offsetof(struct kdbus_cmd_match, items);
1150 m.cookie = cookie;
98531b57 1151 m.owner_id = id;
c7819669 1152
e7176abb
LP
1153 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
1154 if (r < 0)
1155 return -errno;
c7819669 1156
e7176abb
LP
1157 return 0;
1158}
c7819669 1159
e7176abb
LP
1160static int bus_remove_match_internal_dbus1(
1161 sd_bus *bus,
1162 const char *match) {
777d7a61 1163
e7176abb
LP
1164 assert(bus);
1165 assert(match);
1166
1167 return sd_bus_call_method(
1168 bus,
1169 "org.freedesktop.DBus",
cd789fdf 1170 "/org/freedesktop/DBus",
e7176abb
LP
1171 "org.freedesktop.DBus",
1172 "RemoveMatch",
1173 NULL,
1174 NULL,
1175 "s",
1176 match);
1177}
1178
1179int bus_remove_match_internal(
1180 sd_bus *bus,
1181 const char *match,
1182 uint64_t cookie) {
1183
1184 assert(bus);
1185 assert(match);
1186
1187 if (bus->is_kernel)
53461b74 1188 return bus_remove_match_internal_kernel(bus, 0, cookie);
e7176abb
LP
1189 else
1190 return bus_remove_match_internal_dbus1(bus, match);
de1c301e 1191}
70666185 1192
d9f644e2 1193_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
8d162091 1194 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
1195 const char *mid;
1196 int r;
1197
8d162091
LP
1198 assert_return(bus, -EINVAL);
1199 assert_return(name, -EINVAL);
1200 assert_return(machine, -EINVAL);
1201 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
1202 assert_return(!bus_pid_changed(bus), -ECHILD);
45fd5e4d 1203 assert_return(service_name_is_valid(name), -EINVAL);
70666185
LP
1204
1205 if (streq_ptr(name, bus->unique_name))
1206 return sd_id128_get_machine(machine);
1207
8d162091
LP
1208 r = sd_bus_message_new_method_call(
1209 bus,
1210 name,
1211 "/",
1212 "org.freedesktop.DBus.Peer",
1213 "GetMachineId", &m);
1214 if (r < 0)
1215 return r;
1216
1217 r = sd_bus_message_set_no_auto_start(m, true);
1218 if (r < 0)
1219 return r;
70666185 1220
8d162091 1221 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
1222 if (r < 0)
1223 return r;
1224
1225 r = sd_bus_message_read(reply, "s", &mid);
1226 if (r < 0)
1227 return r;
1228
1229 return sd_id128_from_string(mid, machine);
1230}