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/>.
30 #include "bus-internal.h"
31 #include "bus-message.h"
36 #include "synthesize.h"
38 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
39 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
46 r = sd_bus_get_name_creds(bus, name, mask, &c);
47 if (r == -ESRCH || r == -ENXIO)
48 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
52 if ((c->mask & mask) != mask)
61 static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
69 r = sd_bus_message_read(m, "s", &name);
73 return get_creds_by_name(bus, name, mask, _creds, error);
76 int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
86 if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
89 /* The "Hello()" call is is handled in process_hello() */
91 if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
93 if (!sd_bus_message_has_signature(m, ""))
94 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
96 return synthetic_reply_method_return(m, "s",
97 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
98 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
100 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
101 " <method name=\"Introspect\">\n"
102 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
105 " <interface name=\"org.freedesktop.DBus\">\n"
106 " <method name=\"AddMatch\">\n"
107 " <arg type=\"s\" direction=\"in\"/>\n"
109 " <method name=\"RemoveMatch\">\n"
110 " <arg type=\"s\" direction=\"in\"/>\n"
112 " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
113 " <arg type=\"s\" direction=\"in\"/>\n"
114 " <arg type=\"ay\" direction=\"out\"/>\n"
116 " <method name=\"GetConnectionUnixProcessID\">\n"
117 " <arg type=\"s\" direction=\"in\"/>\n"
118 " <arg type=\"u\" direction=\"out\"/>\n"
120 " <method name=\"GetConnectionUnixUser\">\n"
121 " <arg type=\"s\" direction=\"in\"/>\n"
122 " <arg type=\"u\" direction=\"out\"/>\n"
124 " <method name=\"GetId\">\n"
125 " <arg type=\"s\" direction=\"out\"/>\n"
127 " <method name=\"GetNameOwner\">\n"
128 " <arg type=\"s\" direction=\"in\"/>\n"
129 " <arg type=\"s\" direction=\"out\"/>\n"
131 " <method name=\"Hello\">\n"
132 " <arg type=\"s\" direction=\"out\"/>\n"
134 " <method name=\"ListActivatableNames\">\n"
135 " <arg type=\"as\" direction=\"out\"/>\n"
137 " <method name=\"ListNames\">\n"
138 " <arg type=\"as\" direction=\"out\"/>\n"
140 " <method name=\"ListQueuedOwners\">\n"
141 " <arg type=\"s\" direction=\"in\"/>\n"
142 " <arg type=\"as\" direction=\"out\"/>\n"
144 " <method name=\"NameHasOwner\">\n"
145 " <arg type=\"s\" direction=\"in\"/>\n"
146 " <arg type=\"b\" direction=\"out\"/>\n"
148 " <method name=\"ReleaseName\">\n"
149 " <arg type=\"s\" direction=\"in\"/>\n"
150 " <arg type=\"u\" direction=\"out\"/>\n"
152 " <method name=\"ReloadConfig\">\n"
154 " <method name=\"RequestName\">\n"
155 " <arg type=\"s\" direction=\"in\"/>\n"
156 " <arg type=\"u\" direction=\"in\"/>\n"
157 " <arg type=\"u\" direction=\"out\"/>\n"
159 " <method name=\"StartServiceByName\">\n"
160 " <arg type=\"s\" direction=\"in\"/>\n"
161 " <arg type=\"u\" direction=\"in\"/>\n"
162 " <arg type=\"u\" direction=\"out\"/>\n"
164 " <method name=\"UpdateActivationEnvironment\">\n"
165 " <arg type=\"a{ss}\" direction=\"in\"/>\n"
167 " <signal name=\"NameAcquired\">\n"
168 " <arg type=\"s\"/>\n"
170 " <signal name=\"NameLost\">\n"
171 " <arg type=\"s\"/>\n"
173 " <signal name=\"NameOwnerChanged\">\n"
174 " <arg type=\"s\"/>\n"
175 " <arg type=\"s\"/>\n"
176 " <arg type=\"s\"/>\n"
181 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
184 if (!sd_bus_message_has_signature(m, "s"))
185 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
187 r = sd_bus_message_read(m, "s", &match);
189 return synthetic_reply_method_errno(m, r, NULL);
191 r = sd_bus_add_match(a, NULL, match, NULL, NULL);
193 return synthetic_reply_method_errno(m, r, NULL);
195 return synthetic_reply_method_return(m, NULL);
197 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
200 if (!sd_bus_message_has_signature(m, "s"))
201 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
203 r = sd_bus_message_read(m, "s", &match);
205 return synthetic_reply_method_errno(m, r, NULL);
207 r = bus_remove_match_by_string(a, match, NULL, NULL);
209 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
211 return synthetic_reply_method_errno(m, r, NULL);
213 return synthetic_reply_method_return(m, NULL);
215 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
216 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
217 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
219 if (!sd_bus_message_has_signature(m, "s"))
220 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
222 r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
224 return synthetic_reply_method_errno(m, r, &error);
226 return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
228 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
229 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
230 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
232 if (!sd_bus_message_has_signature(m, "s"))
233 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
235 r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
237 return synthetic_reply_method_errno(m, r, &error);
239 return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
241 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
242 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
243 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
245 if (!sd_bus_message_has_signature(m, "s"))
246 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
248 r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
250 return synthetic_reply_method_errno(m, r, &error);
252 return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
254 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
255 sd_id128_t server_id;
256 char buf[SD_ID128_STRING_MAX];
258 if (!sd_bus_message_has_signature(m, ""))
259 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
261 r = sd_bus_get_bus_id(a, &server_id);
263 return synthetic_reply_method_errno(m, r, NULL);
265 return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
267 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
269 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
270 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
272 if (!sd_bus_message_has_signature(m, "s"))
273 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
275 r = sd_bus_message_read(m, "s", &name);
277 return synthetic_reply_method_errno(m, r, NULL);
279 if (streq(name, "org.freedesktop.DBus"))
280 return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
282 r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
284 return synthetic_reply_method_errno(m, r, &error);
286 return synthetic_reply_method_return(m, "s", creds->unique_name);
288 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
289 _cleanup_strv_free_ char **names = NULL;
291 if (!sd_bus_message_has_signature(m, ""))
292 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
294 r = sd_bus_list_names(a, NULL, &names);
296 return synthetic_reply_method_errno(m, r, NULL);
298 /* Let's sort the names list to make it stable */
301 return synthetic_reply_method_return_strv(m, names);
303 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
304 _cleanup_strv_free_ char **names = NULL;
306 if (!sd_bus_message_has_signature(m, ""))
307 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
309 r = sd_bus_list_names(a, &names, NULL);
311 return synthetic_reply_method_errno(m, r, NULL);
313 r = strv_extend(&names, "org.freedesktop.DBus");
315 return synthetic_reply_method_errno(m, r, NULL);
317 /* Let's sort the names list to make it stable */
320 return synthetic_reply_method_return_strv(m, names);
322 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
323 struct kdbus_cmd_list cmd = {
324 .flags = KDBUS_LIST_QUEUED,
327 struct kdbus_info *name_list, *name;
328 _cleanup_strv_free_ char **owners = NULL;
329 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
333 if (!sd_bus_message_has_signature(m, "s"))
334 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
336 r = sd_bus_message_read(m, "s", &arg0);
338 return synthetic_reply_method_errno(m, r, NULL);
340 r = sd_bus_get_name_creds(a, arg0, 0, NULL);
341 if (r == -ESRCH || r == -ENXIO) {
342 sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
343 return synthetic_reply_method_errno(m, r, &error);
346 return synthetic_reply_method_errno(m, r, NULL);
348 r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
350 return synthetic_reply_method_errno(m, -errno, NULL);
352 name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
354 KDBUS_FOREACH(name, name_list, cmd.list_size) {
355 const char *entry_name = NULL;
356 struct kdbus_item *item;
359 KDBUS_ITEM_FOREACH(item, name, items)
360 if (item->type == KDBUS_ITEM_OWNED_NAME)
361 entry_name = item->name.name;
363 if (!streq_ptr(entry_name, arg0))
366 if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
371 r = strv_consume(&owners, n);
378 r = bus_kernel_cmd_free(a, cmd.offset);
380 return synthetic_reply_method_errno(m, r, NULL);
383 return synthetic_reply_method_errno(m, err, NULL);
385 return synthetic_reply_method_return_strv(m, owners);
387 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
390 if (!sd_bus_message_has_signature(m, "s"))
391 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
393 r = sd_bus_message_read(m, "s", &name);
395 return synthetic_reply_method_errno(m, r, NULL);
397 if (streq(name, "org.freedesktop.DBus"))
398 return synthetic_reply_method_return(m, "b", true);
400 r = sd_bus_get_name_creds(a, name, 0, NULL);
401 if (r < 0 && r != -ESRCH && r != -ENXIO)
402 return synthetic_reply_method_errno(m, r, NULL);
404 return synthetic_reply_method_return(m, "b", r >= 0);
406 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
409 if (!sd_bus_message_has_signature(m, "s"))
410 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
412 r = sd_bus_message_read(m, "s", &name);
414 return synthetic_reply_method_errno(m, r, NULL);
416 r = sd_bus_release_name(a, name);
419 return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
420 if (r == -EADDRINUSE)
421 return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
423 return synthetic_reply_method_errno(m, r, NULL);
426 set_remove(owned_names, (char*) name);
428 return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
430 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
431 if (!sd_bus_message_has_signature(m, ""))
432 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
434 r = shared_policy_reload(sp);
436 return synthetic_reply_method_errno(m, r, NULL);
438 return synthetic_reply_method_return(m, NULL);
440 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
442 uint32_t flags, param;
445 if (!sd_bus_message_has_signature(m, "su"))
446 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
448 r = sd_bus_message_read(m, "su", &name, &flags);
450 return synthetic_reply_method_errno(m, r, NULL);
456 policy = shared_policy_acquire(sp);
457 denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
458 shared_policy_release(sp, policy);
460 return synthetic_reply_method_errno(m, -EPERM, NULL);
463 if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
464 return synthetic_reply_method_errno(m, -EINVAL, NULL);
467 if (flags & BUS_NAME_ALLOW_REPLACEMENT)
468 param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
469 if (flags & BUS_NAME_REPLACE_EXISTING)
470 param |= SD_BUS_NAME_REPLACE_EXISTING;
471 if (!(flags & BUS_NAME_DO_NOT_QUEUE))
472 param |= SD_BUS_NAME_QUEUE;
474 r = set_put_strdup(owned_names, name);
476 return synthetic_reply_method_errno(m, r, NULL);
478 r = sd_bus_request_name(a, name, param);
481 return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
483 set_remove(owned_names, (char*) name);
486 return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
487 return synthetic_reply_method_errno(m, r, NULL);
493 return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
495 return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
497 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
498 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
502 if (!sd_bus_message_has_signature(m, "su"))
503 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
505 r = sd_bus_message_read(m, "su", &name, &flags);
507 return synthetic_reply_method_errno(m, r, NULL);
510 return synthetic_reply_method_errno(m, -EINVAL, NULL);
512 r = sd_bus_get_name_creds(a, name, 0, NULL);
513 if (r >= 0 || streq(name, "org.freedesktop.DBus"))
514 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
516 return synthetic_reply_method_errno(m, r, NULL);
518 r = sd_bus_message_new_method_call(
523 "org.freedesktop.DBus.Peer",
526 return synthetic_reply_method_errno(m, r, NULL);
528 r = sd_bus_send(a, msg, NULL);
530 return synthetic_reply_method_errno(m, r, NULL);
532 return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
534 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
535 _cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
536 _cleanup_strv_free_ char **args = NULL;
538 if (!sd_bus_message_has_signature(m, "a{ss}"))
539 return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
541 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
543 return synthetic_reply_method_errno(m, r, NULL);
545 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
546 _cleanup_free_ char *s = NULL;
550 r = sd_bus_message_read(m, "ss", &key, &value);
552 return synthetic_reply_method_errno(m, r, NULL);
554 s = strjoin(key, "=", value, NULL);
556 return synthetic_reply_method_errno(m, -ENOMEM, NULL);
558 r = strv_extend(&args, s);
560 return synthetic_reply_method_errno(m, r, NULL);
562 r = sd_bus_message_exit_container(m);
564 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 return synthetic_reply_method_errno(m, -EINVAL, NULL);
574 r = sd_bus_message_new_method_call(
577 "org.freedesktop.systemd1",
578 "/org/freedesktop/systemd1",
579 "org.freedesktop.systemd1.Manager",
582 return synthetic_reply_method_errno(m, r, NULL);
584 r = sd_bus_message_append_strv(msg, args);
586 return synthetic_reply_method_errno(m, r, NULL);
588 r = sd_bus_call(a, msg, 0, NULL, NULL);
590 return synthetic_reply_method_errno(m, r, NULL);
592 return synthetic_reply_method_return(m, NULL);
595 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
597 r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
599 return synthetic_reply_method_errno(m, r, &error);