chiark / gitweb /
bus-driverd: Fix return code in driver_request_name
[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
38 #include "sd-daemon.h"
39 #include "sd-event.h"
40 #include "event-util.h"
41 #include "bus-util.h"
42 #include "bus-error.h"
43 #include "bus-message.h"
44 #include "bus-kernel.h"
45 #include "socket-util.h"
46 #include "util.h"
47 #include "build.h"
48 #include "strv.h"
49 #include "sd-id128.h"
50 #include "async.h"
51 #include "hashmap.h"
52 #include "def.h"
53
54 /*
55  * TODO:
56  *
57  * AddMatch / RemoveMatch
58  * ListActivatableNames
59  * StartServiceByName
60  */
61
62 static int driver_name_info_error(sd_bus *bus, sd_bus_message *m, const char *name, int error_code) {
63
64         if (error_code == -ENXIO || error_code == -ENOENT)
65                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER,
66                                                   "Could not get owner of name '%s': no such name",
67                                                   name);
68
69         return sd_bus_reply_method_errno(m, error_code, NULL);
70 }
71
72 static int driver_add_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
73
74         char *arg0, *match;
75         int r;
76
77         r = sd_bus_message_read(m, "s", &arg0);
78         if (r < 0)
79                 return r;
80
81         match = strdup(arg0);
82         if (!match)
83                 return -ENOMEM;
84
85         /* FIXME */
86
87         return sd_bus_reply_method_return(m, NULL);
88 }
89
90 static int driver_remove_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
91
92         char *arg0;
93         int r;
94
95         r = sd_bus_message_read(m, "s", &arg0);
96         if (r < 0)
97                 return r;
98
99         /* FIXME */
100
101         return sd_bus_reply_method_return(m, NULL);
102 }
103
104 static int driver_get_security_ctx(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
105
106         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
107         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
108         char *arg0;
109         int r;
110
111         r = sd_bus_message_read(m, "s", &arg0);
112         if (r < 0)
113                 return r;
114
115         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_SELINUX_CONTEXT, &creds);
116         if (r < 0) {
117                 if (r == -ENOENT)
118                         return driver_name_info_error(bus, m, arg0, r);
119                 else
120                         return r;
121         }
122
123         r = sd_bus_message_new_method_return(m, &reply);
124         if (r < 0)
125                 return r;
126
127         r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
128         if (r < 0)
129                 return r;
130
131         return sd_bus_send(bus, reply, NULL);
132 }
133
134 static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
135
136         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
137         char *arg0;
138         int r;
139
140         r = sd_bus_message_read(m, "s", &arg0);
141         if (r < 0)
142                 return r;
143
144         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_PID, &creds);
145         if (r < 0)
146                 return r;
147
148         return sd_bus_reply_method_return(m, "u", creds->pid);
149 }
150
151 static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
152
153         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
154         char *arg0;
155         int r;
156
157         r = sd_bus_message_read(m, "s", &arg0);
158         if (r < 0)
159                 return r;
160
161         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UID, &creds);
162         if (r < 0) {
163                 if (r == -ENOENT)
164                         return driver_name_info_error(bus, m, arg0, r);
165                 else
166                         return r;
167         }
168
169         return sd_bus_reply_method_return(m, "u", creds->uid);
170 }
171
172 static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
173
174         sd_id128_t server_id;
175         char buf[SD_ID128_STRING_MAX];
176         int r;
177
178         r = sd_bus_get_server_id(bus, &server_id);
179         if (r < 0)
180                 return r;
181
182         return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
183 }
184
185 static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
186
187         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
188         char *arg0;
189         int r;
190
191         r = sd_bus_message_read(m, "s", &arg0);
192         if (r < 0)
193                 return r;
194
195         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UNIQUE_NAME, &creds);
196         if (r < 0) {
197                 if (r == -ENOENT)
198                         return driver_name_info_error(bus, m, arg0, r);
199                 else
200                         return r;
201         }
202
203         return sd_bus_reply_method_return(m, "s", creds->unique_name);
204 }
205
206 static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
207
208         return sd_bus_reply_method_return(m, "s", m->sender);
209 }
210
211 static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
212
213         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
214         _cleanup_strv_free_ char **names = NULL;
215         int r;
216
217         r = sd_bus_list_names(bus, &names, NULL);
218         if (r < 0)
219                 return r;
220
221         r = sd_bus_message_new_method_return(m, &reply);
222         if (r < 0)
223                 return r;
224
225         r = sd_bus_message_append_strv(reply, names);
226         if (r < 0)
227                 return r;
228
229         return sd_bus_send(bus, reply, NULL);
230 }
231
232 static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
233
234         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
235         _cleanup_strv_free_ char **names = NULL;
236         int r;
237
238         r = sd_bus_list_names(bus, NULL, &names);
239         if (r < 0)
240                 return r;
241
242         r = sd_bus_message_new_method_return(m, &reply);
243         if (r < 0)
244                 return r;
245
246         r = sd_bus_message_append_strv(reply, names);
247         if (r < 0)
248                 return r;
249
250         return sd_bus_send(bus, reply, NULL);
251 }
252
253 static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
254
255         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
256         struct kdbus_cmd_name_list cmd = {};
257         struct kdbus_name_list *name_list;
258         struct kdbus_cmd_name *name;
259         _cleanup_strv_free_ char **owners = NULL;
260         char *arg0;
261         int r;
262
263         r = sd_bus_message_read(m, "s", &arg0);
264         if (r < 0)
265                 return r;
266
267         cmd.flags = KDBUS_NAME_LIST_QUEUED;
268
269         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
270         if (r < 0)
271                 return -errno;
272
273         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
274
275         KDBUS_ITEM_FOREACH(name, name_list, names) {
276                 if (name->size > sizeof(*name) && !streq(name->name, arg0)) {
277                         char *n;
278
279                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
280                                 return -ENOMEM;
281
282                         r = strv_push(&owners, n);
283                         if (r < 0) {
284                                 free(n);
285                                 return -ENOMEM;
286                         }
287                 }
288         }
289
290         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd.offset);
291         if (r < 0)
292                 return -errno;
293
294         r = sd_bus_message_new_method_return(m, &reply);
295         if (r < 0)
296                 return r;
297
298         r = sd_bus_message_append_strv(reply, owners);
299         if (r < 0)
300                 return r;
301
302         return sd_bus_send(bus, reply, NULL);
303 }
304
305 static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
306
307         char *arg0;
308         int r;
309
310         r = sd_bus_message_read(m, "s", &arg0);
311         if (r < 0)
312                 return r;
313
314         r = sd_bus_get_owner(bus, arg0, 0, NULL);
315         if (r < 0 && r != -ENOENT)
316                 return r;
317
318         return sd_bus_reply_method_return(m, "b", r == 0);
319 }
320
321 static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
322
323         struct kdbus_cmd_name *cmd_name;
324         uint32_t flags;
325         size_t size;
326         uint64_t id;
327         char *name;
328         int r;
329
330         r = sd_bus_message_read(m, "su", &name, &flags);
331         if (r < 0)
332                 return r;
333
334         size = sizeof(*cmd_name) + strlen(name) + 1;
335
336         cmd_name = alloca(size);
337         memset(cmd_name, 0, size);
338         strcpy(cmd_name->name, name);
339         cmd_name->size = size;
340         kdbus_translate_request_name_flags(flags, (uint64_t *) &cmd_name->conn_flags);
341
342         /* This function is open-coded because we request the name 'on behalf'
343          * of the requesting connection */
344         r = bus_kernel_parse_unique_name(m->sender, &id);
345         if (r < 0)
346                 return r;
347
348         cmd_name->id = id;
349
350         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_ACQUIRE, cmd_name);
351         if (r < 0) {
352                 if (errno == EEXIST)
353                         return sd_bus_reply_method_return(m, "u", BUS_NAME_EXISTS);
354                 else if (errno == EALREADY)
355                         return sd_bus_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
356                 else
357                         return sd_bus_reply_method_return(m, "u", -errno);
358         }
359
360         if (cmd_name->flags & KDBUS_NAME_IN_QUEUE)
361                 return sd_bus_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
362
363         return sd_bus_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
364 }
365
366 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
367
368         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
369         char *s;
370         int r;
371
372         return sd_bus_reply_method_return(m, "u", 2);
373
374         r = sd_bus_message_read(m, "s", &s);
375         if (r < 0)
376                 return r;
377
378         /* FIXME */
379
380         return sd_bus_send(bus, reply, NULL);
381 }
382
383 static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
384         return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
385 }
386
387 static const sd_bus_vtable driver_vtable[] = {
388         SD_BUS_VTABLE_START(0),
389         SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, 0),
390         SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_ctx, 0),
391         SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, 0),
392         SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, 0),
393         SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, 0),
394         SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, 0),
395         SD_BUS_METHOD("Hello", NULL, "s", driver_hello, 0),
396         SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, 0),
397         SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, 0),
398         SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, 0),
399         SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, 0),
400         SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, 0),
401         SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, 0),
402         SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, 0),
403         SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, 0),
404         SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_unsupported, 0),
405         SD_BUS_SIGNAL("NameAcquired", "s", 0),
406         SD_BUS_SIGNAL("NameLost", "s", 0),
407         SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
408         SD_BUS_VTABLE_END
409 };
410
411 static int connect_bus(sd_event *event, sd_bus **_bus) {
412         _cleanup_bus_unref_ sd_bus *bus = NULL;
413         int r;
414
415         assert(event);
416         assert(_bus);
417
418         r = sd_bus_default_system(&bus);
419         if (r < 0) {
420                 log_error("Failed to create bus: %s", strerror(-r));
421                 return r;
422         }
423
424         r = sd_bus_add_object_vtable(bus, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable, NULL);
425         if (r < 0) {
426                 log_error("Failed to add manager object vtable: %s", strerror(-r));
427                 return r;
428         }
429
430         r = sd_bus_request_name(bus, "org.freedesktop.DBus", 0);
431         if (r < 0) {
432                 log_error("Unable to request name: %s\n", strerror(-r));
433                 return r;
434         }
435
436         r = sd_bus_attach_event(bus, event, 0);
437         if (r < 0) {
438                 log_error("Error %d while adding bus to even: %s", r, strerror(-r));
439                 return r;
440         }
441
442         *_bus = bus;
443         bus = NULL;
444
445         return 0;
446 }
447
448 int main(int argc, char *argv[]) {
449         _cleanup_event_unref_ sd_event *event = NULL;
450         _cleanup_bus_unref_ sd_bus *bus = NULL;
451         int r;
452
453         log_set_target(LOG_TARGET_AUTO);
454         log_parse_environment();
455         log_open();
456
457         if (argc != 1) {
458                 log_error("This program takes no arguments.");
459                 r = -EINVAL;
460                 goto finish;
461         }
462
463         r = sd_event_default(&event);
464         if (r < 0) {
465                 log_error("Failed to allocate event loop: %s", strerror(-r));
466                 goto finish;
467         }
468
469         sd_event_set_watchdog(event, true);
470
471         r = connect_bus(event, &bus);
472         if (r < 0)
473                 goto finish;
474
475         r = bus_event_loop_with_idle(event, bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC);
476         if (r < 0) {
477                 log_error("Failed to run event loop: %s", strerror(-r));
478                 goto finish;
479         }
480
481 finish:
482         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
483
484 }