1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/types.h>
33 #include "bus-internal.h"
34 #include "bus-message.h"
39 #include "capability.h"
40 #include "bus-control.h"
43 #include "synthesize.h"
45 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
46 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
53 r = sd_bus_get_name_creds(bus, name, mask, &c);
54 if (r == -ESRCH || r == -ENXIO)
55 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
59 if ((c->mask & mask) != mask)
68 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
76 r = sd_bus_message_read(m, "s", &name);
80 return get_creds_by_name(bus, name, mask, _creds, error);
83 int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
93 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
96 /* The "Hello()" call is is handled in process_hello() */
98 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
100 if (!sd_bus_message_has_signature(m, ""))
101 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
103 return synthetic_reply_method_return(m, "s",
104 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
105 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
107 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
108 " <method name=\"Introspect\">\n"
109 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
112 " <interface name=\"org.freedesktop.DBus\">\n"
113 " <method name=\"AddMatch\">\n"
114 " <arg type=\"s\" direction=\"in\"/>\n"
116 " <method name=\"RemoveMatch\">\n"
117 " <arg type=\"s\" direction=\"in\"/>\n"
119 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
120 " <arg type=\"s\" direction=\"in\"/>\n"
121 " <arg type=\"ay\" direction=\"out\"/>\n"
123 " <method name=\"GetConnectionUnixProcessID\">\n"
124 " <arg type=\"s\" direction=\"in\"/>\n"
125 " <arg type=\"u\" direction=\"out\"/>\n"
127 " <method name=\"GetConnectionUnixUser\">\n"
128 " <arg type=\"s\" direction=\"in\"/>\n"
129 " <arg type=\"u\" direction=\"out\"/>\n"
131 " <method name=\"GetId\">\n"
132 " <arg type=\"s\" direction=\"out\"/>\n"
134 " <method name=\"GetNameOwner\">\n"
135 " <arg type=\"s\" direction=\"in\"/>\n"
136 " <arg type=\"s\" direction=\"out\"/>\n"
138 " <method name=\"Hello\">\n"
139 " <arg type=\"s\" direction=\"out\"/>\n"
141 " <method name=\"ListActivatableNames\">\n"
142 " <arg type=\"as\" direction=\"out\"/>\n"
144 " <method name=\"ListNames\">\n"
145 " <arg type=\"as\" direction=\"out\"/>\n"
147 " <method name=\"ListQueuedOwners\">\n"
148 " <arg type=\"s\" direction=\"in\"/>\n"
149 " <arg type=\"as\" direction=\"out\"/>\n"
151 " <method name=\"NameHasOwner\">\n"
152 " <arg type=\"s\" direction=\"in\"/>\n"
153 " <arg type=\"b\" direction=\"out\"/>\n"
155 " <method name=\"ReleaseName\">\n"
156 " <arg type=\"s\" direction=\"in\"/>\n"
157 " <arg type=\"u\" direction=\"out\"/>\n"
159 " <method name=\"ReloadConfig\">\n"
161 " <method name=\"RequestName\">\n"
162 " <arg type=\"s\" direction=\"in\"/>\n"
163 " <arg type=\"u\" direction=\"in\"/>\n"
164 " <arg type=\"u\" direction=\"out\"/>\n"
166 " <method name=\"StartServiceByName\">\n"
167 " <arg type=\"s\" direction=\"in\"/>\n"
168 " <arg type=\"u\" direction=\"in\"/>\n"
169 " <arg type=\"u\" direction=\"out\"/>\n"
171 " <method name=\"UpdateActivationEnvironment\">\n"
172 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
174 " <signal name=\"NameAcquired\">\n"
175 " <arg type=\"s\"/>\n"
177 " <signal name=\"NameLost\">\n"
178 " <arg type=\"s\"/>\n"
180 " <signal name=\"NameOwnerChanged\">\n"
181 " <arg type=\"s\"/>\n"
182 " <arg type=\"s\"/>\n"
183 " <arg type=\"s\"/>\n"
188 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
191 if (!sd_bus_message_has_signature(m, "s"))
192 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
194 r = sd_bus_message_read(m, "s", &match);
196 return synthetic_reply_method_errno(m, r, NULL);
198 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
200 return synthetic_reply_method_errno(m, r, NULL);
202 return synthetic_reply_method_return(m, NULL);
204 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
207 if (!sd_bus_message_has_signature(m, "s"))
208 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
210 r = sd_bus_message_read(m, "s", &match);
212 return synthetic_reply_method_errno(m, r, NULL);
214 r = bus_remove_match_by_string(a, match, NULL, NULL);
216 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
218 return synthetic_reply_method_errno(m, r, NULL);
220 return synthetic_reply_method_return(m, NULL);
222 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
223 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
224 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
226 if (!sd_bus_message_has_signature(m, "s"))
227 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
229 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
231 return synthetic_reply_method_errno(m, r, &error);
233 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
235 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
236 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
237 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
239 if (!sd_bus_message_has_signature(m, "s"))
240 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
242 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
244 return synthetic_reply_method_errno(m, r, &error);
246 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
248 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
249 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
250 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
252 if (!sd_bus_message_has_signature(m, "s"))
253 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
255 r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
257 return synthetic_reply_method_errno(m, r, &error);
259 return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
261 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
262 sd_id128_t server_id;
263 char buf[SD_ID128_STRING_MAX];
265 if (!sd_bus_message_has_signature(m, ""))
266 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
268 r = sd_bus_get_bus_id(a, &server_id);
270 return synthetic_reply_method_errno(m, r, NULL);
272 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
274 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
276 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
277 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
279 if (!sd_bus_message_has_signature(m, "s"))
280 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
282 r = sd_bus_message_read(m, "s", &name);
284 return synthetic_reply_method_errno(m, r, NULL);
286 if (streq(name, "org.freedesktop.DBus"))
287 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
289 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
291 return synthetic_reply_method_errno(m, r, &error);
293 return synthetic_reply_method_return(m, "s", creds->unique_name);
295 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
296 _cleanup_strv_free_ char **names = NULL;
298 if (!sd_bus_message_has_signature(m, ""))
299 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
301 r = sd_bus_list_names(a, NULL, &names);
303 return synthetic_reply_method_errno(m, r, NULL);
305 /* Let's sort the names list to make it stable */
308 return synthetic_reply_return_strv(m, names);
310 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
311 _cleanup_strv_free_ char **names = NULL;
313 if (!sd_bus_message_has_signature(m, ""))
314 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
316 r = sd_bus_list_names(a, &names, NULL);
318 return synthetic_reply_method_errno(m, r, NULL);
320 r = strv_extend(&names, "org.freedesktop.DBus");
322 return synthetic_reply_method_errno(m, r, NULL);
324 /* Let's sort the names list to make it stable */
327 return synthetic_reply_return_strv(m, names);
329 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
330 struct kdbus_cmd_name_list cmd = {};
331 struct kdbus_name_list *name_list;
332 struct kdbus_name_info *name;
333 _cleanup_strv_free_ char **owners = NULL;
334 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
338 if (!sd_bus_message_has_signature(m, "s"))
339 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
341 r = sd_bus_message_read(m, "s", &arg0);
343 return synthetic_reply_method_errno(m, r, NULL);
345 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
346 if (r == -ESRCH || r == -ENXIO) {
347 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
348 return synthetic_reply_method_errno(m, r, &error);
351 return synthetic_reply_method_errno(m, r, NULL);
353 cmd.flags = KDBUS_NAME_LIST_QUEUED;
354 r = ioctl(a->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
356 return synthetic_reply_method_errno(m, -errno, NULL);
358 name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
360 KDBUS_ITEM_FOREACH(name, name_list, names) {
361 const char *entry_name = NULL;
362 struct kdbus_item *item;
365 KDBUS_ITEM_FOREACH(item, name, items)
366 if (item->type == KDBUS_ITEM_OWNED_NAME)
367 entry_name = item->name.name;
369 if (!streq_ptr(entry_name, arg0))
372 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) {
377 r = strv_consume(&owners, n);
384 r = bus_kernel_cmd_free(a, cmd.offset);
386 return synthetic_reply_method_errno(m, r, NULL);
389 return synthetic_reply_method_errno(m, err, NULL);
391 return synthetic_reply_return_strv(m, owners);
393 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
396 if (!sd_bus_message_has_signature(m, "s"))
397 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
399 r = sd_bus_message_read(m, "s", &name);
401 return synthetic_reply_method_errno(m, r, NULL);
403 if (streq(name, "org.freedesktop.DBus"))
404 return synthetic_reply_method_return(m, "b", true);
406 r = sd_bus_get_name_creds(a, name, 0, NULL);
407 if (r < 0 && r != -ESRCH && r != -ENXIO)
408 return synthetic_reply_method_errno(m, r, NULL);
410 return synthetic_reply_method_return(m, "b", r >= 0);
412 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
415 if (!sd_bus_message_has_signature(m, "s"))
416 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
418 r = sd_bus_message_read(m, "s", &name);
420 return synthetic_reply_method_errno(m, r, NULL);
422 r = sd_bus_release_name(a, name);
425 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
426 if (r == -EADDRINUSE)
427 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
429 return synthetic_reply_method_errno(m, r, NULL);
432 set_remove(owned_names, (char*) name);
434 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
436 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
437 if (!sd_bus_message_has_signature(m, ""))
438 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
440 r = shared_policy_reload(sp);
442 return synthetic_reply_method_errno(m, r, NULL);
444 return synthetic_reply_method_return(m, NULL);
446 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
448 uint32_t flags, param;
451 if (!sd_bus_message_has_signature(m, "su"))
452 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
454 r = sd_bus_message_read(m, "su", &name, &flags);
456 return synthetic_reply_method_errno(m, r, NULL);
462 policy = shared_policy_acquire(sp);
463 denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
464 shared_policy_release(sp, policy);
466 return synthetic_reply_method_errno(m, -EPERM, NULL);
469 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
470 return synthetic_reply_method_errno(m, -EINVAL, NULL);
473 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
474 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
475 if (flags & BUS_NAME_REPLACE_EXISTING)
476 param |= SD_BUS_NAME_REPLACE_EXISTING;
477 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
478 param |= SD_BUS_NAME_QUEUE;
480 r = set_put_strdup(owned_names, name);
482 return synthetic_reply_method_errno(m, r, NULL);
484 r = sd_bus_request_name(a, name, param);
487 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
489 set_remove(owned_names, (char*) name);
492 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
493 return synthetic_reply_method_errno(m, r, NULL);
499 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
501 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
503 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
504 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
508 if (!sd_bus_message_has_signature(m, "su"))
509 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
511 r = sd_bus_message_read(m, "su", &name, &flags);
513 return synthetic_reply_method_errno(m, r, NULL);
516 return synthetic_reply_method_errno(m, -EINVAL, NULL);
518 r = sd_bus_get_name_creds(a, name, 0, NULL);
519 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
520 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
522 return synthetic_reply_method_errno(m, r, NULL);
524 r = sd_bus_message_new_method_call(
529 "org.freedesktop.DBus.Peer",
532 return synthetic_reply_method_errno(m, r, NULL);
534 r = sd_bus_send(a, msg, NULL);
536 return synthetic_reply_method_errno(m, r, NULL);
538 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
540 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
541 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
542 _cleanup_strv_free_ char **args = NULL;
544 if (!sd_bus_message_has_signature(m, "a{ss}"))
545 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
547 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
549 return synthetic_reply_method_errno(m, r, NULL);
551 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
552 _cleanup_free_ char *s = NULL;
556 r = sd_bus_message_read(m, "ss", &key, &value);
558 return synthetic_reply_method_errno(m, r, NULL);
560 s = strjoin(key, "=", value, NULL);
562 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
564 r = strv_extend(&args, s);
566 return synthetic_reply_method_errno(m, r, NULL);
568 r = sd_bus_message_exit_container(m);
570 return synthetic_reply_method_errno(m, r, NULL);
573 r = sd_bus_message_exit_container(m);
575 return synthetic_reply_method_errno(m, r, NULL);
578 return synthetic_reply_method_errno(m, -EINVAL, NULL);
580 r = sd_bus_message_new_method_call(
583 "org.freedesktop.systemd1",
584 "/org/freedesktop/systemd1",
585 "org.freedesktop.systemd1.Manager",
588 return synthetic_reply_method_errno(m, r, NULL);
590 r = sd_bus_message_append_strv(msg, args);
592 return synthetic_reply_method_errno(m, r, NULL);
594 r = sd_bus_call(a, msg, 0, NULL, NULL);
596 return synthetic_reply_method_errno(m, r, NULL);
598 return synthetic_reply_method_return(m, NULL);
601 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
603 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
605 return synthetic_reply_method_errno(m, r, &error);