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_list cmd = {};
331 struct kdbus_info *name_list, *name;
332 _cleanup_strv_free_ char **owners = NULL;
333 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
337 if (!sd_bus_message_has_signature(m, "s"))
338 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
340 r = sd_bus_message_read(m, "s", &arg0);
342 return synthetic_reply_method_errno(m, r, NULL);
344 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
345 if (r == -ESRCH || r == -ENXIO) {
346 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
347 return synthetic_reply_method_errno(m, r, &error);
350 return synthetic_reply_method_errno(m, r, NULL);
352 cmd.flags = KDBUS_LIST_QUEUED;
353 r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
355 return synthetic_reply_method_errno(m, -errno, NULL);
357 name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
359 KDBUS_FOREACH(name, name_list, cmd.list_size) {
360 const char *entry_name = NULL;
361 struct kdbus_item *item;
364 KDBUS_ITEM_FOREACH(item, name, items)
365 if (item->type == KDBUS_ITEM_OWNED_NAME)
366 entry_name = item->name.name;
368 if (!streq_ptr(entry_name, arg0))
371 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
376 r = strv_consume(&owners, n);
383 r = bus_kernel_cmd_free(a, cmd.offset);
385 return synthetic_reply_method_errno(m, r, NULL);
388 return synthetic_reply_method_errno(m, err, NULL);
390 return synthetic_reply_return_strv(m, owners);
392 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
395 if (!sd_bus_message_has_signature(m, "s"))
396 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
398 r = sd_bus_message_read(m, "s", &name);
400 return synthetic_reply_method_errno(m, r, NULL);
402 if (streq(name, "org.freedesktop.DBus"))
403 return synthetic_reply_method_return(m, "b", true);
405 r = sd_bus_get_name_creds(a, name, 0, NULL);
406 if (r < 0 && r != -ESRCH && r != -ENXIO)
407 return synthetic_reply_method_errno(m, r, NULL);
409 return synthetic_reply_method_return(m, "b", r >= 0);
411 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
414 if (!sd_bus_message_has_signature(m, "s"))
415 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
417 r = sd_bus_message_read(m, "s", &name);
419 return synthetic_reply_method_errno(m, r, NULL);
421 r = sd_bus_release_name(a, name);
424 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
425 if (r == -EADDRINUSE)
426 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
428 return synthetic_reply_method_errno(m, r, NULL);
431 set_remove(owned_names, (char*) name);
433 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
435 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
436 if (!sd_bus_message_has_signature(m, ""))
437 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
439 r = shared_policy_reload(sp);
441 return synthetic_reply_method_errno(m, r, NULL);
443 return synthetic_reply_method_return(m, NULL);
445 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
447 uint32_t flags, param;
450 if (!sd_bus_message_has_signature(m, "su"))
451 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
453 r = sd_bus_message_read(m, "su", &name, &flags);
455 return synthetic_reply_method_errno(m, r, NULL);
461 policy = shared_policy_acquire(sp);
462 denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
463 shared_policy_release(sp, policy);
465 return synthetic_reply_method_errno(m, -EPERM, NULL);
468 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
469 return synthetic_reply_method_errno(m, -EINVAL, NULL);
472 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
473 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
474 if (flags & BUS_NAME_REPLACE_EXISTING)
475 param |= SD_BUS_NAME_REPLACE_EXISTING;
476 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
477 param |= SD_BUS_NAME_QUEUE;
479 r = set_put_strdup(owned_names, name);
481 return synthetic_reply_method_errno(m, r, NULL);
483 r = sd_bus_request_name(a, name, param);
486 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
488 set_remove(owned_names, (char*) name);
491 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
492 return synthetic_reply_method_errno(m, r, NULL);
498 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
500 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
502 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
503 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
507 if (!sd_bus_message_has_signature(m, "su"))
508 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
510 r = sd_bus_message_read(m, "su", &name, &flags);
512 return synthetic_reply_method_errno(m, r, NULL);
515 return synthetic_reply_method_errno(m, -EINVAL, NULL);
517 r = sd_bus_get_name_creds(a, name, 0, NULL);
518 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
519 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
521 return synthetic_reply_method_errno(m, r, NULL);
523 r = sd_bus_message_new_method_call(
528 "org.freedesktop.DBus.Peer",
531 return synthetic_reply_method_errno(m, r, NULL);
533 r = sd_bus_send(a, msg, NULL);
535 return synthetic_reply_method_errno(m, r, NULL);
537 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
539 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
540 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
541 _cleanup_strv_free_ char **args = NULL;
543 if (!sd_bus_message_has_signature(m, "a{ss}"))
544 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
546 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
548 return synthetic_reply_method_errno(m, r, NULL);
550 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
551 _cleanup_free_ char *s = NULL;
555 r = sd_bus_message_read(m, "ss", &key, &value);
557 return synthetic_reply_method_errno(m, r, NULL);
559 s = strjoin(key, "=", value, NULL);
561 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
563 r = strv_extend(&args, s);
565 return synthetic_reply_method_errno(m, r, NULL);
567 r = sd_bus_message_exit_container(m);
569 return synthetic_reply_method_errno(m, r, NULL);
572 r = sd_bus_message_exit_container(m);
574 return synthetic_reply_method_errno(m, r, NULL);
577 return synthetic_reply_method_errno(m, -EINVAL, NULL);
579 r = sd_bus_message_new_method_call(
582 "org.freedesktop.systemd1",
583 "/org/freedesktop/systemd1",
584 "org.freedesktop.systemd1.Manager",
587 return synthetic_reply_method_errno(m, r, NULL);
589 r = sd_bus_message_append_strv(msg, args);
591 return synthetic_reply_method_errno(m, r, NULL);
593 r = sd_bus_call(a, msg, 0, NULL, NULL);
595 return synthetic_reply_method_errno(m, r, NULL);
597 return synthetic_reply_method_return(m, NULL);
600 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
602 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
604 return synthetic_reply_method_errno(m, r, &error);