]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-control.c
bus: add new sd_bus_creds object to encapsulate process credentials
[thirdparty/systemd.git] / src / libsystemd-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"
30
31#include "sd-bus.h"
32#include "bus-internal.h"
33#include "bus-message.h"
392d5b37 34#include "bus-control.h"
c7819669 35#include "bus-bloom.h"
40ca29a1 36#include "bus-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
de1c301e 41 if (!bus)
20902f3e
LP
42 return -EINVAL;
43 if (!unique)
44 return -EINVAL;
d5a2b9a6
LP
45 if (bus_pid_changed(bus))
46 return -ECHILD;
20902f3e
LP
47
48 r = bus_ensure_running(bus);
49 if (r < 0)
50 return r;
de1c301e 51
20902f3e
LP
52 *unique = bus->unique_name;
53 return 0;
de1c301e
LP
54}
55
d9f644e2 56_public_ int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
d4100e24 57 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
de1c301e
LP
58 uint32_t ret;
59 int r;
60
61 if (!bus)
62 return -EINVAL;
63 if (!name)
64 return -EINVAL;
f08838da
LP
65 if (!bus->bus_client)
66 return -EINVAL;
d5a2b9a6
LP
67 if (!BUS_IS_OPEN(bus->state))
68 return -ENOTCONN;
69 if (bus_pid_changed(bus))
70 return -ECHILD;
de1c301e 71
f08838da
LP
72 if (bus->is_kernel) {
73 struct kdbus_cmd_name *n;
74 size_t l;
75
76 l = strlen(name);
ed5c5dbd 77 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
f08838da 78 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
9b3848f2 79 n->flags = flags;
f08838da
LP
80 memcpy(n->name, name, l+1);
81
75722f1d
LP
82#ifdef HAVE_VALGRIND_MEMCHECK_H
83 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
84#endif
85
f08838da
LP
86 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
87 if (r < 0)
88 return -errno;
89
9b3848f2 90 return n->flags;
f08838da
LP
91 } else {
92 r = sd_bus_call_method(
93 bus,
94 "org.freedesktop.DBus",
95 "/",
96 "org.freedesktop.DBus",
97 "RequestName",
98 NULL,
99 &reply,
100 "su",
101 name,
102 flags);
103 if (r < 0)
104 return r;
105
106 r = sd_bus_message_read(reply, "u", &ret);
107 if (r < 0)
108 return r;
109
110 return ret;
111 }
de1c301e
LP
112}
113
d9f644e2 114_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
d4100e24 115 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
de1c301e
LP
116 uint32_t ret;
117 int r;
118
119 if (!bus)
120 return -EINVAL;
121 if (!name)
122 return -EINVAL;
f08838da
LP
123 if (!bus->bus_client)
124 return -EINVAL;
d5a2b9a6
LP
125 if (!BUS_IS_OPEN(bus->state))
126 return -ENOTCONN;
127 if (bus_pid_changed(bus))
128 return -ECHILD;
de1c301e 129
f08838da
LP
130 if (bus->is_kernel) {
131 struct kdbus_cmd_name *n;
132 size_t l;
133
134 l = strlen(name);
ed5c5dbd 135 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
f08838da 136 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
f08838da
LP
137 memcpy(n->name, name, l+1);
138
75722f1d
LP
139#ifdef HAVE_VALGRIND_MEMCHECK_H
140 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
141#endif
f08838da
LP
142 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
143 if (r < 0)
144 return -errno;
145
9b3848f2 146 return n->flags;
f08838da
LP
147 } else {
148 r = sd_bus_call_method(
149 bus,
150 "org.freedesktop.DBus",
151 "/",
152 "org.freedesktop.DBus",
153 "ReleaseName",
154 NULL,
155 &reply,
156 "s",
157 name);
158 if (r < 0)
159 return r;
160
161 r = sd_bus_message_read(reply, "u", &ret);
162 if (r < 0)
163 return r;
164 }
de1c301e
LP
165
166 return ret;
167}
168
d9f644e2 169_public_ int sd_bus_list_names(sd_bus *bus, char ***l) {
d4100e24 170 _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
de1c301e
LP
171 char **x = NULL;
172 int r;
173
174 if (!bus)
175 return -EINVAL;
176 if (!l)
177 return -EINVAL;
d5a2b9a6
LP
178 if (!BUS_IS_OPEN(bus->state))
179 return -ENOTCONN;
180 if (bus_pid_changed(bus))
181 return -ECHILD;
de1c301e 182
d4100e24 183 r = sd_bus_call_method(
de1c301e
LP
184 bus,
185 "org.freedesktop.DBus",
186 "/",
187 "org.freedesktop.DBus",
188 "ListNames",
d4100e24
LP
189 NULL,
190 &reply1,
191 NULL);
de1c301e
LP
192 if (r < 0)
193 return r;
194
d4100e24 195 r = sd_bus_call_method(
de1c301e
LP
196 bus,
197 "org.freedesktop.DBus",
198 "/",
199 "org.freedesktop.DBus",
200 "ListActivatableNames",
d4100e24
LP
201 NULL,
202 &reply2,
203 NULL);
de1c301e
LP
204 if (r < 0)
205 return r;
206
89ffcd2a
LP
207 r = bus_message_read_strv_extend(reply1, &x);
208 if (r < 0) {
209 strv_free(x);
de1c301e 210 return r;
89ffcd2a 211 }
de1c301e 212
89ffcd2a
LP
213 r = bus_message_read_strv_extend(reply2, &x);
214 if (r < 0) {
215 strv_free(x);
de1c301e 216 return r;
89ffcd2a 217 }
de1c301e
LP
218
219 *l = strv_uniq(x);
220 return 0;
221}
222
d9f644e2 223_public_ int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
d4100e24 224 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
89ffcd2a 225 const char *found;
de1c301e
LP
226 int r;
227
8d162091
LP
228 assert_return(bus, -EINVAL);
229 assert_return(name, -EINVAL);
230 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
231 assert_return(!bus_pid_changed(bus), -ECHILD);
de1c301e 232
d4100e24 233 r = sd_bus_call_method(
de1c301e
LP
234 bus,
235 "org.freedesktop.DBus",
236 "/",
237 "org.freedesktop.DBus",
238 "GetNameOwner",
d4100e24
LP
239 NULL,
240 &reply,
241 "s",
242 name);
de1c301e
LP
243 if (r < 0)
244 return r;
245
89ffcd2a
LP
246 r = sd_bus_message_read(reply, "s", &found);
247 if (r < 0)
248 return r;
249
250 if (owner) {
251 char *t;
252
253 t = strdup(found);
254 if (!t)
255 return -ENOMEM;
256
257 *owner = t;
258 }
259
260 return 0;
de1c301e
LP
261}
262
5b12334d 263_public_ int sd_bus_get_owner_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds) {
d4100e24 264 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5b12334d
LP
265 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
266 pid_t pid = 0;
de1c301e
LP
267 int r;
268
5b12334d
LP
269 assert_return(bus, -EINVAL);
270 assert_return(name, -EINVAL);
271 assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
272 assert_return(creds, -EINVAL);
273 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
274 assert_return(!bus_pid_changed(bus), -ECHILD);
de1c301e 275
5b12334d
LP
276 c = bus_creds_new();
277 if (!c)
278 return -ENOMEM;
de1c301e 279
5b12334d
LP
280 if ((mask & SD_BUS_CREDS_PID) ||
281 mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
282 uint32_t u;
de1c301e 283
5b12334d
LP
284 r = sd_bus_call_method(
285 bus,
286 "org.freedesktop.DBus",
287 "/",
288 "org.freedesktop.DBus",
289 "GetConnectionUnixProcessID",
290 NULL,
291 &reply,
292 "s",
293 name);
294 if (r < 0)
295 return r;
de1c301e 296
5b12334d
LP
297 r = sd_bus_message_read(reply, "u", &u);
298 if (r < 0)
299 return r;
de1c301e 300
5b12334d
LP
301 pid = u;
302 if (mask & SD_BUS_CREDS_PID) {
303 c->pid = u;
304 c->mask |= SD_BUS_CREDS_PID;
305 }
de1c301e 306
5b12334d
LP
307 reply = sd_bus_message_unref(reply);
308 }
309
310 if (mask & SD_BUS_CREDS_UID) {
311 uint32_t u;
312
313 r = sd_bus_call_method(
314 bus,
315 "org.freedesktop.DBus",
316 "/",
317 "org.freedesktop.DBus",
318 "GetConnectionUnixUser",
319 NULL,
320 &reply,
321 "s",
322 name);
323 if (r < 0)
324 return r;
325
326 r = sd_bus_message_read(reply, "u", &u);
327 if (r < 0)
328 return r;
329
330 c->uid = u;
331 c->mask |= SD_BUS_CREDS_UID;
332
333 reply = sd_bus_message_unref(reply);
334 }
335
336 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
337 const void *p;
338 size_t sz;
339
340 r = sd_bus_call_method(
341 bus,
342 "org.freedesktop.DBus",
343 "/",
344 "org.freedesktop.DBus",
345 "GetConnectionSELinuxSecurityContext",
346 NULL,
347 &reply,
348 "s",
349 name);
350 if (r < 0)
351 return r;
352
353 r = sd_bus_message_read_array(reply, 'y', &p, &sz);
354 if (r < 0)
355 return r;
356
357 c->label = strndup(p, sz);
358 if (!c->label)
359 return -ENOMEM;
360
361 c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
362 }
de1c301e 363
5b12334d 364 r = bus_creds_add_more(c, mask, pid, 0);
de1c301e
LP
365 if (r < 0)
366 return r;
367
5b12334d
LP
368 *creds = c;
369 c = NULL;
de1c301e 370
de1c301e
LP
371 return 0;
372}
373
c7819669
LP
374int bus_add_match_internal(
375 sd_bus *bus,
376 const char *match,
377 struct bus_match_component *components,
378 unsigned n_components,
379 uint64_t cookie) {
380
381 int r;
382
392d5b37
LP
383 assert(bus);
384 assert(match);
de1c301e 385
c7819669
LP
386 if (bus->is_kernel) {
387 struct kdbus_cmd_match *m;
388 struct kdbus_item *item;
389 uint64_t bloom[BLOOM_SIZE/8];
390 size_t sz;
391 const char *sender = NULL;
392 size_t sender_length = 0;
393 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
394 bool using_bloom = false;
395 unsigned i;
396
397 zero(bloom);
398
399 sz = offsetof(struct kdbus_cmd_match, items);
400
401 for (i = 0; i < n_components; i++) {
402 struct bus_match_component *c = &components[i];
403
404 switch (c->type) {
405
406 case BUS_MATCH_SENDER:
407 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
408 if (r < 0)
409 return r;
410
411 if (r > 0) {
412 sender = c->value_str;
413 sender_length = strlen(sender);
414 sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
415 }
416
417 break;
418
86312ab8
LP
419 case BUS_MATCH_MESSAGE_TYPE:
420 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
421 using_bloom = true;
c7819669
LP
422 break;
423
424 case BUS_MATCH_INTERFACE:
425 bloom_add_pair(bloom, "interface", c->value_str);
426 using_bloom = true;
427 break;
428
429 case BUS_MATCH_MEMBER:
430 bloom_add_pair(bloom, "member", c->value_str);
431 using_bloom = true;
432 break;
433
434 case BUS_MATCH_PATH:
435 bloom_add_pair(bloom, "path", c->value_str);
436 using_bloom = true;
437 break;
438
439 case BUS_MATCH_PATH_NAMESPACE:
f11e11e3
LP
440 if (!streq(c->value_str, "/")) {
441 bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
442 using_bloom = true;
443 }
c7819669
LP
444 break;
445
86312ab8
LP
446 case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
447 char buf[sizeof("arg")-1 + 2 + 1];
448
449 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
450 bloom_add_pair(bloom, buf, c->value_str);
451 using_bloom = true;
452 break;
453 }
454
455 case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
456 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
457
458 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
459 bloom_add_pair(bloom, buf, c->value_str);
460 using_bloom = true;
461 break;
462 }
463
464 case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
465 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
466
467 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
468 bloom_add_pair(bloom, buf, c->value_str);
469 using_bloom = true;
470 break;
471 }
472
473 case BUS_MATCH_DESTINATION:
474 /* The bloom filter does not include
475 the destination, since it is only
476 available for broadcast messages
477 which do not carry a destination
478 since they are undirected. */
c7819669
LP
479 break;
480
481 case BUS_MATCH_ROOT:
482 case BUS_MATCH_VALUE:
483 case BUS_MATCH_LEAF:
484 case _BUS_MATCH_NODE_TYPE_MAX:
485 case _BUS_MATCH_NODE_TYPE_INVALID:
486 assert_not_reached("Invalid match type?");
487 }
488 }
489
490 if (using_bloom)
491 sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
492
493 m = alloca0(sz);
494 m->size = sz;
495 m->cookie = cookie;
496 m->src_id = src_id;
497
498 item = m->items;
499
500 if (using_bloom) {
501 item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
502 item->type = KDBUS_MATCH_BLOOM;
503 memcpy(item->data64, bloom, BLOOM_SIZE);
504
505 item = KDBUS_ITEM_NEXT(item);
506 }
507
508 if (sender) {
509 item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
510 item->type = KDBUS_MATCH_SRC_NAME;
511 memcpy(item->str, sender, sender_length + 1);
512 }
513
514 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
515 if (r < 0)
516 return -errno;
517
518 } else {
519 return sd_bus_call_method(
520 bus,
521 "org.freedesktop.DBus",
522 "/",
523 "org.freedesktop.DBus",
524 "AddMatch",
525 NULL,
526 NULL,
527 "s",
528 match);
529 }
530
531 return 0;
de1c301e
LP
532}
533
c7819669
LP
534int bus_remove_match_internal(
535 sd_bus *bus,
536 const char *match,
537 uint64_t cookie) {
538
539 int r;
540
392d5b37
LP
541 assert(bus);
542 assert(match);
de1c301e 543
c7819669
LP
544 if (bus->is_kernel) {
545 struct kdbus_cmd_match m;
546
547 zero(m);
548 m.size = offsetof(struct kdbus_cmd_match, items);
549 m.cookie = cookie;
550
551 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
552 if (r < 0)
553 return -errno;
554
555 } else {
556 return sd_bus_call_method(
557 bus,
558 "org.freedesktop.DBus",
559 "/",
560 "org.freedesktop.DBus",
561 "RemoveMatch",
562 NULL,
563 NULL,
564 "s",
565 match);
566 }
567
568 return 0;
de1c301e 569}
70666185 570
d9f644e2 571_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
8d162091 572 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
70666185
LP
573 const char *mid;
574 int r;
575
8d162091
LP
576 assert_return(bus, -EINVAL);
577 assert_return(name, -EINVAL);
578 assert_return(machine, -EINVAL);
579 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
580 assert_return(!bus_pid_changed(bus), -ECHILD);
70666185
LP
581
582 if (streq_ptr(name, bus->unique_name))
583 return sd_id128_get_machine(machine);
584
8d162091
LP
585 r = sd_bus_message_new_method_call(
586 bus,
587 name,
588 "/",
589 "org.freedesktop.DBus.Peer",
590 "GetMachineId", &m);
591 if (r < 0)
592 return r;
593
594 r = sd_bus_message_set_no_auto_start(m, true);
595 if (r < 0)
596 return r;
70666185 597
8d162091 598 r = sd_bus_call(bus, m, 0, NULL, &reply);
70666185
LP
599 if (r < 0)
600 return r;
601
602 r = sd_bus_message_read(reply, "s", &mid);
603 if (r < 0)
604 return r;
605
606 return sd_id128_from_string(mid, machine);
607}