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