chiark / gitweb /
b222175148222db02ec504d2e4d2a1ed91d576fd
[elogind.git] / src / libsystemd-bus / bus-control.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <stddef.h>
27 #include <errno.h>
28
29 #include "strv.h"
30
31 #include "sd-bus.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35 #include "bus-bloom.h"
36 #include "bus-util.h"
37
38 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
39         int r;
40
41         if (!bus)
42                 return -EINVAL;
43         if (!unique)
44                 return -EINVAL;
45         if (bus_pid_changed(bus))
46                 return -ECHILD;
47
48         r = bus_ensure_running(bus);
49         if (r < 0)
50                 return r;
51
52         *unique = bus->unique_name;
53         return 0;
54 }
55
56 _public_ int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
57         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
58         uint32_t ret;
59         int r;
60
61         if (!bus)
62                 return -EINVAL;
63         if (!name)
64                 return -EINVAL;
65         if (!bus->bus_client)
66                 return -EINVAL;
67         if (!BUS_IS_OPEN(bus->state))
68                 return -ENOTCONN;
69         if (bus_pid_changed(bus))
70                 return -ECHILD;
71
72         if (bus->is_kernel) {
73                 struct kdbus_cmd_name *n;
74                 size_t l;
75
76                 l = strlen(name);
77                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
78                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
79                 n->flags = flags;
80                 memcpy(n->name, name, l+1);
81
82 #ifdef HAVE_VALGRIND_MEMCHECK_H
83                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
84 #endif
85
86                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
87                 if (r < 0) {
88                         if (errno == -EALREADY)
89                                 return SD_BUS_NAME_ALREADY_OWNER;
90
91                         if (errno == -EEXIST)
92                                 return SD_BUS_NAME_EXISTS;
93
94                         return -errno;
95                 }
96
97                 if (n->flags & KDBUS_NAME_IN_QUEUE)
98                         return SD_BUS_NAME_IN_QUEUE;
99
100                 return SD_BUS_NAME_PRIMARY_OWNER;
101         } else {
102                 r = sd_bus_call_method(
103                                 bus,
104                                 "org.freedesktop.DBus",
105                                 "/",
106                                 "org.freedesktop.DBus",
107                                 "RequestName",
108                                 NULL,
109                                 &reply,
110                                 "su",
111                                 name,
112                                 flags);
113                 if (r < 0)
114                         return r;
115
116                 r = sd_bus_message_read(reply, "u", &ret);
117                 if (r < 0)
118                         return r;
119
120                 return ret;
121         }
122 }
123
124 _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
125         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
126         uint32_t ret;
127         int r;
128
129         if (!bus)
130                 return -EINVAL;
131         if (!name)
132                 return -EINVAL;
133         if (!bus->bus_client)
134                 return -EINVAL;
135         if (!BUS_IS_OPEN(bus->state))
136                 return -ENOTCONN;
137         if (bus_pid_changed(bus))
138                 return -ECHILD;
139
140         if (bus->is_kernel) {
141                 struct kdbus_cmd_name *n;
142                 size_t l;
143
144                 l = strlen(name);
145                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
146                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
147                 memcpy(n->name, name, l+1);
148
149 #ifdef HAVE_VALGRIND_MEMCHECK_H
150                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
151 #endif
152                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
153                 if (r < 0)
154                         return -errno;
155
156                 return n->flags;
157         } else {
158                 r = sd_bus_call_method(
159                                 bus,
160                                 "org.freedesktop.DBus",
161                                 "/",
162                                 "org.freedesktop.DBus",
163                                 "ReleaseName",
164                                 NULL,
165                                 &reply,
166                                 "s",
167                                 name);
168                 if (r < 0)
169                         return r;
170
171                 r = sd_bus_message_read(reply, "u", &ret);
172                 if (r < 0)
173                         return r;
174         }
175
176         return ret;
177 }
178
179 _public_ int sd_bus_list_names(sd_bus *bus, char ***l) {
180         _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
181         char **x = NULL;
182         int r;
183
184         if (!bus)
185                 return -EINVAL;
186         if (!l)
187                 return -EINVAL;
188         if (!BUS_IS_OPEN(bus->state))
189                 return -ENOTCONN;
190         if (bus_pid_changed(bus))
191                 return -ECHILD;
192
193         if (bus->is_kernel) {
194                 _cleanup_free_ struct kdbus_cmd_names *names = NULL;
195                 struct kdbus_cmd_name *name;
196                 size_t size;
197
198                 /* assume 8k size first. If that doesn't suffice, kdbus will tell us
199                  * how big the buffer needs to be.  */
200                 size = 8192;
201
202                 for(;;) {
203                         names = realloc(names, size);
204                         if (!names)
205                                 return -ENOMEM;
206
207                         names->size = size;
208                         names->flags = KDBUS_NAME_LIST_UNIQUE_NAMES;
209
210                         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_LIST, names);
211                         if (r < 0) {
212                                 if (errno == ENOBUFS && size != names->size) {
213                                         size = names->size;
214                                         continue;
215                                 }
216
217                                 return -errno;
218                         }
219
220                         break;
221                 }
222
223                 KDBUS_PART_FOREACH(name, names, names) {
224                         char *n;
225
226                         if (name->size > sizeof(*name))
227                                 n = name->name;
228                         else
229                                 asprintf(&n, ":1.%llu", (unsigned long long) name->id);
230
231                         r = strv_extend(&x, n);
232                         if (r < 0)
233                                 return -ENOMEM;
234                 }
235
236                 *l = x;
237         } else {
238                 r = sd_bus_call_method(
239                                 bus,
240                                 "org.freedesktop.DBus",
241                                 "/",
242                                 "org.freedesktop.DBus",
243                                 "ListNames",
244                                 NULL,
245                                 &reply1,
246                                 NULL);
247                 if (r < 0)
248                         return r;
249
250                 r = sd_bus_call_method(
251                                 bus,
252                                 "org.freedesktop.DBus",
253                                 "/",
254                                 "org.freedesktop.DBus",
255                                 "ListActivatableNames",
256                                 NULL,
257                                 &reply2,
258                                 NULL);
259                 if (r < 0)
260                         return r;
261
262                 r = bus_message_read_strv_extend(reply1, &x);
263                 if (r < 0) {
264                         strv_free(x);
265                         return r;
266                 }
267
268                 r = bus_message_read_strv_extend(reply2, &x);
269                 if (r < 0) {
270                         strv_free(x);
271                         return r;
272                 }
273
274                 *l = strv_uniq(x);
275         }
276
277         return 0;
278 }
279
280 _public_ int sd_bus_get_owner(
281                 sd_bus *bus,
282                 const char *name,
283                 uint64_t mask,
284                 char **owner,
285                 sd_bus_creds **creds) {
286
287         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
288         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
289         _cleanup_free_ char *unique = NULL;
290         pid_t pid = 0;
291         int r;
292
293         assert_return(bus, -EINVAL);
294         assert_return(name, -EINVAL);
295         assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
296         assert_return(mask == 0 || creds, -EINVAL);
297         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
298         assert_return(!bus_pid_changed(bus), -ECHILD);
299
300         /* Only query the owner if the caller wants to know it or if
301          * the caller just wants to check whether a name exists */
302         if (owner || mask == 0) {
303                 const char *found;
304
305                 r = sd_bus_call_method(
306                                 bus,
307                                 "org.freedesktop.DBus",
308                                 "/",
309                                 "org.freedesktop.DBus",
310                                 "GetNameOwner",
311                                 NULL,
312                                 &reply,
313                                 "s",
314                                 name);
315                 if (r < 0)
316                         return r;
317
318                 r = sd_bus_message_read(reply, "s", &found);
319                 if (r < 0)
320                         return r;
321
322                 unique = strdup(found);
323                 if (!unique)
324                         return -ENOMEM;
325
326                 reply = sd_bus_message_unref(reply);
327         }
328
329         if (mask != 0) {
330                 c = bus_creds_new();
331                 if (!c)
332                         return -ENOMEM;
333
334                 if ((mask & SD_BUS_CREDS_PID) ||
335                     mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
336                         uint32_t u;
337
338                         r = sd_bus_call_method(
339                                         bus,
340                                         "org.freedesktop.DBus",
341                                         "/",
342                                         "org.freedesktop.DBus",
343                                         "GetConnectionUnixProcessID",
344                                         NULL,
345                                         &reply,
346                                         "s",
347                                         name);
348                         if (r < 0)
349                                 return r;
350
351                         r = sd_bus_message_read(reply, "u", &u);
352                         if (r < 0)
353                                 return r;
354
355                         pid = u;
356                         if (mask & SD_BUS_CREDS_PID) {
357                                 c->pid = u;
358                                 c->mask |= SD_BUS_CREDS_PID;
359                         }
360
361                         reply = sd_bus_message_unref(reply);
362                 }
363
364                 if (mask & SD_BUS_CREDS_UID) {
365                         uint32_t u;
366
367                         r = sd_bus_call_method(
368                                         bus,
369                                         "org.freedesktop.DBus",
370                                         "/",
371                                         "org.freedesktop.DBus",
372                                         "GetConnectionUnixUser",
373                                         NULL,
374                                         &reply,
375                                         "s",
376                                         name);
377                         if (r < 0)
378                                 return r;
379
380                         r = sd_bus_message_read(reply, "u", &u);
381                         if (r < 0)
382                                 return r;
383
384                         c->uid = u;
385                         c->mask |= SD_BUS_CREDS_UID;
386
387                         reply = sd_bus_message_unref(reply);
388                 }
389
390                 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
391                         const void *p;
392                         size_t sz;
393
394                         r = sd_bus_call_method(
395                                         bus,
396                                         "org.freedesktop.DBus",
397                                         "/",
398                                         "org.freedesktop.DBus",
399                                         "GetConnectionSELinuxSecurityContext",
400                                         NULL,
401                                         &reply,
402                                         "s",
403                                         name);
404                         if (r < 0)
405                                 return r;
406
407                         r = sd_bus_message_read_array(reply, 'y', &p, &sz);
408                         if (r < 0)
409                                 return r;
410
411                         c->label = strndup(p, sz);
412                         if (!c->label)
413                                 return -ENOMEM;
414
415                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
416                 }
417
418                 r = bus_creds_add_more(c, mask, pid, 0);
419                 if (r < 0)
420                         return r;
421         }
422
423         if (creds) {
424                 *creds = c;
425                 c = NULL;
426         }
427
428         if (owner) {
429                 *owner = unique;
430                 unique = NULL;
431         }
432
433         return 0;
434 }
435
436 int bus_add_match_internal(
437                 sd_bus *bus,
438                 const char *match,
439                 struct bus_match_component *components,
440                 unsigned n_components,
441                 uint64_t cookie) {
442
443         int r;
444
445         assert(bus);
446         assert(match);
447
448         if (bus->is_kernel) {
449                 struct kdbus_cmd_match *m;
450                 struct kdbus_item *item;
451                 uint64_t bloom[BLOOM_SIZE/8];
452                 size_t sz;
453                 const char *sender = NULL;
454                 size_t sender_length = 0;
455                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
456                 bool using_bloom = false;
457                 unsigned i;
458
459                 zero(bloom);
460
461                 sz = offsetof(struct kdbus_cmd_match, items);
462
463                 for (i = 0; i < n_components; i++) {
464                         struct bus_match_component *c = &components[i];
465
466                         switch (c->type) {
467
468                         case BUS_MATCH_SENDER:
469                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
470                                 if (r < 0)
471                                         return r;
472
473                                 if (r > 0) {
474                                         sender = c->value_str;
475                                         sender_length = strlen(sender);
476                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
477                                 }
478
479                                 break;
480
481                         case BUS_MATCH_MESSAGE_TYPE:
482                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
483                                 using_bloom = true;
484                                 break;
485
486                         case BUS_MATCH_INTERFACE:
487                                 bloom_add_pair(bloom, "interface", c->value_str);
488                                 using_bloom = true;
489                                 break;
490
491                         case BUS_MATCH_MEMBER:
492                                 bloom_add_pair(bloom, "member", c->value_str);
493                                 using_bloom = true;
494                                 break;
495
496                         case BUS_MATCH_PATH:
497                                 bloom_add_pair(bloom, "path", c->value_str);
498                                 using_bloom = true;
499                                 break;
500
501                         case BUS_MATCH_PATH_NAMESPACE:
502                                 if (!streq(c->value_str, "/")) {
503                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
504                                         using_bloom = true;
505                                 }
506                                 break;
507
508                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
509                                 char buf[sizeof("arg")-1 + 2 + 1];
510
511                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
512                                 bloom_add_pair(bloom, buf, c->value_str);
513                                 using_bloom = true;
514                                 break;
515                         }
516
517                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
518                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
519
520                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
521                                 bloom_add_pair(bloom, buf, c->value_str);
522                                 using_bloom = true;
523                                 break;
524                         }
525
526                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
527                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
528
529                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
530                                 bloom_add_pair(bloom, buf, c->value_str);
531                                 using_bloom = true;
532                                 break;
533                         }
534
535                         case BUS_MATCH_DESTINATION:
536                                 /* The bloom filter does not include
537                                    the destination, since it is only
538                                    available for broadcast messages
539                                    which do not carry a destination
540                                    since they are undirected. */
541                                 break;
542
543                         case BUS_MATCH_ROOT:
544                         case BUS_MATCH_VALUE:
545                         case BUS_MATCH_LEAF:
546                         case _BUS_MATCH_NODE_TYPE_MAX:
547                         case _BUS_MATCH_NODE_TYPE_INVALID:
548                                 assert_not_reached("Invalid match type?");
549                         }
550                 }
551
552                 if (using_bloom)
553                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
554
555                 m = alloca0(sz);
556                 m->size = sz;
557                 m->cookie = cookie;
558                 m->src_id = src_id;
559
560                 item = m->items;
561
562                 if (using_bloom) {
563                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
564                         item->type = KDBUS_MATCH_BLOOM;
565                         memcpy(item->data64, bloom, BLOOM_SIZE);
566
567                         item = KDBUS_PART_NEXT(item);
568                 }
569
570                 if (sender) {
571                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
572                         item->type = KDBUS_MATCH_SRC_NAME;
573                         memcpy(item->str, sender, sender_length + 1);
574                 }
575
576                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
577                 if (r < 0)
578                         return -errno;
579
580         } else {
581                 return sd_bus_call_method(
582                                 bus,
583                                 "org.freedesktop.DBus",
584                                 "/",
585                                 "org.freedesktop.DBus",
586                                 "AddMatch",
587                                 NULL,
588                                 NULL,
589                                 "s",
590                                 match);
591         }
592
593         return 0;
594 }
595
596 int bus_remove_match_internal(
597                 sd_bus *bus,
598                 const char *match,
599                 uint64_t cookie) {
600
601         int r;
602
603         assert(bus);
604         assert(match);
605
606         if (bus->is_kernel) {
607                 struct kdbus_cmd_match m;
608
609                 zero(m);
610                 m.size = offsetof(struct kdbus_cmd_match, items);
611                 m.cookie = cookie;
612
613                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
614                 if (r < 0)
615                         return -errno;
616
617         } else {
618                 return sd_bus_call_method(
619                                 bus,
620                                 "org.freedesktop.DBus",
621                                 "/",
622                                 "org.freedesktop.DBus",
623                                 "RemoveMatch",
624                                 NULL,
625                                 NULL,
626                                 "s",
627                                 match);
628         }
629
630         return 0;
631 }
632
633 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
634         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
635         const char *mid;
636         int r;
637
638         assert_return(bus, -EINVAL);
639         assert_return(name, -EINVAL);
640         assert_return(machine, -EINVAL);
641         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
642         assert_return(!bus_pid_changed(bus), -ECHILD);
643
644         if (streq_ptr(name, bus->unique_name))
645                 return sd_id128_get_machine(machine);
646
647         r = sd_bus_message_new_method_call(
648                         bus,
649                         name,
650                         "/",
651                         "org.freedesktop.DBus.Peer",
652                         "GetMachineId", &m);
653         if (r < 0)
654                 return r;
655
656         r = sd_bus_message_set_no_auto_start(m, true);
657         if (r < 0)
658                 return r;
659
660         r = sd_bus_call(bus, m, 0, NULL, &reply);
661         if (r < 0)
662                 return r;
663
664         r = sd_bus_message_read(reply, "s", &mid);
665         if (r < 0)
666                 return r;
667
668         return sd_id128_from_string(mid, machine);
669 }