chiark / gitweb /
bus: set no_auto_start flag for GetMachineId calls, so that we don't auto-start if...
[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(sd_bus *bus, const char *name, char **owner) {
224         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
225         const char *found;
226         int r;
227
228         assert_return(bus, -EINVAL);
229         assert_return(name, -EINVAL);
230         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
231         assert_return(!bus_pid_changed(bus), -ECHILD);
232
233         r = sd_bus_call_method(
234                         bus,
235                         "org.freedesktop.DBus",
236                         "/",
237                         "org.freedesktop.DBus",
238                         "GetNameOwner",
239                         NULL,
240                         &reply,
241                         "s",
242                         name);
243         if (r < 0)
244                 return r;
245
246         r = sd_bus_message_read(reply, "s", &found);
247         if (r < 0)
248                 return r;
249
250         if (owner) {
251                 char *t;
252
253                 t = strdup(found);
254                 if (!t)
255                         return -ENOMEM;
256
257                 *owner = t;
258         }
259
260         return 0;
261 }
262
263 _public_ int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
264         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
265         uint32_t u;
266         int r;
267
268         if (!bus)
269                 return -EINVAL;
270         if (!name)
271                 return -EINVAL;
272         if (!uid)
273                 return -EINVAL;
274         if (!BUS_IS_OPEN(bus->state))
275                 return -ENOTCONN;
276         if (bus_pid_changed(bus))
277                 return -ECHILD;
278
279         r = sd_bus_call_method(
280                         bus,
281                         "org.freedesktop.DBus",
282                         "/",
283                         "org.freedesktop.DBus",
284                         "GetConnectionUnixUser",
285                         NULL,
286                         &reply,
287                         "s",
288                         name);
289         if (r < 0)
290                 return r;
291
292         r = sd_bus_message_read(reply, "u", &u);
293         if (r < 0)
294                 return r;
295
296         *uid = (uid_t) u;
297         return 0;
298 }
299
300 _public_ int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
301         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
302         uint32_t u;
303         int r;
304
305         if (!bus)
306                 return -EINVAL;
307         if (!name)
308                 return -EINVAL;
309         if (!pid)
310                 return -EINVAL;
311         if (!BUS_IS_OPEN(bus->state))
312                 return -ENOTCONN;
313         if (bus_pid_changed(bus))
314                 return -ECHILD;
315
316         r = sd_bus_call_method(
317                         bus,
318                         "org.freedesktop.DBus",
319                         "/",
320                         "org.freedesktop.DBus",
321                         "GetConnectionUnixProcessID",
322                         NULL,
323                         &reply,
324                         "s",
325                         name);
326         if (r < 0)
327                 return r;
328
329         r = sd_bus_message_read(reply, "u", &u);
330         if (r < 0)
331                 return r;
332
333         if (u == 0)
334                 return -EIO;
335
336         *pid = (uid_t) u;
337         return 0;
338 }
339
340 int bus_add_match_internal(
341                 sd_bus *bus,
342                 const char *match,
343                 struct bus_match_component *components,
344                 unsigned n_components,
345                 uint64_t cookie) {
346
347         int r;
348
349         assert(bus);
350         assert(match);
351
352         if (bus->is_kernel) {
353                 struct kdbus_cmd_match *m;
354                 struct kdbus_item *item;
355                 uint64_t bloom[BLOOM_SIZE/8];
356                 size_t sz;
357                 const char *sender = NULL;
358                 size_t sender_length = 0;
359                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
360                 bool using_bloom = false;
361                 unsigned i;
362
363                 zero(bloom);
364
365                 sz = offsetof(struct kdbus_cmd_match, items);
366
367                 for (i = 0; i < n_components; i++) {
368                         struct bus_match_component *c = &components[i];
369
370                         switch (c->type) {
371
372                         case BUS_MATCH_SENDER:
373                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
374                                 if (r < 0)
375                                         return r;
376
377                                 if (r > 0) {
378                                         sender = c->value_str;
379                                         sender_length = strlen(sender);
380                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
381                                 }
382
383                                 break;
384
385                         case BUS_MATCH_MESSAGE_TYPE:
386                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
387                                 using_bloom = true;
388                                 break;
389
390                         case BUS_MATCH_INTERFACE:
391                                 bloom_add_pair(bloom, "interface", c->value_str);
392                                 using_bloom = true;
393                                 break;
394
395                         case BUS_MATCH_MEMBER:
396                                 bloom_add_pair(bloom, "member", c->value_str);
397                                 using_bloom = true;
398                                 break;
399
400                         case BUS_MATCH_PATH:
401                                 bloom_add_pair(bloom, "path", c->value_str);
402                                 using_bloom = true;
403                                 break;
404
405                         case BUS_MATCH_PATH_NAMESPACE:
406                                 if (!streq(c->value_str, "/")) {
407                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
408                                         using_bloom = true;
409                                 }
410                                 break;
411
412                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
413                                 char buf[sizeof("arg")-1 + 2 + 1];
414
415                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
416                                 bloom_add_pair(bloom, buf, c->value_str);
417                                 using_bloom = true;
418                                 break;
419                         }
420
421                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
422                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
423
424                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
425                                 bloom_add_pair(bloom, buf, c->value_str);
426                                 using_bloom = true;
427                                 break;
428                         }
429
430                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
431                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
432
433                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
434                                 bloom_add_pair(bloom, buf, c->value_str);
435                                 using_bloom = true;
436                                 break;
437                         }
438
439                         case BUS_MATCH_DESTINATION:
440                                 /* The bloom filter does not include
441                                    the destination, since it is only
442                                    available for broadcast messages
443                                    which do not carry a destination
444                                    since they are undirected. */
445                                 break;
446
447                         case BUS_MATCH_ROOT:
448                         case BUS_MATCH_VALUE:
449                         case BUS_MATCH_LEAF:
450                         case _BUS_MATCH_NODE_TYPE_MAX:
451                         case _BUS_MATCH_NODE_TYPE_INVALID:
452                                 assert_not_reached("Invalid match type?");
453                         }
454                 }
455
456                 if (using_bloom)
457                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
458
459                 m = alloca0(sz);
460                 m->size = sz;
461                 m->cookie = cookie;
462                 m->src_id = src_id;
463
464                 item = m->items;
465
466                 if (using_bloom) {
467                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
468                         item->type = KDBUS_MATCH_BLOOM;
469                         memcpy(item->data64, bloom, BLOOM_SIZE);
470
471                         item = KDBUS_ITEM_NEXT(item);
472                 }
473
474                 if (sender) {
475                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
476                         item->type = KDBUS_MATCH_SRC_NAME;
477                         memcpy(item->str, sender, sender_length + 1);
478                 }
479
480                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
481                 if (r < 0)
482                         return -errno;
483
484         } else {
485                 return sd_bus_call_method(
486                                 bus,
487                                 "org.freedesktop.DBus",
488                                 "/",
489                                 "org.freedesktop.DBus",
490                                 "AddMatch",
491                                 NULL,
492                                 NULL,
493                                 "s",
494                                 match);
495         }
496
497         return 0;
498 }
499
500 int bus_remove_match_internal(
501                 sd_bus *bus,
502                 const char *match,
503                 uint64_t cookie) {
504
505         int r;
506
507         assert(bus);
508         assert(match);
509
510         if (bus->is_kernel) {
511                 struct kdbus_cmd_match m;
512
513                 zero(m);
514                 m.size = offsetof(struct kdbus_cmd_match, items);
515                 m.cookie = cookie;
516
517                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
518                 if (r < 0)
519                         return -errno;
520
521         } else {
522                 return sd_bus_call_method(
523                                 bus,
524                                 "org.freedesktop.DBus",
525                                 "/",
526                                 "org.freedesktop.DBus",
527                                 "RemoveMatch",
528                                 NULL,
529                                 NULL,
530                                 "s",
531                                 match);
532         }
533
534         return 0;
535 }
536
537 _public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
538         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
539         const char *mid;
540         int r;
541
542         assert_return(bus, -EINVAL);
543         assert_return(name, -EINVAL);
544         assert_return(machine, -EINVAL);
545         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
546         assert_return(!bus_pid_changed(bus), -ECHILD);
547
548         if (streq_ptr(name, bus->unique_name))
549                 return sd_id128_get_machine(machine);
550
551         r = sd_bus_message_new_method_call(
552                         bus,
553                         name,
554                         "/",
555                         "org.freedesktop.DBus.Peer",
556                         "GetMachineId", &m);
557         if (r < 0)
558                 return r;
559
560         r = sd_bus_message_set_no_auto_start(m, true);
561         if (r < 0)
562                 return r;
563
564         r = sd_bus_call(bus, m, 0, NULL, &reply);
565         if (r < 0)
566                 return r;
567
568         r = sd_bus_message_read(reply, "s", &mid);
569         if (r < 0)
570                 return r;
571
572         return sd_id128_from_string(mid, machine);
573 }