LCOV - code coverage report
Current view: top level - shared - bus-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 66 865 7.6 %
Date: 2019-08-22 15:41:25 Functions: 4 34 11.8 %

          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          17 : void bus_verify_polkit_async_registry_free(Hashmap *registry) {
     537             : #if ENABLE_POLKIT
     538          17 :         hashmap_free_with_destructor(registry, async_polkit_query_free);
     539             : #endif
     540          17 : }
     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           1 : int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
    1521           1 :         _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
    1522             :         char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
    1523             :         int r;
    1524             : 
    1525           1 :         assert_return(b || (sender_id && external_id), -EINVAL);
    1526           1 :         assert_return(object_path_is_valid(prefix), -EINVAL);
    1527           1 :         assert_return(ret_path, -EINVAL);
    1528             : 
    1529           1 :         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           1 :         if (!external_id) {
    1536           0 :                 xsprintf(external_buf, "%"PRIu64, ++b->cookie);
    1537           0 :                 external_id = external_buf;
    1538             :         }
    1539             : 
    1540           1 :         sender_label = bus_label_escape(sender_id);
    1541           1 :         if (!sender_label)
    1542           0 :                 return -ENOMEM;
    1543             : 
    1544           1 :         external_label = bus_label_escape(external_id);
    1545           1 :         if (!external_label)
    1546           0 :                 return -ENOMEM;
    1547             : 
    1548           1 :         p = path_join(prefix, sender_label, external_label);
    1549           1 :         if (!p)
    1550           0 :                 return -ENOMEM;
    1551             : 
    1552           1 :         *ret_path = p;
    1553           1 :         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           4 : 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           4 :         assert(object_path_is_valid(path));
    1579           4 :         assert(object_path_is_valid(prefix));
    1580           4 :         assert(ret_sender);
    1581           4 :         assert(ret_external);
    1582             : 
    1583           4 :         p = object_path_startswith(path, prefix);
    1584           4 :         if (!p) {
    1585           1 :                 *ret_sender = NULL;
    1586           1 :                 *ret_external = NULL;
    1587           1 :                 return 0;
    1588             :         }
    1589             : 
    1590           3 :         q = strchr(p, '/');
    1591           3 :         if (!q) {
    1592           1 :                 *ret_sender = NULL;
    1593           1 :                 *ret_external = NULL;
    1594           1 :                 return 0;
    1595             :         }
    1596             : 
    1597           2 :         sender = bus_label_unescape_n(p, q - p);
    1598           2 :         external = bus_label_unescape(q + 1);
    1599           2 :         if (!sender || !external) {
    1600           0 :                 free(sender);
    1601           0 :                 free(external);
    1602           0 :                 return -ENOMEM;
    1603             :         }
    1604             : 
    1605           2 :         *ret_sender = sender;
    1606           2 :         *ret_external = external;
    1607           2 :         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           1 : int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
    1678           1 :         _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
    1679             :         const char *e;
    1680             :         int r;
    1681             : 
    1682           1 :         assert(ret);
    1683             : 
    1684             :         /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal turned on. */
    1685             : 
    1686           1 :         r = sd_bus_new(&bus);
    1687           1 :         if (r < 0)
    1688           0 :                 return r;
    1689             : 
    1690           1 :         if (description) {
    1691           1 :                 r = sd_bus_set_description(bus, description);
    1692           1 :                 if (r < 0)
    1693           0 :                         return r;
    1694             :         }
    1695             : 
    1696           1 :         e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
    1697           1 :         if (!e)
    1698           1 :                 e = DEFAULT_SYSTEM_BUS_ADDRESS;
    1699             : 
    1700           1 :         r = sd_bus_set_address(bus, e);
    1701           1 :         if (r < 0)
    1702           0 :                 return r;
    1703             : 
    1704           1 :         r = sd_bus_set_bus_client(bus, true);
    1705           1 :         if (r < 0)
    1706           0 :                 return r;
    1707             : 
    1708           1 :         r = sd_bus_set_trusted(bus, true);
    1709           1 :         if (r < 0)
    1710           0 :                 return r;
    1711             : 
    1712           1 :         r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
    1713           1 :         if (r < 0)
    1714           0 :                 return r;
    1715             : 
    1716           1 :         r = sd_bus_set_watch_bind(bus, true);
    1717           1 :         if (r < 0)
    1718           0 :                 return r;
    1719             : 
    1720           1 :         r = sd_bus_set_connected_signal(bus, true);
    1721           1 :         if (r < 0)
    1722           0 :                 return r;
    1723             : 
    1724           1 :         r = sd_bus_start(bus);
    1725           1 :         if (r < 0)
    1726           0 :                 return r;
    1727             : 
    1728           1 :         *ret = TAKE_PTR(bus);
    1729             : 
    1730           1 :         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             : };

Generated by: LCOV version 1.14