Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <inttypes.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <sys/ioctl.h>
10 : : #include <sys/resource.h>
11 : : #include <sys/socket.h>
12 : : #include <unistd.h>
13 : :
14 : : #include "sd-bus-protocol.h"
15 : : #include "sd-bus.h"
16 : : #include "sd-daemon.h"
17 : : #include "sd-event.h"
18 : : #include "sd-id128.h"
19 : :
20 : : #include "alloc-util.h"
21 : : #include "bus-internal.h"
22 : : #include "bus-label.h"
23 : : #include "bus-message.h"
24 : : #include "bus-util.h"
25 : : #include "cap-list.h"
26 : : #include "cgroup-util.h"
27 : : #include "def.h"
28 : : #include "escape.h"
29 : : #include "fd-util.h"
30 : : #include "missing.h"
31 : : #include "mountpoint-util.h"
32 : : #include "nsflags.h"
33 : : #include "parse-util.h"
34 : : #include "path-util.h"
35 : : #include "proc-cmdline.h"
36 : : #include "rlimit-util.h"
37 : : #include "stdio-util.h"
38 : : #include "strv.h"
39 : : #include "user-util.h"
40 : :
41 : 0 : static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
42 : 0 : sd_event *e = userdata;
43 : :
44 [ # # ]: 0 : assert(m);
45 [ # # ]: 0 : assert(e);
46 : :
47 : 0 : sd_bus_close(sd_bus_message_get_bus(m));
48 : 0 : sd_event_exit(e, 0);
49 : :
50 : 0 : return 1;
51 : : }
52 : :
53 : 0 : int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
54 : : const char *match;
55 : : const char *unique;
56 : : int r;
57 : :
58 [ # # ]: 0 : assert(e);
59 [ # # ]: 0 : assert(bus);
60 [ # # ]: 0 : assert(name);
61 : :
62 : : /* We unregister the name here and then wait for the
63 : : * NameOwnerChanged signal for this event to arrive before we
64 : : * quit. We do this in order to make sure that any queued
65 : : * requests are still processed before we really exit. */
66 : :
67 : 0 : r = sd_bus_get_unique_name(bus, &unique);
68 [ # # ]: 0 : if (r < 0)
69 : 0 : return r;
70 : :
71 [ # # # # : 0 : match = strjoina(
# # # # #
# # # ]
72 : : "sender='org.freedesktop.DBus',"
73 : : "type='signal',"
74 : : "interface='org.freedesktop.DBus',"
75 : : "member='NameOwnerChanged',"
76 : : "path='/org/freedesktop/DBus',"
77 : : "arg0='", name, "',",
78 : : "arg1='", unique, "',",
79 : : "arg2=''");
80 : :
81 : 0 : r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
82 [ # # ]: 0 : if (r < 0)
83 : 0 : return r;
84 : :
85 : 0 : r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
86 [ # # ]: 0 : if (r < 0)
87 : 0 : return r;
88 : :
89 : 0 : return 0;
90 : : }
91 : :
92 : 0 : int bus_event_loop_with_idle(
93 : : sd_event *e,
94 : : sd_bus *bus,
95 : : const char *name,
96 : : usec_t timeout,
97 : : check_idle_t check_idle,
98 : : void *userdata) {
99 : 0 : bool exiting = false;
100 : : int r, code;
101 : :
102 [ # # ]: 0 : assert(e);
103 [ # # ]: 0 : assert(bus);
104 [ # # ]: 0 : assert(name);
105 : :
106 : 0 : for (;;) {
107 : : bool idle;
108 : :
109 : 0 : r = sd_event_get_state(e);
110 [ # # ]: 0 : if (r < 0)
111 : 0 : return r;
112 [ # # ]: 0 : if (r == SD_EVENT_FINISHED)
113 : 0 : break;
114 : :
115 [ # # ]: 0 : if (check_idle)
116 : 0 : idle = check_idle(userdata);
117 : : else
118 : 0 : idle = true;
119 : :
120 [ # # # # ]: 0 : r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout);
121 [ # # ]: 0 : if (r < 0)
122 : 0 : return r;
123 : :
124 [ # # # # : 0 : if (r == 0 && !exiting && idle) {
# # ]
125 : :
126 : 0 : r = sd_bus_try_close(bus);
127 [ # # ]: 0 : if (r == -EBUSY)
128 : 0 : continue;
129 : :
130 : : /* Fallback for dbus1 connections: we
131 : : * unregister the name and wait for the
132 : : * response to come through for it */
133 [ # # ]: 0 : if (r == -EOPNOTSUPP) {
134 : :
135 : : /* Inform the service manager that we
136 : : * are going down, so that it will
137 : : * queue all further start requests,
138 : : * instead of assuming we are already
139 : : * running. */
140 : 0 : sd_notify(false, "STOPPING=1");
141 : :
142 : 0 : r = bus_async_unregister_and_exit(e, bus, name);
143 [ # # ]: 0 : if (r < 0)
144 : 0 : return r;
145 : :
146 : 0 : exiting = true;
147 : 0 : continue;
148 : : }
149 : :
150 [ # # ]: 0 : if (r < 0)
151 : 0 : return r;
152 : :
153 : 0 : sd_event_exit(e, 0);
154 : 0 : break;
155 : : }
156 : : }
157 : :
158 : 0 : r = sd_event_get_exit_code(e, &code);
159 [ # # ]: 0 : if (r < 0)
160 : 0 : return r;
161 : :
162 : 0 : return code;
163 : : }
164 : :
165 : 0 : int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
166 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
167 : 0 : int r, has_owner = 0;
168 : :
169 [ # # ]: 0 : assert(c);
170 [ # # ]: 0 : assert(name);
171 : :
172 : 0 : r = sd_bus_call_method(c,
173 : : "org.freedesktop.DBus",
174 : : "/org/freedesktop/dbus",
175 : : "org.freedesktop.DBus",
176 : : "NameHasOwner",
177 : : error,
178 : : &rep,
179 : : "s",
180 : : name);
181 [ # # ]: 0 : if (r < 0)
182 : 0 : return r;
183 : :
184 : 0 : r = sd_bus_message_read_basic(rep, 'b', &has_owner);
185 [ # # ]: 0 : if (r < 0)
186 : 0 : return sd_bus_error_set_errno(error, r);
187 : :
188 : 0 : return has_owner;
189 : : }
190 : :
191 : 0 : static int check_good_user(sd_bus_message *m, uid_t good_user) {
192 : 0 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
193 : : uid_t sender_uid;
194 : : int r;
195 : :
196 [ # # ]: 0 : assert(m);
197 : :
198 [ # # ]: 0 : if (good_user == UID_INVALID)
199 : 0 : return 0;
200 : :
201 : 0 : r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
202 [ # # ]: 0 : if (r < 0)
203 : 0 : return r;
204 : :
205 : : /* Don't trust augmented credentials for authorization */
206 [ # # # # ]: 0 : assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
207 : :
208 : 0 : r = sd_bus_creds_get_euid(creds, &sender_uid);
209 [ # # ]: 0 : if (r < 0)
210 : 0 : return r;
211 : :
212 : 0 : return sender_uid == good_user;
213 : : }
214 : :
215 : 0 : int bus_test_polkit(
216 : : sd_bus_message *call,
217 : : int capability,
218 : : const char *action,
219 : : const char **details,
220 : : uid_t good_user,
221 : : bool *_challenge,
222 : : sd_bus_error *e) {
223 : :
224 : : int r;
225 : :
226 [ # # ]: 0 : assert(call);
227 [ # # ]: 0 : assert(action);
228 : :
229 : : /* Tests non-interactively! */
230 : :
231 : 0 : r = check_good_user(call, good_user);
232 [ # # ]: 0 : if (r != 0)
233 : 0 : return r;
234 : :
235 : 0 : r = sd_bus_query_sender_privilege(call, capability);
236 [ # # ]: 0 : if (r < 0)
237 : 0 : return r;
238 [ # # ]: 0 : else if (r > 0)
239 : 0 : return 1;
240 : : #if ENABLE_POLKIT
241 : : else {
242 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
243 [ # # ]: 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
244 : 0 : int authorized = false, challenge = false;
245 : : const char *sender, **k, **v;
246 : :
247 : 0 : sender = sd_bus_message_get_sender(call);
248 [ # # ]: 0 : if (!sender)
249 : 0 : return -EBADMSG;
250 : :
251 : 0 : r = sd_bus_message_new_method_call(
252 : : call->bus,
253 : : &request,
254 : : "org.freedesktop.PolicyKit1",
255 : : "/org/freedesktop/PolicyKit1/Authority",
256 : : "org.freedesktop.PolicyKit1.Authority",
257 : : "CheckAuthorization");
258 [ # # ]: 0 : if (r < 0)
259 : 0 : return r;
260 : :
261 : 0 : r = sd_bus_message_append(
262 : : request,
263 : : "(sa{sv})s",
264 : : "system-bus-name", 1, "name", "s", sender,
265 : : action);
266 [ # # ]: 0 : if (r < 0)
267 : 0 : return r;
268 : :
269 : 0 : r = sd_bus_message_open_container(request, 'a', "{ss}");
270 [ # # ]: 0 : if (r < 0)
271 : 0 : return r;
272 : :
273 [ # # # # : 0 : STRV_FOREACH_PAIR(k, v, details) {
# # ]
274 : 0 : r = sd_bus_message_append(request, "{ss}", *k, *v);
275 [ # # ]: 0 : if (r < 0)
276 : 0 : return r;
277 : : }
278 : :
279 : 0 : r = sd_bus_message_close_container(request);
280 [ # # ]: 0 : if (r < 0)
281 : 0 : return r;
282 : :
283 : 0 : r = sd_bus_message_append(request, "us", 0, NULL);
284 [ # # ]: 0 : if (r < 0)
285 : 0 : return r;
286 : :
287 : 0 : r = sd_bus_call(call->bus, request, 0, e, &reply);
288 [ # # ]: 0 : if (r < 0) {
289 : : /* Treat no PK available as access denied */
290 [ # # ]: 0 : if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
291 : 0 : sd_bus_error_free(e);
292 : 0 : return -EACCES;
293 : : }
294 : :
295 : 0 : return r;
296 : : }
297 : :
298 : 0 : r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
299 [ # # ]: 0 : if (r < 0)
300 : 0 : return r;
301 : :
302 : 0 : r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
303 [ # # ]: 0 : if (r < 0)
304 : 0 : return r;
305 : :
306 [ # # ]: 0 : if (authorized)
307 : 0 : return 1;
308 : :
309 [ # # ]: 0 : if (_challenge) {
310 : 0 : *_challenge = challenge;
311 : 0 : return 0;
312 : : }
313 : : }
314 : : #endif
315 : :
316 : 0 : return -EACCES;
317 : : }
318 : :
319 : : #if ENABLE_POLKIT
320 : :
321 : : typedef struct AsyncPolkitQuery {
322 : : sd_bus_message *request, *reply;
323 : : sd_bus_message_handler_t callback;
324 : : void *userdata;
325 : : sd_bus_slot *slot;
326 : : Hashmap *registry;
327 : : } AsyncPolkitQuery;
328 : :
329 : 0 : static void async_polkit_query_free(AsyncPolkitQuery *q) {
330 : :
331 [ # # ]: 0 : if (!q)
332 : 0 : return;
333 : :
334 : 0 : sd_bus_slot_unref(q->slot);
335 : :
336 [ # # # # ]: 0 : if (q->registry && q->request)
337 : 0 : hashmap_remove(q->registry, q->request);
338 : :
339 : 0 : sd_bus_message_unref(q->request);
340 : 0 : sd_bus_message_unref(q->reply);
341 : :
342 : 0 : free(q);
343 : : }
344 : :
345 : 0 : static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
346 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
347 : 0 : AsyncPolkitQuery *q = userdata;
348 : : int r;
349 : :
350 [ # # ]: 0 : assert(reply);
351 [ # # ]: 0 : assert(q);
352 : :
353 : 0 : q->slot = sd_bus_slot_unref(q->slot);
354 : 0 : q->reply = sd_bus_message_ref(reply);
355 : :
356 : 0 : r = sd_bus_message_rewind(q->request, true);
357 [ # # ]: 0 : if (r < 0) {
358 : 0 : r = sd_bus_reply_method_errno(q->request, r, NULL);
359 : 0 : goto finish;
360 : : }
361 : :
362 : 0 : r = q->callback(q->request, q->userdata, &error_buffer);
363 : 0 : r = bus_maybe_reply_error(q->request, r, &error_buffer);
364 : :
365 : 0 : finish:
366 : 0 : async_polkit_query_free(q);
367 : :
368 : 0 : return r;
369 : : }
370 : :
371 : : #endif
372 : :
373 : 0 : int bus_verify_polkit_async(
374 : : sd_bus_message *call,
375 : : int capability,
376 : : const char *action,
377 : : const char **details,
378 : : bool interactive,
379 : : uid_t good_user,
380 : : Hashmap **registry,
381 : : sd_bus_error *error) {
382 : :
383 : : #if ENABLE_POLKIT
384 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
385 : : AsyncPolkitQuery *q;
386 : : const char *sender, **k, **v;
387 : : sd_bus_message_handler_t callback;
388 : : void *userdata;
389 : : int c;
390 : : #endif
391 : : int r;
392 : :
393 [ # # ]: 0 : assert(call);
394 [ # # ]: 0 : assert(action);
395 [ # # ]: 0 : assert(registry);
396 : :
397 : 0 : r = check_good_user(call, good_user);
398 [ # # ]: 0 : if (r != 0)
399 : 0 : return r;
400 : :
401 : : #if ENABLE_POLKIT
402 : 0 : q = hashmap_get(*registry, call);
403 [ # # ]: 0 : if (q) {
404 : : int authorized, challenge;
405 : :
406 : : /* This is the second invocation of this function, and
407 : : * there's already a response from polkit, let's
408 : : * process it */
409 [ # # ]: 0 : assert(q->reply);
410 : :
411 [ # # ]: 0 : if (sd_bus_message_is_method_error(q->reply, NULL)) {
412 : : const sd_bus_error *e;
413 : :
414 : 0 : e = sd_bus_message_get_error(q->reply);
415 : :
416 : : /* Treat no PK available as access denied */
417 [ # # ]: 0 : if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
418 : 0 : return -EACCES;
419 : :
420 : : /* Copy error from polkit reply */
421 : 0 : sd_bus_error_copy(error, e);
422 : 0 : return -sd_bus_error_get_errno(e);
423 : : }
424 : :
425 : 0 : r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
426 [ # # ]: 0 : if (r >= 0)
427 : 0 : r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
428 : :
429 [ # # ]: 0 : if (r < 0)
430 : 0 : return r;
431 : :
432 [ # # ]: 0 : if (authorized)
433 : 0 : return 1;
434 : :
435 [ # # ]: 0 : if (challenge)
436 : 0 : return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
437 : :
438 : 0 : return -EACCES;
439 : : }
440 : : #endif
441 : :
442 : 0 : r = sd_bus_query_sender_privilege(call, capability);
443 [ # # ]: 0 : if (r < 0)
444 : 0 : return r;
445 [ # # ]: 0 : else if (r > 0)
446 : 0 : return 1;
447 : :
448 : : #if ENABLE_POLKIT
449 [ # # ]: 0 : if (sd_bus_get_current_message(call->bus) != call)
450 : 0 : return -EINVAL;
451 : :
452 : 0 : callback = sd_bus_get_current_handler(call->bus);
453 [ # # ]: 0 : if (!callback)
454 : 0 : return -EINVAL;
455 : :
456 : 0 : userdata = sd_bus_get_current_userdata(call->bus);
457 : :
458 : 0 : sender = sd_bus_message_get_sender(call);
459 [ # # ]: 0 : if (!sender)
460 : 0 : return -EBADMSG;
461 : :
462 : 0 : c = sd_bus_message_get_allow_interactive_authorization(call);
463 [ # # ]: 0 : if (c < 0)
464 : 0 : return c;
465 [ # # ]: 0 : if (c > 0)
466 : 0 : interactive = true;
467 : :
468 : 0 : r = hashmap_ensure_allocated(registry, NULL);
469 [ # # ]: 0 : if (r < 0)
470 : 0 : return r;
471 : :
472 : 0 : r = sd_bus_message_new_method_call(
473 : : call->bus,
474 : : &pk,
475 : : "org.freedesktop.PolicyKit1",
476 : : "/org/freedesktop/PolicyKit1/Authority",
477 : : "org.freedesktop.PolicyKit1.Authority",
478 : : "CheckAuthorization");
479 [ # # ]: 0 : if (r < 0)
480 : 0 : return r;
481 : :
482 : 0 : r = sd_bus_message_append(
483 : : pk,
484 : : "(sa{sv})s",
485 : : "system-bus-name", 1, "name", "s", sender,
486 : : action);
487 [ # # ]: 0 : if (r < 0)
488 : 0 : return r;
489 : :
490 : 0 : r = sd_bus_message_open_container(pk, 'a', "{ss}");
491 [ # # ]: 0 : if (r < 0)
492 : 0 : return r;
493 : :
494 [ # # # # : 0 : STRV_FOREACH_PAIR(k, v, details) {
# # ]
495 : 0 : r = sd_bus_message_append(pk, "{ss}", *k, *v);
496 [ # # ]: 0 : if (r < 0)
497 : 0 : return r;
498 : : }
499 : :
500 : 0 : r = sd_bus_message_close_container(pk);
501 [ # # ]: 0 : if (r < 0)
502 : 0 : return r;
503 : :
504 : 0 : r = sd_bus_message_append(pk, "us", interactive, NULL);
505 [ # # ]: 0 : if (r < 0)
506 : 0 : return r;
507 : :
508 : 0 : q = new0(AsyncPolkitQuery, 1);
509 [ # # ]: 0 : if (!q)
510 : 0 : return -ENOMEM;
511 : :
512 : 0 : q->request = sd_bus_message_ref(call);
513 : 0 : q->callback = callback;
514 : 0 : q->userdata = userdata;
515 : :
516 : 0 : r = hashmap_put(*registry, call, q);
517 [ # # ]: 0 : if (r < 0) {
518 : 0 : async_polkit_query_free(q);
519 : 0 : return r;
520 : : }
521 : :
522 : 0 : q->registry = *registry;
523 : :
524 : 0 : r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
525 [ # # ]: 0 : if (r < 0) {
526 : 0 : async_polkit_query_free(q);
527 : 0 : return r;
528 : : }
529 : :
530 : 0 : return 0;
531 : : #endif
532 : :
533 : : return -EACCES;
534 : : }
535 : :
536 : 68 : void bus_verify_polkit_async_registry_free(Hashmap *registry) {
537 : : #if ENABLE_POLKIT
538 [ - + ]: 68 : hashmap_free_with_destructor(registry, async_polkit_query_free);
539 : : #endif
540 : 68 : }
541 : :
542 : 0 : int bus_check_peercred(sd_bus *c) {
543 : : struct ucred ucred;
544 : : int fd, r;
545 : :
546 [ # # ]: 0 : assert(c);
547 : :
548 : 0 : fd = sd_bus_get_fd(c);
549 [ # # ]: 0 : if (fd < 0)
550 : 0 : return fd;
551 : :
552 : 0 : r = getpeercred(fd, &ucred);
553 [ # # ]: 0 : if (r < 0)
554 : 0 : return r;
555 : :
556 [ # # # # ]: 0 : if (ucred.uid != 0 && ucred.uid != geteuid())
557 : 0 : return -EPERM;
558 : :
559 : 0 : return 1;
560 : : }
561 : :
562 : 0 : int bus_connect_system_systemd(sd_bus **_bus) {
563 : 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
564 : : int r;
565 : :
566 [ # # ]: 0 : assert(_bus);
567 : :
568 [ # # ]: 0 : if (geteuid() != 0)
569 : 0 : return sd_bus_default_system(_bus);
570 : :
571 : : /* If we are root then let's talk directly to the system
572 : : * instance, instead of going via the bus */
573 : :
574 : 0 : r = sd_bus_new(&bus);
575 [ # # ]: 0 : if (r < 0)
576 : 0 : return r;
577 : :
578 : 0 : r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
579 [ # # ]: 0 : if (r < 0)
580 : 0 : return r;
581 : :
582 : 0 : r = sd_bus_start(bus);
583 [ # # ]: 0 : if (r < 0)
584 : 0 : return sd_bus_default_system(_bus);
585 : :
586 : 0 : r = bus_check_peercred(bus);
587 [ # # ]: 0 : if (r < 0)
588 : 0 : return r;
589 : :
590 : 0 : *_bus = TAKE_PTR(bus);
591 : :
592 : 0 : return 0;
593 : : }
594 : :
595 : 0 : int bus_connect_user_systemd(sd_bus **_bus) {
596 : 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
597 : 0 : _cleanup_free_ char *ee = NULL;
598 : : const char *e;
599 : : int r;
600 : :
601 [ # # ]: 0 : assert(_bus);
602 : :
603 : 0 : e = secure_getenv("XDG_RUNTIME_DIR");
604 [ # # ]: 0 : if (!e)
605 : 0 : return sd_bus_default_user(_bus);
606 : :
607 : 0 : ee = bus_address_escape(e);
608 [ # # ]: 0 : if (!ee)
609 : 0 : return -ENOMEM;
610 : :
611 : 0 : r = sd_bus_new(&bus);
612 [ # # ]: 0 : if (r < 0)
613 : 0 : return r;
614 : :
615 : 0 : bus->address = strjoin("unix:path=", ee, "/systemd/private");
616 [ # # ]: 0 : if (!bus->address)
617 : 0 : return -ENOMEM;
618 : :
619 : 0 : r = sd_bus_start(bus);
620 [ # # ]: 0 : if (r < 0)
621 : 0 : return sd_bus_default_user(_bus);
622 : :
623 : 0 : r = bus_check_peercred(bus);
624 [ # # ]: 0 : if (r < 0)
625 : 0 : return r;
626 : :
627 : 0 : *_bus = TAKE_PTR(bus);
628 : :
629 : 0 : return 0;
630 : : }
631 : :
632 : 0 : int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value) {
633 [ # # ]: 0 : assert(name);
634 : :
635 [ # # # # ]: 0 : if (expected_value && !streq_ptr(expected_value, value))
636 : 0 : return 0;
637 : :
638 [ # # ]: 0 : if (only_value)
639 : 0 : puts(value);
640 : : else
641 : 0 : printf("%s=%s\n", name, value);
642 : :
643 : 0 : return 0;
644 : : }
645 : :
646 : 0 : int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
647 : : va_list ap;
648 : : int r;
649 : :
650 [ # # ]: 0 : assert(name);
651 [ # # ]: 0 : assert(fmt);
652 : :
653 [ # # ]: 0 : if (expected_value) {
654 : 0 : _cleanup_free_ char *s = NULL;
655 : :
656 : 0 : va_start(ap, fmt);
657 : 0 : r = vasprintf(&s, fmt, ap);
658 : 0 : va_end(ap);
659 [ # # ]: 0 : if (r < 0)
660 : 0 : return -ENOMEM;
661 : :
662 [ # # ]: 0 : if (streq_ptr(expected_value, s)) {
663 [ # # ]: 0 : if (only_value)
664 : 0 : puts(s);
665 : : else
666 : 0 : printf("%s=%s\n", name, s);
667 : : }
668 : :
669 : 0 : return 0;
670 : : }
671 : :
672 [ # # ]: 0 : if (!only_value)
673 : 0 : printf("%s=", name);
674 : 0 : va_start(ap, fmt);
675 : 0 : vprintf(fmt, ap);
676 : 0 : va_end(ap);
677 : 0 : puts("");
678 : :
679 : 0 : return 0;
680 : : }
681 : :
682 : 0 : static int bus_print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
683 : : char type;
684 : : const char *contents;
685 : : int r;
686 : :
687 [ # # ]: 0 : assert(name);
688 [ # # ]: 0 : assert(m);
689 : :
690 : 0 : r = sd_bus_message_peek_type(m, &type, &contents);
691 [ # # ]: 0 : if (r < 0)
692 : 0 : return r;
693 : :
694 [ # # # # : 0 : switch (type) {
# # # #
# ]
695 : :
696 : 0 : case SD_BUS_TYPE_STRING: {
697 : : const char *s;
698 : :
699 : 0 : r = sd_bus_message_read_basic(m, type, &s);
700 [ # # ]: 0 : if (r < 0)
701 : 0 : return r;
702 : :
703 [ # # # # ]: 0 : if (all || !isempty(s)) {
704 : : bool good;
705 : :
706 : : /* This property has a single value, so we need to take
707 : : * care not to print a new line, everything else is OK. */
708 : 0 : good = !strchr(s, '\n');
709 [ # # ]: 0 : bus_print_property_value(name, expected_value, value, good ? s : "[unprintable]");
710 : : }
711 : :
712 : 0 : return 1;
713 : : }
714 : :
715 : 0 : case SD_BUS_TYPE_BOOLEAN: {
716 : : int b;
717 : :
718 : 0 : r = sd_bus_message_read_basic(m, type, &b);
719 [ # # ]: 0 : if (r < 0)
720 : 0 : return r;
721 : :
722 [ # # # # ]: 0 : if (expected_value && parse_boolean(expected_value) != b)
723 : 0 : return 1;
724 : :
725 : 0 : bus_print_property_value(name, NULL, value, yes_no(b));
726 : 0 : return 1;
727 : : }
728 : :
729 : 0 : case SD_BUS_TYPE_UINT64: {
730 : : uint64_t u;
731 : :
732 : 0 : r = sd_bus_message_read_basic(m, type, &u);
733 [ # # ]: 0 : if (r < 0)
734 : 0 : return r;
735 : :
736 : : /* Yes, heuristics! But we can change this check
737 : : * should it turn out to not be sufficient */
738 : :
739 [ # # ]: 0 : if (endswith(name, "Timestamp") ||
740 [ # # ]: 0 : STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec")) {
741 : : char timestamp[FORMAT_TIMESTAMP_MAX];
742 : : const char *t;
743 : :
744 : 0 : t = format_timestamp(timestamp, sizeof(timestamp), u);
745 [ # # # # ]: 0 : if (t || all)
746 : 0 : bus_print_property_value(name, expected_value, value, strempty(t));
747 : :
748 [ # # ]: 0 : } else if (strstr(name, "USec")) {
749 : : char timespan[FORMAT_TIMESPAN_MAX];
750 : :
751 : 0 : (void) format_timespan(timespan, sizeof(timespan), u, 0);
752 : 0 : bus_print_property_value(name, expected_value, value, timespan);
753 : :
754 [ # # ]: 0 : } else if (streq(name, "RestrictNamespaces")) {
755 [ # # ]: 0 : _cleanup_free_ char *s = NULL;
756 : : const char *result;
757 : :
758 [ # # ]: 0 : if ((u & NAMESPACE_FLAGS_ALL) == 0)
759 : 0 : result = "yes";
760 [ # # ]: 0 : else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL))
761 : 0 : result = "no";
762 : : else {
763 : 0 : r = namespace_flags_to_string(u, &s);
764 [ # # ]: 0 : if (r < 0)
765 : 0 : return r;
766 : :
767 : 0 : result = s;
768 : : }
769 : :
770 : 0 : bus_print_property_value(name, expected_value, value, result);
771 : :
772 [ # # ]: 0 : } else if (streq(name, "MountFlags")) {
773 : : const char *result;
774 : :
775 : 0 : result = mount_propagation_flags_to_string(u);
776 [ # # ]: 0 : if (!result)
777 : 0 : return -EINVAL;
778 : :
779 : 0 : bus_print_property_value(name, expected_value, value, result);
780 : :
781 [ # # ]: 0 : } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
782 [ # # ]: 0 : _cleanup_free_ char *s = NULL;
783 : :
784 : 0 : r = capability_set_to_string_alloc(u, &s);
785 [ # # ]: 0 : if (r < 0)
786 : 0 : return r;
787 : :
788 : 0 : bus_print_property_value(name, expected_value, value, s);
789 : :
790 [ # # # # ]: 0 : } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
791 [ # # # # ]: 0 : (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
792 [ # # # # ]: 0 : (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
793 [ # # # # ]: 0 : (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
794 [ # # # # ]: 0 : (endswith(name, "NSec") && u == (uint64_t) -1))
795 : :
796 : 0 : bus_print_property_value(name, expected_value, value, "[not set]");
797 : :
798 [ # # # # ]: 0 : else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
799 [ # # # # : 0 : (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
# # ]
800 [ # # # # ]: 0 : (startswith(name, "Limit") && u == (uint64_t) -1) ||
801 [ # # ]: 0 : (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
802 : :
803 : 0 : bus_print_property_value(name, expected_value, value, "infinity");
804 [ # # # # ]: 0 : else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1)
805 : 0 : bus_print_property_value(name, expected_value, value, "[no data]");
806 : : else
807 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u);
808 : :
809 : 0 : return 1;
810 : : }
811 : :
812 : 0 : case SD_BUS_TYPE_INT64: {
813 : : int64_t i;
814 : :
815 : 0 : r = sd_bus_message_read_basic(m, type, &i);
816 [ # # ]: 0 : if (r < 0)
817 : 0 : return r;
818 : :
819 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIi64, i);
820 : 0 : return 1;
821 : : }
822 : :
823 : 0 : case SD_BUS_TYPE_UINT32: {
824 : : uint32_t u;
825 : :
826 : 0 : r = sd_bus_message_read_basic(m, type, &u);
827 [ # # ]: 0 : if (r < 0)
828 : 0 : return r;
829 : :
830 [ # # # # ]: 0 : if (strstr(name, "UMask") || strstr(name, "Mode"))
831 : 0 : bus_print_property_valuef(name, expected_value, value, "%04o", u);
832 : :
833 [ # # ]: 0 : else if (streq(name, "UID")) {
834 [ # # ]: 0 : if (u == UID_INVALID)
835 : 0 : bus_print_property_value(name, expected_value, value, "[not set]");
836 : : else
837 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
838 [ # # ]: 0 : } else if (streq(name, "GID")) {
839 [ # # ]: 0 : if (u == GID_INVALID)
840 : 0 : bus_print_property_value(name, expected_value, value, "[not set]");
841 : : else
842 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
843 : : } else
844 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
845 : :
846 : 0 : return 1;
847 : : }
848 : :
849 : 0 : case SD_BUS_TYPE_INT32: {
850 : : int32_t i;
851 : :
852 : 0 : r = sd_bus_message_read_basic(m, type, &i);
853 [ # # ]: 0 : if (r < 0)
854 : 0 : return r;
855 : :
856 : 0 : bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
857 : 0 : return 1;
858 : : }
859 : :
860 : 0 : case SD_BUS_TYPE_DOUBLE: {
861 : : double d;
862 : :
863 : 0 : r = sd_bus_message_read_basic(m, type, &d);
864 [ # # ]: 0 : if (r < 0)
865 : 0 : return r;
866 : :
867 : 0 : bus_print_property_valuef(name, expected_value, value, "%g", d);
868 : 0 : return 1;
869 : : }
870 : :
871 : 0 : case SD_BUS_TYPE_ARRAY:
872 [ # # ]: 0 : if (streq(contents, "s")) {
873 : 0 : bool first = true;
874 : : const char *str;
875 : :
876 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, contents);
877 [ # # ]: 0 : if (r < 0)
878 : 0 : return r;
879 : :
880 [ # # ]: 0 : while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
881 : : bool good;
882 : :
883 [ # # # # ]: 0 : if (first && !value)
884 : 0 : printf("%s=", name);
885 : :
886 : : /* This property has multiple space-separated values, so
887 : : * neither spaces nor newlines can be allowed in a value. */
888 : 0 : good = str[strcspn(str, " \n")] == '\0';
889 : :
890 [ # # # # ]: 0 : printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
891 : :
892 : 0 : first = false;
893 : : }
894 [ # # ]: 0 : if (r < 0)
895 : 0 : return r;
896 : :
897 [ # # # # : 0 : if (first && all && !value)
# # ]
898 : 0 : printf("%s=", name);
899 [ # # # # ]: 0 : if (!first || all)
900 : 0 : puts("");
901 : :
902 : 0 : r = sd_bus_message_exit_container(m);
903 [ # # ]: 0 : if (r < 0)
904 : 0 : return r;
905 : :
906 : 0 : return 1;
907 : :
908 [ # # ]: 0 : } else if (streq(contents, "y")) {
909 : : const uint8_t *u;
910 : : size_t n;
911 : :
912 : 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, (const void**) &u, &n);
913 [ # # ]: 0 : if (r < 0)
914 : 0 : return r;
915 : :
916 [ # # # # ]: 0 : if (all || n > 0) {
917 : : unsigned i;
918 : :
919 [ # # ]: 0 : if (!value)
920 : 0 : printf("%s=", name);
921 : :
922 [ # # ]: 0 : for (i = 0; i < n; i++)
923 : 0 : printf("%02x", u[i]);
924 : :
925 : 0 : puts("");
926 : : }
927 : :
928 : 0 : return 1;
929 : :
930 [ # # ]: 0 : } else if (streq(contents, "u")) {
931 : : uint32_t *u;
932 : : size_t n;
933 : :
934 : 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_UINT32, (const void**) &u, &n);
935 [ # # ]: 0 : if (r < 0)
936 : 0 : return r;
937 : :
938 [ # # # # ]: 0 : if (all || n > 0) {
939 : : unsigned i;
940 : :
941 [ # # ]: 0 : if (!value)
942 : 0 : printf("%s=", name);
943 : :
944 [ # # ]: 0 : for (i = 0; i < n; i++)
945 : 0 : printf("%08x", u[i]);
946 : :
947 : 0 : puts("");
948 : : }
949 : :
950 : 0 : return 1;
951 : : }
952 : :
953 : 0 : break;
954 : : }
955 : :
956 : 0 : return 0;
957 : : }
958 : :
959 : 0 : int bus_message_print_all_properties(
960 : : sd_bus_message *m,
961 : : bus_message_print_t func,
962 : : char **filter,
963 : : bool value,
964 : : bool all,
965 : : Set **found_properties) {
966 : :
967 : : int r;
968 : :
969 [ # # ]: 0 : assert(m);
970 : :
971 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
972 [ # # ]: 0 : if (r < 0)
973 : 0 : return r;
974 : :
975 [ # # ]: 0 : while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
976 [ # # ]: 0 : _cleanup_free_ char *name_with_equal = NULL;
977 : 0 : const char *name, *contents, *expected_value = NULL;
978 : :
979 : 0 : r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
980 [ # # ]: 0 : if (r < 0)
981 : 0 : return r;
982 : :
983 [ # # ]: 0 : if (found_properties) {
984 : 0 : r = set_ensure_allocated(found_properties, &string_hash_ops);
985 [ # # ]: 0 : if (r < 0)
986 : 0 : return log_oom();
987 : :
988 : 0 : r = set_put(*found_properties, name);
989 [ # # # # ]: 0 : if (r < 0 && r != -EEXIST)
990 : 0 : return log_oom();
991 : : }
992 : :
993 : 0 : name_with_equal = strjoin(name, "=");
994 [ # # ]: 0 : if (!name_with_equal)
995 : 0 : return log_oom();
996 : :
997 [ # # # # ]: 0 : if (!filter || strv_find(filter, name) ||
998 [ # # ]: 0 : (expected_value = strv_find_startswith(filter, name_with_equal))) {
999 : 0 : r = sd_bus_message_peek_type(m, NULL, &contents);
1000 [ # # ]: 0 : if (r < 0)
1001 : 0 : return r;
1002 : :
1003 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1004 [ # # ]: 0 : if (r < 0)
1005 : 0 : return r;
1006 : :
1007 [ # # ]: 0 : if (func)
1008 : 0 : r = func(name, expected_value, m, value, all);
1009 [ # # # # ]: 0 : if (!func || r == 0)
1010 : 0 : r = bus_print_property(name, expected_value, m, value, all);
1011 [ # # ]: 0 : if (r < 0)
1012 : 0 : return r;
1013 [ # # ]: 0 : if (r == 0) {
1014 [ # # # # ]: 0 : if (all && !expected_value)
1015 : 0 : printf("%s=[unprintable]\n", name);
1016 : : /* skip what we didn't read */
1017 : 0 : r = sd_bus_message_skip(m, contents);
1018 [ # # ]: 0 : if (r < 0)
1019 : 0 : return r;
1020 : : }
1021 : :
1022 : 0 : r = sd_bus_message_exit_container(m);
1023 [ # # ]: 0 : if (r < 0)
1024 : 0 : return r;
1025 : : } else {
1026 : 0 : r = sd_bus_message_skip(m, "v");
1027 [ # # ]: 0 : if (r < 0)
1028 : 0 : return r;
1029 : : }
1030 : :
1031 : 0 : r = sd_bus_message_exit_container(m);
1032 [ # # ]: 0 : if (r < 0)
1033 : 0 : return r;
1034 : : }
1035 [ # # ]: 0 : if (r < 0)
1036 : 0 : return r;
1037 : :
1038 : 0 : r = sd_bus_message_exit_container(m);
1039 [ # # ]: 0 : if (r < 0)
1040 : 0 : return r;
1041 : :
1042 : 0 : return 0;
1043 : : }
1044 : :
1045 : 0 : int bus_print_all_properties(
1046 : : sd_bus *bus,
1047 : : const char *dest,
1048 : : const char *path,
1049 : : bus_message_print_t func,
1050 : : char **filter,
1051 : : bool value,
1052 : : bool all,
1053 : : Set **found_properties) {
1054 : :
1055 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1056 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1057 : : int r;
1058 : :
1059 [ # # ]: 0 : assert(bus);
1060 [ # # ]: 0 : assert(path);
1061 : :
1062 : 0 : r = sd_bus_call_method(bus,
1063 : : dest,
1064 : : path,
1065 : : "org.freedesktop.DBus.Properties",
1066 : : "GetAll",
1067 : : &error,
1068 : : &reply,
1069 : : "s", "");
1070 [ # # ]: 0 : if (r < 0)
1071 : 0 : return r;
1072 : :
1073 : 0 : return bus_message_print_all_properties(reply, func, filter, value, all, found_properties);
1074 : : }
1075 : :
1076 : 0 : int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1077 : 0 : sd_id128_t *p = userdata;
1078 : : const void *v;
1079 : : size_t n;
1080 : : int r;
1081 : :
1082 : 0 : r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
1083 [ # # ]: 0 : if (r < 0)
1084 : 0 : return r;
1085 : :
1086 [ # # ]: 0 : if (n == 0)
1087 : 0 : *p = SD_ID128_NULL;
1088 [ # # ]: 0 : else if (n == 16)
1089 : 0 : memcpy((*p).bytes, v, n);
1090 : : else
1091 : 0 : return -EINVAL;
1092 : :
1093 : 0 : return 0;
1094 : : }
1095 : :
1096 : 0 : static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
1097 : : char type;
1098 : : int r;
1099 : :
1100 : 0 : r = sd_bus_message_peek_type(m, &type, NULL);
1101 [ # # ]: 0 : if (r < 0)
1102 : 0 : return r;
1103 : :
1104 [ # # # # : 0 : switch (type) {
# # # ]
1105 : :
1106 : 0 : case SD_BUS_TYPE_STRING: {
1107 : 0 : const char **p = userdata;
1108 : : const char *s;
1109 : :
1110 : 0 : r = sd_bus_message_read_basic(m, type, &s);
1111 [ # # ]: 0 : if (r < 0)
1112 : 0 : return r;
1113 : :
1114 [ # # ]: 0 : if (isempty(s))
1115 : 0 : s = NULL;
1116 : :
1117 [ # # ]: 0 : if (flags & BUS_MAP_STRDUP)
1118 : 0 : return free_and_strdup((char **) userdata, s);
1119 : :
1120 : 0 : *p = s;
1121 : 0 : return 0;
1122 : : }
1123 : :
1124 : 0 : case SD_BUS_TYPE_ARRAY: {
1125 : 0 : _cleanup_strv_free_ char **l = NULL;
1126 : 0 : char ***p = userdata;
1127 : :
1128 : 0 : r = bus_message_read_strv_extend(m, &l);
1129 [ # # ]: 0 : if (r < 0)
1130 : 0 : return r;
1131 : :
1132 : 0 : return strv_free_and_replace(*p, l);
1133 : : }
1134 : :
1135 : 0 : case SD_BUS_TYPE_BOOLEAN: {
1136 : : int b;
1137 : :
1138 : 0 : r = sd_bus_message_read_basic(m, type, &b);
1139 [ # # ]: 0 : if (r < 0)
1140 : 0 : return r;
1141 : :
1142 [ # # ]: 0 : if (flags & BUS_MAP_BOOLEAN_AS_BOOL)
1143 : 0 : *(bool*) userdata = b;
1144 : : else
1145 : 0 : *(int*) userdata = b;
1146 : :
1147 : 0 : return 0;
1148 : : }
1149 : :
1150 : 0 : case SD_BUS_TYPE_INT32:
1151 : : case SD_BUS_TYPE_UINT32: {
1152 : 0 : uint32_t u, *p = userdata;
1153 : :
1154 : 0 : r = sd_bus_message_read_basic(m, type, &u);
1155 [ # # ]: 0 : if (r < 0)
1156 : 0 : return r;
1157 : :
1158 : 0 : *p = u;
1159 : 0 : return 0;
1160 : : }
1161 : :
1162 : 0 : case SD_BUS_TYPE_INT64:
1163 : : case SD_BUS_TYPE_UINT64: {
1164 : 0 : uint64_t t, *p = userdata;
1165 : :
1166 : 0 : r = sd_bus_message_read_basic(m, type, &t);
1167 [ # # ]: 0 : if (r < 0)
1168 : 0 : return r;
1169 : :
1170 : 0 : *p = t;
1171 : 0 : return 0;
1172 : : }
1173 : :
1174 : 0 : case SD_BUS_TYPE_DOUBLE: {
1175 : 0 : double d, *p = userdata;
1176 : :
1177 : 0 : r = sd_bus_message_read_basic(m, type, &d);
1178 [ # # ]: 0 : if (r < 0)
1179 : 0 : return r;
1180 : :
1181 : 0 : *p = d;
1182 : 0 : return 0;
1183 : : }}
1184 : :
1185 : 0 : return -EOPNOTSUPP;
1186 : : }
1187 : :
1188 : 0 : int bus_message_map_all_properties(
1189 : : sd_bus_message *m,
1190 : : const struct bus_properties_map *map,
1191 : : unsigned flags,
1192 : : sd_bus_error *error,
1193 : : void *userdata) {
1194 : :
1195 : : int r;
1196 : :
1197 [ # # ]: 0 : assert(m);
1198 [ # # ]: 0 : assert(map);
1199 : :
1200 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
1201 [ # # ]: 0 : if (r < 0)
1202 : 0 : return r;
1203 : :
1204 [ # # ]: 0 : while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
1205 : : const struct bus_properties_map *prop;
1206 : : const char *member;
1207 : : const char *contents;
1208 : : void *v;
1209 : : unsigned i;
1210 : :
1211 : 0 : r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
1212 [ # # ]: 0 : if (r < 0)
1213 : 0 : return r;
1214 : :
1215 [ # # ]: 0 : for (i = 0, prop = NULL; map[i].member; i++)
1216 [ # # ]: 0 : if (streq(map[i].member, member)) {
1217 : 0 : prop = &map[i];
1218 : 0 : break;
1219 : : }
1220 : :
1221 [ # # ]: 0 : if (prop) {
1222 : 0 : r = sd_bus_message_peek_type(m, NULL, &contents);
1223 [ # # ]: 0 : if (r < 0)
1224 : 0 : return r;
1225 : :
1226 : 0 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
1227 [ # # ]: 0 : if (r < 0)
1228 : 0 : return r;
1229 : :
1230 : 0 : v = (uint8_t *)userdata + prop->offset;
1231 [ # # ]: 0 : if (map[i].set)
1232 : 0 : r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
1233 : : else
1234 : 0 : r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
1235 [ # # ]: 0 : if (r < 0)
1236 : 0 : return r;
1237 : :
1238 : 0 : r = sd_bus_message_exit_container(m);
1239 [ # # ]: 0 : if (r < 0)
1240 : 0 : return r;
1241 : : } else {
1242 : 0 : r = sd_bus_message_skip(m, "v");
1243 [ # # ]: 0 : if (r < 0)
1244 : 0 : return r;
1245 : : }
1246 : :
1247 : 0 : r = sd_bus_message_exit_container(m);
1248 [ # # ]: 0 : if (r < 0)
1249 : 0 : return r;
1250 : : }
1251 [ # # ]: 0 : if (r < 0)
1252 : 0 : return r;
1253 : :
1254 : 0 : return sd_bus_message_exit_container(m);
1255 : : }
1256 : :
1257 : 0 : int bus_map_all_properties(
1258 : : sd_bus *bus,
1259 : : const char *destination,
1260 : : const char *path,
1261 : : const struct bus_properties_map *map,
1262 : : unsigned flags,
1263 : : sd_bus_error *error,
1264 : : sd_bus_message **reply,
1265 : : void *userdata) {
1266 : :
1267 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1268 : : int r;
1269 : :
1270 [ # # ]: 0 : assert(bus);
1271 [ # # ]: 0 : assert(destination);
1272 [ # # ]: 0 : assert(path);
1273 [ # # ]: 0 : assert(map);
1274 [ # # # # ]: 0 : assert(reply || (flags & BUS_MAP_STRDUP));
1275 : :
1276 : 0 : r = sd_bus_call_method(
1277 : : bus,
1278 : : destination,
1279 : : path,
1280 : : "org.freedesktop.DBus.Properties",
1281 : : "GetAll",
1282 : : error,
1283 : : &m,
1284 : : "s", "");
1285 [ # # ]: 0 : if (r < 0)
1286 : 0 : return r;
1287 : :
1288 : 0 : r = bus_message_map_all_properties(m, map, flags, error, userdata);
1289 [ # # ]: 0 : if (r < 0)
1290 : 0 : return r;
1291 : :
1292 [ # # ]: 0 : if (reply)
1293 : 0 : *reply = sd_bus_message_ref(m);
1294 : :
1295 : 0 : return r;
1296 : : }
1297 : :
1298 : 0 : int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
1299 : 0 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1300 : : int r;
1301 : :
1302 [ # # ]: 0 : assert(transport >= 0);
1303 [ # # ]: 0 : assert(transport < _BUS_TRANSPORT_MAX);
1304 [ # # ]: 0 : assert(ret);
1305 : :
1306 [ # # # # ]: 0 : assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1307 [ # # # # : 0 : assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
# # ]
1308 : :
1309 [ # # # # ]: 0 : switch (transport) {
1310 : :
1311 : 0 : case BUS_TRANSPORT_LOCAL:
1312 [ # # ]: 0 : if (user)
1313 : 0 : r = sd_bus_default_user(&bus);
1314 : : else {
1315 [ # # ]: 0 : if (sd_booted() <= 0) {
1316 : : /* Print a friendly message when the local system is actually not running systemd as PID 1. */
1317 [ # # ]: 0 : log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
1318 : :
1319 : 0 : return -EHOSTDOWN;
1320 : : }
1321 : 0 : r = sd_bus_default_system(&bus);
1322 : : }
1323 : 0 : break;
1324 : :
1325 : 0 : case BUS_TRANSPORT_REMOTE:
1326 : 0 : r = sd_bus_open_system_remote(&bus, host);
1327 : 0 : break;
1328 : :
1329 : 0 : case BUS_TRANSPORT_MACHINE:
1330 : 0 : r = sd_bus_open_system_machine(&bus, host);
1331 : 0 : break;
1332 : :
1333 : 0 : default:
1334 : 0 : assert_not_reached("Hmm, unknown transport type.");
1335 : : }
1336 [ # # ]: 0 : if (r < 0)
1337 : 0 : return r;
1338 : :
1339 : 0 : r = sd_bus_set_exit_on_disconnect(bus, true);
1340 [ # # ]: 0 : if (r < 0)
1341 : 0 : return r;
1342 : :
1343 : 0 : *ret = TAKE_PTR(bus);
1344 : :
1345 : 0 : return 0;
1346 : : }
1347 : :
1348 : 0 : int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
1349 : : int r;
1350 : :
1351 [ # # ]: 0 : assert(transport >= 0);
1352 [ # # ]: 0 : assert(transport < _BUS_TRANSPORT_MAX);
1353 [ # # ]: 0 : assert(bus);
1354 : :
1355 [ # # # # ]: 0 : assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
1356 [ # # # # : 0 : assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
# # ]
1357 : :
1358 [ # # # # ]: 0 : switch (transport) {
1359 : :
1360 : 0 : case BUS_TRANSPORT_LOCAL:
1361 [ # # ]: 0 : if (user)
1362 : 0 : r = bus_connect_user_systemd(bus);
1363 : : else {
1364 [ # # ]: 0 : if (sd_booted() <= 0)
1365 : : /* Print a friendly message when the local system is actually not running systemd as PID 1. */
1366 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
1367 : : "System has not been booted with systemd as init system (PID 1). Can't operate.");
1368 : 0 : r = bus_connect_system_systemd(bus);
1369 : : }
1370 : 0 : break;
1371 : :
1372 : 0 : case BUS_TRANSPORT_REMOTE:
1373 : 0 : r = sd_bus_open_system_remote(bus, host);
1374 : 0 : break;
1375 : :
1376 : 0 : case BUS_TRANSPORT_MACHINE:
1377 : 0 : r = sd_bus_open_system_machine(bus, host);
1378 : 0 : break;
1379 : :
1380 : 0 : default:
1381 : 0 : assert_not_reached("Hmm, unknown transport type.");
1382 : : }
1383 : :
1384 : 0 : return r;
1385 : : }
1386 : :
1387 : 0 : int bus_property_get_bool(
1388 : : sd_bus *bus,
1389 : : const char *path,
1390 : : const char *interface,
1391 : : const char *property,
1392 : : sd_bus_message *reply,
1393 : : void *userdata,
1394 : : sd_bus_error *error) {
1395 : :
1396 : 0 : int b = *(bool*) userdata;
1397 : :
1398 : 0 : return sd_bus_message_append_basic(reply, 'b', &b);
1399 : : }
1400 : :
1401 : 0 : int bus_property_set_bool(
1402 : : sd_bus *bus,
1403 : : const char *path,
1404 : : const char *interface,
1405 : : const char *property,
1406 : : sd_bus_message *value,
1407 : : void *userdata,
1408 : : sd_bus_error *error) {
1409 : :
1410 : : int b, r;
1411 : :
1412 : 0 : r = sd_bus_message_read(value, "b", &b);
1413 [ # # ]: 0 : if (r < 0)
1414 : 0 : return r;
1415 : :
1416 : 0 : *(bool*) userdata = b;
1417 : 0 : return 0;
1418 : : }
1419 : :
1420 : 0 : int bus_property_get_id128(
1421 : : sd_bus *bus,
1422 : : const char *path,
1423 : : const char *interface,
1424 : : const char *property,
1425 : : sd_bus_message *reply,
1426 : : void *userdata,
1427 : : sd_bus_error *error) {
1428 : :
1429 : 0 : sd_id128_t *id = userdata;
1430 : :
1431 [ # # ]: 0 : if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */
1432 : 0 : return sd_bus_message_append(reply, "ay", 0);
1433 : : else
1434 : 0 : return sd_bus_message_append_array(reply, 'y', id->bytes, 16);
1435 : : }
1436 : :
1437 : : #if __SIZEOF_SIZE_T__ != 8
1438 : : int bus_property_get_size(
1439 : : sd_bus *bus,
1440 : : const char *path,
1441 : : const char *interface,
1442 : : const char *property,
1443 : : sd_bus_message *reply,
1444 : : void *userdata,
1445 : : sd_bus_error *error) {
1446 : :
1447 : : uint64_t sz = *(size_t*) userdata;
1448 : :
1449 : : return sd_bus_message_append_basic(reply, 't', &sz);
1450 : : }
1451 : : #endif
1452 : :
1453 : : #if __SIZEOF_LONG__ != 8
1454 : : int bus_property_get_long(
1455 : : sd_bus *bus,
1456 : : const char *path,
1457 : : const char *interface,
1458 : : const char *property,
1459 : : sd_bus_message *reply,
1460 : : void *userdata,
1461 : : sd_bus_error *error) {
1462 : :
1463 : : int64_t l = *(long*) userdata;
1464 : :
1465 : : return sd_bus_message_append_basic(reply, 'x', &l);
1466 : : }
1467 : :
1468 : : int bus_property_get_ulong(
1469 : : sd_bus *bus,
1470 : : const char *path,
1471 : : const char *interface,
1472 : : const char *property,
1473 : : sd_bus_message *reply,
1474 : : void *userdata,
1475 : : sd_bus_error *error) {
1476 : :
1477 : : uint64_t ul = *(unsigned long*) userdata;
1478 : :
1479 : : return sd_bus_message_append_basic(reply, 't', &ul);
1480 : : }
1481 : : #endif
1482 : :
1483 : : /**
1484 : : * bus_path_encode_unique() - encode unique object path
1485 : : * @b: bus connection or NULL
1486 : : * @prefix: object path prefix
1487 : : * @sender_id: unique-name of client, or NULL
1488 : : * @external_id: external ID to be chosen by client, or NULL
1489 : : * @ret_path: storage for encoded object path pointer
1490 : : *
1491 : : * Whenever we provide a bus API that allows clients to create and manage
1492 : : * server-side objects, we need to provide a unique name for these objects. If
1493 : : * we let the server choose the name, we suffer from a race condition: If a
1494 : : * client creates an object asynchronously, it cannot destroy that object until
1495 : : * it received the method reply. It cannot know the name of the new object,
1496 : : * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
1497 : : *
1498 : : * Therefore, many APIs allow the client to choose the unique name for newly
1499 : : * created objects. There're two problems to solve, though:
1500 : : * 1) Object names are usually defined via dbus object paths, which are
1501 : : * usually globally namespaced. Therefore, multiple clients must be able
1502 : : * to choose unique object names without interference.
1503 : : * 2) If multiple libraries share the same bus connection, they must be
1504 : : * able to choose unique object names without interference.
1505 : : * The first problem is solved easily by prefixing a name with the
1506 : : * unique-bus-name of a connection. The server side must enforce this and
1507 : : * reject any other name. The second problem is solved by providing unique
1508 : : * suffixes from within sd-bus.
1509 : : *
1510 : : * This helper allows clients to create unique object-paths. It uses the
1511 : : * template '/prefix/sender_id/external_id' and returns the new path in
1512 : : * @ret_path (must be freed by the caller).
1513 : : * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
1514 : : * NULL, this function allocates a unique suffix via @b (by requesting a new
1515 : : * cookie). If both @sender_id and @external_id are given, @b can be passed as
1516 : : * NULL.
1517 : : *
1518 : : * Returns: 0 on success, negative error code on failure.
1519 : : */
1520 : 4 : int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1521 : 4 : _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1522 : : char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1523 : : int r;
1524 : :
1525 [ + - + - : 4 : assert_return(b || (sender_id && external_id), -EINVAL);
+ - - + -
+ ]
1526 [ - + - + ]: 4 : assert_return(object_path_is_valid(prefix), -EINVAL);
1527 [ - + - + ]: 4 : assert_return(ret_path, -EINVAL);
1528 : :
1529 [ - + ]: 4 : if (!sender_id) {
1530 : 0 : r = sd_bus_get_unique_name(b, &sender_id);
1531 [ # # ]: 0 : if (r < 0)
1532 : 0 : return r;
1533 : : }
1534 : :
1535 [ - + ]: 4 : if (!external_id) {
1536 [ # # ]: 0 : xsprintf(external_buf, "%"PRIu64, ++b->cookie);
1537 : 0 : external_id = external_buf;
1538 : : }
1539 : :
1540 : 4 : sender_label = bus_label_escape(sender_id);
1541 [ - + ]: 4 : if (!sender_label)
1542 : 0 : return -ENOMEM;
1543 : :
1544 : 4 : external_label = bus_label_escape(external_id);
1545 [ - + ]: 4 : if (!external_label)
1546 : 0 : return -ENOMEM;
1547 : :
1548 : 4 : p = path_join(prefix, sender_label, external_label);
1549 [ - + ]: 4 : if (!p)
1550 : 0 : return -ENOMEM;
1551 : :
1552 : 4 : *ret_path = p;
1553 : 4 : return 0;
1554 : : }
1555 : :
1556 : : /**
1557 : : * bus_path_decode_unique() - decode unique object path
1558 : : * @path: object path to decode
1559 : : * @prefix: object path prefix
1560 : : * @ret_sender: output parameter for sender-id label
1561 : : * @ret_external: output parameter for external-id label
1562 : : *
1563 : : * This does the reverse of bus_path_encode_unique() (see its description for
1564 : : * details). Both trailing labels, sender-id and external-id, are unescaped and
1565 : : * returned in the given output parameters (the caller must free them).
1566 : : *
1567 : : * Note that this function returns 0 if the path does not match the template
1568 : : * (see bus_path_encode_unique()), 1 if it matched.
1569 : : *
1570 : : * Returns: Negative error code on failure, 0 if the given object path does not
1571 : : * match the template (return parameters are set to NULL), 1 if it was
1572 : : * parsed successfully (return parameters contain allocated labels).
1573 : : */
1574 : 16 : int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
1575 : : const char *p, *q;
1576 : : char *sender, *external;
1577 : :
1578 [ - + ]: 16 : assert(object_path_is_valid(path));
1579 [ - + ]: 16 : assert(object_path_is_valid(prefix));
1580 [ - + ]: 16 : assert(ret_sender);
1581 [ - + ]: 16 : assert(ret_external);
1582 : :
1583 : 16 : p = object_path_startswith(path, prefix);
1584 [ + + ]: 16 : if (!p) {
1585 : 4 : *ret_sender = NULL;
1586 : 4 : *ret_external = NULL;
1587 : 4 : return 0;
1588 : : }
1589 : :
1590 : 12 : q = strchr(p, '/');
1591 [ + + ]: 12 : if (!q) {
1592 : 4 : *ret_sender = NULL;
1593 : 4 : *ret_external = NULL;
1594 : 4 : return 0;
1595 : : }
1596 : :
1597 : 8 : sender = bus_label_unescape_n(p, q - p);
1598 : 8 : external = bus_label_unescape(q + 1);
1599 [ + - - + ]: 8 : if (!sender || !external) {
1600 : 0 : free(sender);
1601 : 0 : free(external);
1602 : 0 : return -ENOMEM;
1603 : : }
1604 : :
1605 : 8 : *ret_sender = sender;
1606 : 8 : *ret_external = external;
1607 : 8 : return 1;
1608 : : }
1609 : :
1610 : 0 : int bus_property_get_rlimit(
1611 : : sd_bus *bus,
1612 : : const char *path,
1613 : : const char *interface,
1614 : : const char *property,
1615 : : sd_bus_message *reply,
1616 : : void *userdata,
1617 : : sd_bus_error *error) {
1618 : :
1619 : : const char *is_soft;
1620 : : struct rlimit *rl;
1621 : : uint64_t u;
1622 : : rlim_t x;
1623 : :
1624 [ # # ]: 0 : assert(bus);
1625 [ # # ]: 0 : assert(reply);
1626 [ # # ]: 0 : assert(userdata);
1627 : :
1628 : 0 : is_soft = endswith(property, "Soft");
1629 : :
1630 : 0 : rl = *(struct rlimit**) userdata;
1631 [ # # ]: 0 : if (rl)
1632 [ # # ]: 0 : x = is_soft ? rl->rlim_cur : rl->rlim_max;
1633 : : else {
1634 : 0 : struct rlimit buf = {};
1635 : : const char *s, *p;
1636 : : int z;
1637 : :
1638 : : /* Chop off "Soft" suffix */
1639 [ # # ]: 0 : s = is_soft ? strndupa(property, is_soft - property) : property;
1640 : :
1641 : : /* Skip over any prefix, such as "Default" */
1642 [ # # ]: 0 : assert_se(p = strstr(s, "Limit"));
1643 : :
1644 : 0 : z = rlimit_from_string(p + 5);
1645 [ # # ]: 0 : assert(z >= 0);
1646 : :
1647 : 0 : (void) getrlimit(z, &buf);
1648 [ # # ]: 0 : x = is_soft ? buf.rlim_cur : buf.rlim_max;
1649 : : }
1650 : :
1651 : : /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
1652 : : * archs */
1653 : 0 : u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
1654 : :
1655 : 0 : return sd_bus_message_append(reply, "t", u);
1656 : : }
1657 : :
1658 : 0 : int bus_track_add_name_many(sd_bus_track *t, char **l) {
1659 : 0 : int r = 0;
1660 : : char **i;
1661 : :
1662 [ # # ]: 0 : assert(t);
1663 : :
1664 : : /* Continues adding after failure, and returns the first failure. */
1665 : :
1666 [ # # # # ]: 0 : STRV_FOREACH(i, l) {
1667 : : int k;
1668 : :
1669 : 0 : k = sd_bus_track_add_name(t, *i);
1670 [ # # # # ]: 0 : if (k < 0 && r >= 0)
1671 : 0 : r = k;
1672 : : }
1673 : :
1674 : 0 : return r;
1675 : : }
1676 : :
1677 : 4 : int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
1678 : 4 : _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1679 : : const char *e;
1680 : : int r;
1681 : :
1682 [ - + ]: 4 : assert(ret);
1683 : :
1684 : : /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
1685 : :
1686 : 4 : r = sd_bus_new(&bus);
1687 [ - + ]: 4 : if (r < 0)
1688 : 0 : return r;
1689 : :
1690 [ + - ]: 4 : if (description) {
1691 : 4 : r = sd_bus_set_description(bus, description);
1692 [ - + ]: 4 : if (r < 0)
1693 : 0 : return r;
1694 : : }
1695 : :
1696 : 4 : e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
1697 [ + - ]: 4 : if (!e)
1698 : 4 : e = DEFAULT_SYSTEM_BUS_ADDRESS;
1699 : :
1700 : 4 : r = sd_bus_set_address(bus, e);
1701 [ - + ]: 4 : if (r < 0)
1702 : 0 : return r;
1703 : :
1704 : 4 : r = sd_bus_set_bus_client(bus, true);
1705 [ - + ]: 4 : if (r < 0)
1706 : 0 : return r;
1707 : :
1708 : 4 : r = sd_bus_set_trusted(bus, true);
1709 [ - + ]: 4 : if (r < 0)
1710 : 0 : return r;
1711 : :
1712 : 4 : r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
1713 [ - + ]: 4 : if (r < 0)
1714 : 0 : return r;
1715 : :
1716 : 4 : r = sd_bus_set_watch_bind(bus, true);
1717 [ - + ]: 4 : if (r < 0)
1718 : 0 : return r;
1719 : :
1720 : 4 : r = sd_bus_set_connected_signal(bus, true);
1721 [ - + ]: 4 : if (r < 0)
1722 : 0 : return r;
1723 : :
1724 : 4 : r = sd_bus_start(bus);
1725 [ - + ]: 4 : if (r < 0)
1726 : 0 : return r;
1727 : :
1728 : 4 : *ret = TAKE_PTR(bus);
1729 : :
1730 : 4 : return 0;
1731 : : }
1732 : :
1733 : 0 : int bus_reply_pair_array(sd_bus_message *m, char **l) {
1734 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1735 : : char **k, **v;
1736 : : int r;
1737 : :
1738 [ # # ]: 0 : assert(m);
1739 : :
1740 : : /* Reply to the specified message with a message containing a dictionary put together from the specified
1741 : : * strv */
1742 : :
1743 : 0 : r = sd_bus_message_new_method_return(m, &reply);
1744 [ # # ]: 0 : if (r < 0)
1745 : 0 : return r;
1746 : :
1747 : 0 : r = sd_bus_message_open_container(reply, 'a', "{ss}");
1748 [ # # ]: 0 : if (r < 0)
1749 : 0 : return r;
1750 : :
1751 [ # # # # : 0 : STRV_FOREACH_PAIR(k, v, l) {
# # ]
1752 : 0 : r = sd_bus_message_append(reply, "{ss}", *k, *v);
1753 [ # # ]: 0 : if (r < 0)
1754 : 0 : return r;
1755 : : }
1756 : :
1757 : 0 : r = sd_bus_message_close_container(reply);
1758 [ # # ]: 0 : if (r < 0)
1759 : 0 : return r;
1760 : :
1761 : 0 : return sd_bus_send(NULL, reply, NULL);
1762 : : }
1763 : :
1764 : 0 : static void bus_message_unref_wrapper(void *m) {
1765 : 0 : sd_bus_message_unref(m);
1766 : 0 : }
1767 : :
1768 : : const struct hash_ops bus_message_hash_ops = {
1769 : : .hash = trivial_hash_func,
1770 : : .compare = trivial_compare_func,
1771 : : .free_value = bus_message_unref_wrapper,
1772 : : };
|