chiark / gitweb /
bus: properly return an error code when release_name fails abnormally
[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 = alloca0(size);
337         strcpy(cmd_name->name, name);
338         cmd_name->size = size;
339         kdbus_translate_request_name_flags(flags, (uint64_t *) &cmd_name->conn_flags);
340
341         /* This function is open-coded because we request the name 'on behalf'
342          * of the requesting connection */
343         r = bus_kernel_parse_unique_name(m->sender, &id);
344         if (r < 0)
345                 return r;
346
347         cmd_name->id = id;
348
349         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_ACQUIRE, cmd_name);
350         if (r < 0) {
351                 if (errno == EEXIST)
352                         return sd_bus_reply_method_return(m, "u", BUS_NAME_EXISTS);
353                 else if (errno == EALREADY)
354                         return sd_bus_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
355
356                 return -errno;
357         }
358
359         if (cmd_name->flags & KDBUS_NAME_IN_QUEUE)
360                 return sd_bus_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
361
362         return sd_bus_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
363 }
364
365 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
366
367         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
368         char *s;
369         int r;
370
371         return sd_bus_reply_method_return(m, "u", 2);
372
373         r = sd_bus_message_read(m, "s", &s);
374         if (r < 0)
375                 return r;
376
377         /* FIXME */
378
379         return sd_bus_send(bus, reply, NULL);
380 }
381
382 static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
383         return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
384 }
385
386 static const sd_bus_vtable driver_vtable[] = {
387         SD_BUS_VTABLE_START(0),
388         SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, 0),
389         SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_ctx, 0),
390         SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, 0),
391         SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, 0),
392         SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, 0),
393         SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, 0),
394         SD_BUS_METHOD("Hello", NULL, "s", driver_hello, 0),
395         SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, 0),
396         SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, 0),
397         SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, 0),
398         SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, 0),
399         SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, 0),
400         SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, 0),
401         SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, 0),
402         SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, 0),
403         SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_unsupported, 0),
404         SD_BUS_SIGNAL("NameAcquired", "s", 0),
405         SD_BUS_SIGNAL("NameLost", "s", 0),
406         SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
407         SD_BUS_VTABLE_END
408 };
409
410 static int connect_bus(sd_event *event, sd_bus **_bus) {
411         _cleanup_bus_unref_ sd_bus *bus = NULL;
412         int r;
413
414         assert(event);
415         assert(_bus);
416
417         r = sd_bus_default_system(&bus);
418         if (r < 0) {
419                 log_error("Failed to create bus: %s", strerror(-r));
420                 return r;
421         }
422
423         r = sd_bus_add_object_vtable(bus, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable, NULL);
424         if (r < 0) {
425                 log_error("Failed to add manager object vtable: %s", strerror(-r));
426                 return r;
427         }
428
429         r = sd_bus_request_name(bus, "org.freedesktop.DBus", 0);
430         if (r < 0) {
431                 log_error("Unable to request name: %s\n", strerror(-r));
432                 return r;
433         }
434
435         r = sd_bus_attach_event(bus, event, 0);
436         if (r < 0) {
437                 log_error("Error %d while adding bus to even: %s", r, strerror(-r));
438                 return r;
439         }
440
441         *_bus = bus;
442         bus = NULL;
443
444         return 0;
445 }
446
447 int main(int argc, char *argv[]) {
448         _cleanup_event_unref_ sd_event *event = NULL;
449         _cleanup_bus_unref_ sd_bus *bus = NULL;
450         int r;
451
452         log_set_target(LOG_TARGET_AUTO);
453         log_parse_environment();
454         log_open();
455
456         if (argc != 1) {
457                 log_error("This program takes no arguments.");
458                 r = -EINVAL;
459                 goto finish;
460         }
461
462         r = sd_event_default(&event);
463         if (r < 0) {
464                 log_error("Failed to allocate event loop: %s", strerror(-r));
465                 goto finish;
466         }
467
468         sd_event_set_watchdog(event, true);
469
470         r = connect_bus(event, &bus);
471         if (r < 0)
472                 goto finish;
473
474         r = bus_event_loop_with_idle(event, bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC);
475         if (r < 0) {
476                 log_error("Failed to run event loop: %s", strerror(-r));
477                 goto finish;
478         }
479
480 finish:
481         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
482
483 }