chiark / gitweb /
bus: merge sd_bus_get_owner() and sd_bus_get_owner_creds() into one call
[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         r = sd_bus_call_method(
184                         bus,
185                         "org.freedesktop.DBus",
186                         "/",
187                         "org.freedesktop.DBus",
188                         "ListNames",
189                         NULL,
190                         &reply1,
191                         NULL);
192         if (r < 0)
193                 return r;
194
195         r = sd_bus_call_method(
196                         bus,
197                         "org.freedesktop.DBus",
198                         "/",
199                         "org.freedesktop.DBus",
200                         "ListActivatableNames",
201                         NULL,
202                         &reply2,
203                         NULL);
204         if (r < 0)
205                 return r;
206
207         r = bus_message_read_strv_extend(reply1, &x);
208         if (r < 0) {
209                 strv_free(x);
210                 return r;
211         }
212
213         r = bus_message_read_strv_extend(reply2, &x);
214         if (r < 0) {
215                 strv_free(x);
216                 return r;
217         }
218
219         *l = strv_uniq(x);
220         return 0;
221 }
222
223 _public_ int sd_bus_get_owner(
224                 sd_bus *bus,
225                 const char *name,
226                 uint64_t mask,
227                 char **owner,
228                 sd_bus_creds **creds) {
229
230         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
231         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
232         _cleanup_free_ char *unique = NULL;
233         pid_t pid = 0;
234         int r;
235
236         assert_return(bus, -EINVAL);
237         assert_return(name, -EINVAL);
238         assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
239         assert_return(mask == 0 || creds, -EINVAL);
240         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
241         assert_return(!bus_pid_changed(bus), -ECHILD);
242
243         /* Only query the owner if the caller wants to know it or if
244          * the caller just wants to check whether a name exists */
245         if (owner || mask == 0) {
246                 const char *found;
247
248                 r = sd_bus_call_method(
249                                 bus,
250                                 "org.freedesktop.DBus",
251                                 "/",
252                                 "org.freedesktop.DBus",
253                                 "GetNameOwner",
254                                 NULL,
255                                 &reply,
256                                 "s",
257                                 name);
258                 if (r < 0)
259                         return r;
260
261                 r = sd_bus_message_read(reply, "s", &found);
262                 if (r < 0)
263                         return r;
264
265                 unique = strdup(found);
266                 if (!unique)
267                         return -ENOMEM;
268
269                 reply = sd_bus_message_unref(reply);
270         }
271
272         if (mask != 0) {
273                 c = bus_creds_new();
274                 if (!c)
275                         return -ENOMEM;
276
277                 if ((mask & SD_BUS_CREDS_PID) ||
278                     mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) {
279                         uint32_t u;
280
281                         r = sd_bus_call_method(
282                                         bus,
283                                         "org.freedesktop.DBus",
284                                         "/",
285                                         "org.freedesktop.DBus",
286                                         "GetConnectionUnixProcessID",
287                                         NULL,
288                                         &reply,
289                                         "s",
290                                         name);
291                         if (r < 0)
292                                 return r;
293
294                         r = sd_bus_message_read(reply, "u", &u);
295                         if (r < 0)
296                                 return r;
297
298                         pid = u;
299                         if (mask & SD_BUS_CREDS_PID) {
300                                 c->pid = u;
301                                 c->mask |= SD_BUS_CREDS_PID;
302                         }
303
304                         reply = sd_bus_message_unref(reply);
305                 }
306
307                 if (mask & SD_BUS_CREDS_UID) {
308                         uint32_t u;
309
310                         r = sd_bus_call_method(
311                                         bus,
312                                         "org.freedesktop.DBus",
313                                         "/",
314                                         "org.freedesktop.DBus",
315                                         "GetConnectionUnixUser",
316                                         NULL,
317                                         &reply,
318                                         "s",
319                                         name);
320                         if (r < 0)
321                                 return r;
322
323                         r = sd_bus_message_read(reply, "u", &u);
324                         if (r < 0)
325                                 return r;
326
327                         c->uid = u;
328                         c->mask |= SD_BUS_CREDS_UID;
329
330                         reply = sd_bus_message_unref(reply);
331                 }
332
333                 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
334                         const void *p;
335                         size_t sz;
336
337                         r = sd_bus_call_method(
338                                         bus,
339                                         "org.freedesktop.DBus",
340                                         "/",
341                                         "org.freedesktop.DBus",
342                                         "GetConnectionSELinuxSecurityContext",
343                                         NULL,
344                                         &reply,
345                                         "s",
346                                         name);
347                         if (r < 0)
348                                 return r;
349
350                         r = sd_bus_message_read_array(reply, 'y', &p, &sz);
351                         if (r < 0)
352                                 return r;
353
354                         c->label = strndup(p, sz);
355                         if (!c->label)
356                                 return -ENOMEM;
357
358                         c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
359                 }
360
361                 r = bus_creds_add_more(c, mask, pid, 0);
362                 if (r < 0)
363                         return r;
364         }
365
366         if (creds) {
367                 *creds = c;
368                 c = NULL;
369         }
370
371         if (owner) {
372                 *owner = unique;
373                 unique = NULL;
374         }
375
376         return 0;
377 }
378
379 int bus_add_match_internal(
380                 sd_bus *bus,
381                 const char *match,
382                 struct bus_match_component *components,
383                 unsigned n_components,
384                 uint64_t cookie) {
385
386         int r;
387
388         assert(bus);
389         assert(match);
390
391         if (bus->is_kernel) {
392                 struct kdbus_cmd_match *m;
393                 struct kdbus_item *item;
394                 uint64_t bloom[BLOOM_SIZE/8];
395                 size_t sz;
396                 const char *sender = NULL;
397                 size_t sender_length = 0;
398                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
399                 bool using_bloom = false;
400                 unsigned i;
401
402                 zero(bloom);
403
404                 sz = offsetof(struct kdbus_cmd_match, items);
405
406                 for (i = 0; i < n_components; i++) {
407                         struct bus_match_component *c = &components[i];
408
409                         switch (c->type) {
410
411                         case BUS_MATCH_SENDER:
412                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
413                                 if (r < 0)
414                                         return r;
415
416                                 if (r > 0) {
417                                         sender = c->value_str;
418                                         sender_length = strlen(sender);
419                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
420                                 }
421
422                                 break;
423
424                         case BUS_MATCH_MESSAGE_TYPE:
425                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
426                                 using_bloom = true;
427                                 break;
428
429                         case BUS_MATCH_INTERFACE:
430                                 bloom_add_pair(bloom, "interface", c->value_str);
431                                 using_bloom = true;
432                                 break;
433
434                         case BUS_MATCH_MEMBER:
435                                 bloom_add_pair(bloom, "member", c->value_str);
436                                 using_bloom = true;
437                                 break;
438
439                         case BUS_MATCH_PATH:
440                                 bloom_add_pair(bloom, "path", c->value_str);
441                                 using_bloom = true;
442                                 break;
443
444                         case BUS_MATCH_PATH_NAMESPACE:
445                                 if (!streq(c->value_str, "/")) {
446                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
447                                         using_bloom = true;
448                                 }
449                                 break;
450
451                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
452                                 char buf[sizeof("arg")-1 + 2 + 1];
453
454                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
455                                 bloom_add_pair(bloom, buf, c->value_str);
456                                 using_bloom = true;
457                                 break;
458                         }
459
460                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
461                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
462
463                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
464                                 bloom_add_pair(bloom, buf, c->value_str);
465                                 using_bloom = true;
466                                 break;
467                         }
468
469                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
470                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
471
472                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
473                                 bloom_add_pair(bloom, buf, c->value_str);
474                                 using_bloom = true;
475                                 break;
476                         }
477
478                         case BUS_MATCH_DESTINATION:
479                                 /* The bloom filter does not include
480                                    the destination, since it is only
481                                    available for broadcast messages
482                                    which do not carry a destination
483                                    since they are undirected. */
484                                 break;
485
486                         case BUS_MATCH_ROOT:
487                         case BUS_MATCH_VALUE:
488                         case BUS_MATCH_LEAF:
489                         case _BUS_MATCH_NODE_TYPE_MAX:
490                         case _BUS_MATCH_NODE_TYPE_INVALID:
491                                 assert_not_reached("Invalid match type?");
492                         }
493                 }
494
495                 if (using_bloom)
496                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
497
498                 m = alloca0(sz);
499                 m->size = sz;
500                 m->cookie = cookie;
501                 m->src_id = src_id;
502
503                 item = m->items;
504
505                 if (using_bloom) {
506                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
507                         item->type = KDBUS_MATCH_BLOOM;
508                         memcpy(item->data64, bloom, BLOOM_SIZE);
509
510                         item = KDBUS_ITEM_NEXT(item);
511                 }
512
513                 if (sender) {
514                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
515                         item->type = KDBUS_MATCH_SRC_NAME;
516                         memcpy(item->str, sender, sender_length + 1);
517                 }
518
519                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
520                 if (r < 0)
521                         return -errno;
522
523         } else {
524                 return sd_bus_call_method(
525                                 bus,
526                                 "org.freedesktop.DBus",
527                                 "/",
528                                 "org.freedesktop.DBus",
529                                 "AddMatch",
530                                 NULL,
531                                 NULL,
532                                 "s",
533                                 match);
534         }
535
536         return 0;
537 }
538
539 int bus_remove_match_internal(
540                 sd_bus *bus,
541                 const char *match,
542                 uint64_t cookie) {
543
544         int r;
545
546         assert(bus);
547         assert(match);
548
549         if (bus->is_kernel) {
550                 struct kdbus_cmd_match m;
551
552                 zero(m);
553                 m.size = offsetof(struct kdbus_cmd_match, items);
554                 m.cookie = cookie;
555
556                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
557                 if (r < 0)
558                         return -errno;
559
560         } else {
561                 return sd_bus_call_method(
562                                 bus,
563                                 "org.freedesktop.DBus",
564                                 "/",
565                                 "org.freedesktop.DBus",
566                                 "RemoveMatch",
567                                 NULL,
568                                 NULL,
569                                 "s",
570                                 match);
571         }
572
573         return 0;
574 }
575
576 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
577         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
578         const char *mid;
579         int r;
580
581         assert_return(bus, -EINVAL);
582         assert_return(name, -EINVAL);
583         assert_return(machine, -EINVAL);
584         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
585         assert_return(!bus_pid_changed(bus), -ECHILD);
586
587         if (streq_ptr(name, bus->unique_name))
588                 return sd_id128_get_machine(machine);
589
590         r = sd_bus_message_new_method_call(
591                         bus,
592                         name,
593                         "/",
594                         "org.freedesktop.DBus.Peer",
595                         "GetMachineId", &m);
596         if (r < 0)
597                 return r;
598
599         r = sd_bus_message_set_no_auto_start(m, true);
600         if (r < 0)
601                 return r;
602
603         r = sd_bus_call(bus, m, 0, NULL, &reply);
604         if (r < 0)
605                 return r;
606
607         r = sd_bus_message_read(reply, "s", &mid);
608         if (r < 0)
609                 return r;
610
611         return sd_id128_from_string(mid, machine);
612 }