chiark / gitweb /
f28dc5738e62dc38ed515e049a25f05b1530bb6e
[elogind.git] / src / bus-driverd / bus-driverd.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Daniel Mack
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <locale.h>
25 #include <string.h>
26 #include <poll.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/timex.h>
31 #include <sys/utsname.h>
32 #include <unistd.h>
33
34 #include "kdbus.h"
35 #include "sd-bus.h"
36 #include "bus-internal.h"
37 #include "sd-daemon.h"
38 #include "sd-event.h"
39 #include "event-util.h"
40 #include "bus-util.h"
41 #include "bus-error.h"
42 #include "bus-message.h"
43 #include "bus-kernel.h"
44 #include "socket-util.h"
45 #include "util.h"
46 #include "build.h"
47 #include "strv.h"
48 #include "sd-id128.h"
49 #include "async.h"
50 #include "hashmap.h"
51 #include "def.h"
52 #include "unit-name.h"
53
54 /*
55  * TODO:
56  *
57  * AddMatch / RemoveMatch
58  */
59
60 static int driver_add_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
61
62         char *arg0;
63         int r;
64
65         r = sd_bus_message_read(m, "s", &arg0);
66         if (r < 0)
67                 return r;
68
69         /* FIXME */
70
71         return sd_bus_reply_method_return(m, NULL);
72 }
73
74 static int driver_remove_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
75         char *arg0;
76         int r;
77
78         r = sd_bus_message_read(m, "s", &arg0);
79         if (r < 0)
80                 return r;
81
82         /* FIXME */
83
84         return sd_bus_reply_method_return(m, NULL);
85 }
86
87 static int driver_get_security_ctx(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
88         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
89         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
90         char *arg0;
91         int r;
92
93         r = sd_bus_message_read(m, "s", &arg0);
94         if (r < 0)
95                 return r;
96
97         assert_return(service_name_is_valid(arg0), -EINVAL);
98
99         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_SELINUX_CONTEXT, &creds);
100         if (r < 0)
101                 return r;
102
103         r = sd_bus_message_new_method_return(m, &reply);
104         if (r < 0)
105                 return r;
106
107         r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
108         if (r < 0)
109                 return r;
110
111         return sd_bus_send(bus, reply, NULL);
112 }
113
114 static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
115         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
116         char *arg0;
117         int r;
118
119         r = sd_bus_message_read(m, "s", &arg0);
120         if (r < 0)
121                 return r;
122
123         assert_return(service_name_is_valid(arg0), -EINVAL);
124
125         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_PID, &creds);
126         if (r < 0)
127                 return r;
128
129         return sd_bus_reply_method_return(m, "u", creds->pid);
130 }
131
132 static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
133         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
134         char *arg0;
135         int r;
136
137         r = sd_bus_message_read(m, "s", &arg0);
138         if (r < 0)
139                 return r;
140
141         assert_return(service_name_is_valid(arg0), -EINVAL);
142
143         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UID, &creds);
144         if (r < 0)
145                 return r;
146
147         return sd_bus_reply_method_return(m, "u", creds->uid);
148 }
149
150 static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
151         sd_id128_t server_id;
152         char buf[SD_ID128_STRING_MAX];
153         int r;
154
155         r = sd_bus_get_server_id(bus, &server_id);
156         if (r < 0)
157                 return r;
158
159         return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
160 }
161
162 static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
163         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
164         char *arg0;
165         int r;
166
167         r = sd_bus_message_read(m, "s", &arg0);
168         if (r < 0)
169                 return r;
170
171         assert_return(service_name_is_valid(arg0), -EINVAL);
172
173         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UNIQUE_NAME, &creds);
174         if (r < 0)
175                 return r;
176
177         return sd_bus_reply_method_return(m, "s", creds->unique_name);
178 }
179
180 static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
181         return sd_bus_reply_method_return(m, "s", m->sender);
182 }
183
184 static int return_strv(sd_bus *bus, sd_bus_message *m, char **l) {
185         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
186         int r;
187
188         r = sd_bus_message_new_method_return(m, &reply);
189         if (r < 0)
190                 return r;
191
192         r = sd_bus_message_append_strv(reply, l);
193         if (r < 0)
194                 return r;
195
196         return sd_bus_send(bus, reply, NULL);
197 }
198
199 static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
200         _cleanup_strv_free_ char **names = NULL;
201         int r;
202
203         r = sd_bus_list_names(bus, &names, NULL);
204         if (r < 0)
205                 return r;
206
207         return return_strv(bus, m, names);
208 }
209
210 static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
211         _cleanup_strv_free_ char **names = NULL;
212         int r;
213
214         r = sd_bus_list_names(bus, NULL, &names);
215         if (r < 0)
216                 return r;
217
218         return return_strv(bus, m, names);
219 }
220
221 static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
222         struct kdbus_cmd_name_list cmd = {};
223         struct kdbus_name_list *name_list;
224         struct kdbus_cmd_name *name;
225         _cleanup_strv_free_ char **owners = NULL;
226         char *arg0;
227         int r;
228
229         r = sd_bus_message_read(m, "s", &arg0);
230         if (r < 0)
231                 return r;
232
233         assert_return(service_name_is_valid(arg0), -EINVAL);
234
235         cmd.flags = KDBUS_NAME_LIST_QUEUED;
236
237         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
238         if (r < 0)
239                 return -errno;
240
241         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
242
243         KDBUS_ITEM_FOREACH(name, name_list, names) {
244                 char *n;
245
246                 if (name->size <= sizeof(*name))
247                         continue;
248
249                 if (!streq(name->name, arg0))
250                         continue;
251
252                 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
253                         return -ENOMEM;
254
255                 r = strv_push(&owners, n);
256                 if (r < 0) {
257                         free(n);
258                         return -ENOMEM;
259                 }
260         }
261
262         r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
263         if (r < 0)
264                 return -errno;
265
266         return return_strv(bus, m, owners);
267 }
268
269 static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
270         char *arg0;
271         int r;
272
273         r = sd_bus_message_read(m, "s", &arg0);
274         if (r < 0)
275                 return r;
276
277         assert_return(service_name_is_valid(arg0), -EINVAL);
278
279         r = sd_bus_get_owner(bus, arg0, 0, NULL);
280         if (r < 0 && r != -ENOENT)
281                 return r;
282
283         return sd_bus_reply_method_return(m, "b", r >= 0);
284 }
285
286 static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
287         struct kdbus_cmd_name *n;
288         uint32_t flags;
289         size_t size, l;
290         uint64_t id;
291         const char *name;
292         int r;
293
294         r = sd_bus_message_read(m, "su", &name, &flags);
295         if (r < 0)
296                 return r;
297
298         assert_return(service_name_is_valid(name), -EINVAL);
299         assert_return((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) == 0, -EINVAL);
300
301         l = strlen(name);
302         size = offsetof(struct kdbus_cmd_name, name) + l + 1;
303         n = alloca0(size);
304         n->size = size;
305         memcpy(n->name, name, l+1);
306         kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
307
308         /* This function is open-coded because we request the name 'on behalf'
309          * of the requesting connection */
310         r = bus_kernel_parse_unique_name(m->sender, &id);
311         if (r < 0)
312                 return r;
313
314         n->id = id;
315
316         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
317         if (r < 0) {
318                 if (errno == EEXIST)
319                         return sd_bus_reply_method_return(m, "u", BUS_NAME_EXISTS);
320                 if (errno == EALREADY)
321                         return sd_bus_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
322
323                 return -errno;
324         }
325
326         if (n->flags & KDBUS_NAME_IN_QUEUE)
327                 return sd_bus_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
328
329         return sd_bus_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
330 }
331
332 static int driver_release_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
333         struct kdbus_cmd_name *n;
334         const char *name;
335         size_t l, size;
336         uint64_t id;
337         int r;
338
339         r = sd_bus_message_read(m, "s", &name);
340         if (r < 0)
341                 return r;
342
343         assert_return(service_name_is_valid(name), -EINVAL);
344
345         l = strlen(name);
346         size = offsetof(struct kdbus_cmd_name, name) + l + 1;
347         n = alloca0(size);
348         n->size = size;
349         memcpy(n->name, name, l+1);
350
351         /* This function is open-coded because we request the name 'on behalf'
352          * of the requesting connection */
353         r = bus_kernel_parse_unique_name(m->sender, &id);
354         if (r < 0)
355                 return r;
356
357         n->id = id;
358
359         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
360         if (r < 0) {
361                 if (errno == ESRCH)
362                         return sd_bus_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
363                 if (errno == EADDRINUSE)
364                         return sd_bus_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
365                 return -errno;
366         }
367
368         return sd_bus_reply_method_return(m, "u", BUS_NAME_RELEASED);
369 }
370
371 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
372         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373         _cleanup_strv_free_ char **t = NULL;
374         _cleanup_free_ char *path = NULL;
375         uint32_t flags;
376         char *name, *u;
377         int r;
378
379         r = sd_bus_message_read(m, "su", &name, &flags);
380         if (r < 0)
381                 return r;
382
383         assert_return(service_name_is_valid(name), -EINVAL);
384         assert_return(flags == 0, -ENOTSUP);
385
386         r = sd_bus_get_owner(bus, name, 0, NULL);
387         if (r >= 0)
388                 return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
389         if (r != -ENOENT)
390                 return r;
391
392         u = strappenda(name, ".busname");
393
394         path = unit_dbus_path_from_name(u);
395         if (!path)
396                 return -ENOMEM;
397
398         r = sd_bus_get_property_strv(
399                         bus,
400                         "org.freedesktop.systemd1",
401                         path,
402                         "org.freedesktop.systemd1.Unit",
403                         "Triggers",
404                         error,
405                         &t);
406         if (r < 0)
407                 return r;
408
409         if (!t[0] || t[1])
410                 return -EIO;
411
412         r = sd_bus_call_method(
413                         bus,
414                         "org.freedesktop.systemd1",
415                         "/org/freedesktop/systemd1",
416                         "org.freedesktop.systemd1.Manager",
417                         "StartUnit",
418                         error,
419                         &reply,
420                         "ss",
421                         t[0],
422                         "replace");
423         if (r < 0)
424                 return r;
425
426         return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
427 }
428
429 static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
430         return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
431 }
432
433 static const sd_bus_vtable driver_vtable[] = {
434         SD_BUS_VTABLE_START(0),
435         SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, 0),
436         SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_ctx, SD_BUS_VTABLE_UNPRIVILEGED),
437         SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, SD_BUS_VTABLE_UNPRIVILEGED),
438         SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, SD_BUS_VTABLE_UNPRIVILEGED),
439         SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, SD_BUS_VTABLE_UNPRIVILEGED),
440         SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, SD_BUS_VTABLE_UNPRIVILEGED),
441         SD_BUS_METHOD("Hello", NULL, "s", driver_hello, SD_BUS_VTABLE_UNPRIVILEGED),
442         SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, SD_BUS_VTABLE_UNPRIVILEGED),
443         SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, SD_BUS_VTABLE_UNPRIVILEGED),
444         SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, SD_BUS_VTABLE_UNPRIVILEGED),
445         SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, SD_BUS_VTABLE_UNPRIVILEGED),
446         SD_BUS_METHOD("ReleaseName", "s", "u", driver_release_name, SD_BUS_VTABLE_UNPRIVILEGED),
447         SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, SD_BUS_VTABLE_DEPRECATED),
448         SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, SD_BUS_VTABLE_UNPRIVILEGED),
449         SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, SD_BUS_VTABLE_UNPRIVILEGED),
450         SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
451         SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_unsupported, SD_BUS_VTABLE_DEPRECATED),
452         SD_BUS_SIGNAL("NameAcquired", "s", SD_BUS_VTABLE_DEPRECATED),
453         SD_BUS_SIGNAL("NameLost", "s", SD_BUS_VTABLE_DEPRECATED),
454         SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
455         SD_BUS_VTABLE_END
456 };
457
458 static int connect_bus(sd_event *event, sd_bus **_bus) {
459         _cleanup_bus_unref_ sd_bus *bus = NULL;
460         int r;
461
462         assert(event);
463         assert(_bus);
464
465         r = sd_bus_default_system(&bus);
466         if (r < 0) {
467                 log_error("Failed to create bus: %s", strerror(-r));
468                 return r;
469         }
470
471         if (!bus->is_kernel) {
472                 log_error("Not running on kdbus");
473                 return -EPERM;
474         }
475
476         r = sd_bus_add_object_vtable(bus, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable, NULL);
477         if (r < 0) {
478                 log_error("Failed to add manager object vtable: %s", strerror(-r));
479                 return r;
480         }
481
482         r = sd_bus_request_name(bus, "org.freedesktop.DBus", 0);
483         if (r < 0) {
484                 log_error("Unable to request name: %s\n", strerror(-r));
485                 return r;
486         }
487
488         r = sd_bus_attach_event(bus, event, 0);
489         if (r < 0) {
490                 log_error("Error %d while adding bus to even: %s", r, strerror(-r));
491                 return r;
492         }
493
494         *_bus = bus;
495         bus = NULL;
496
497         return 0;
498 }
499
500 int main(int argc, char *argv[]) {
501         _cleanup_event_unref_ sd_event *event = NULL;
502         _cleanup_bus_unref_ sd_bus *bus = NULL;
503         int r;
504
505         log_set_target(LOG_TARGET_AUTO);
506         log_parse_environment();
507         log_open();
508
509         if (argc != 1) {
510                 log_error("This program takes no arguments.");
511                 r = -EINVAL;
512                 goto finish;
513         }
514
515         r = sd_event_default(&event);
516         if (r < 0) {
517                 log_error("Failed to allocate event loop: %s", strerror(-r));
518                 goto finish;
519         }
520
521         sd_event_set_watchdog(event, true);
522
523         r = connect_bus(event, &bus);
524         if (r < 0)
525                 goto finish;
526
527         r = bus_event_loop_with_idle(event, bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC);
528         if (r < 0) {
529                 log_error("Failed to run event loop: %s", strerror(-r));
530                 goto finish;
531         }
532
533 finish:
534         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
535
536 }