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