2 This file is part of systemd.
4 Copyright 2013 Daniel Mack
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.
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.
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/>.
28 #include <sys/socket.h>
30 #include <sys/timex.h>
31 #include <sys/utsname.h>
36 #include "bus-internal.h"
37 #include "sd-daemon.h"
39 #include "event-util.h"
41 #include "bus-error.h"
42 #include "bus-message.h"
43 #include "bus-kernel.h"
44 #include "socket-util.h"
52 #include "unit-name.h"
53 #include "bus-control.h"
55 #define CLIENTS_MAX 1024
56 #define MATCHES_MAX 1024
58 typedef struct Match Match
;
59 typedef struct Client Client
;
60 typedef struct Context Context
;
66 LIST_FIELDS(Match
, matches
);
84 static void match_free(Match
*m
) {
92 first
= hashmap_get(m
->client
->matches
, m
->match
);
93 LIST_REMOVE(matches
, first
, m
);
95 assert_se(hashmap_replace(m
->client
->matches
, m
->match
, first
) >= 0);
97 hashmap_remove(m
->client
->matches
, m
->match
);
99 m
->client
->n_matches
--;
106 static int match_new(Client
*c
, struct bus_match_component
*components
, unsigned n_components
, Match
**_m
) {
113 r
= hashmap_ensure_allocated(&c
->matches
, string_hash_func
, string_compare_func
);
121 m
->match
= bus_match_to_string(components
, n_components
);
127 m
->cookie
= ++c
->next_cookie
;
129 first
= hashmap_get(c
->matches
, m
->match
);
130 LIST_PREPEND(matches
, first
, m
);
131 r
= hashmap_replace(c
->matches
, m
->match
, first
);
133 LIST_REMOVE(matches
, first
, m
);
150 static int on_name_owner_changed(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
);
152 static void client_free(Client
*c
) {
160 sd_bus_remove_match(c
->context
->bus
, c
->watch
, on_name_owner_changed
, c
);
162 assert_se(hashmap_remove(c
->context
->clients
, &c
->id
) == c
);
165 while ((m
= hashmap_first(c
->matches
)))
168 hashmap_free(c
->matches
);
174 static int on_name_owner_changed(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
175 Client
*c
= userdata
;
184 static int client_acquire(Context
*context
, uint64_t id
, Client
**_c
) {
192 c
= hashmap_get(context
->clients
, &id
);
198 if (hashmap_size(context
->clients
) >= CLIENTS_MAX
)
201 r
= hashmap_ensure_allocated(&context
->clients
, uint64_hash_func
, uint64_compare_func
);
211 r
= hashmap_put(context
->clients
, &c
->id
, c
);
215 c
->context
= context
;
219 "sender='org.freedesktop.DBus',"
220 "path='/org/freedesktop/DBus',"
221 "interface='org.freedesktop.DBus',"
222 "member='NameOwnerChanged',"
223 "arg0=':1.%llu'", (unsigned long long) id
) < 0) {
228 r
= sd_bus_add_match(context
->bus
, watch
, on_name_owner_changed
, c
);
244 static int driver_add_match(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
246 struct bus_match_component
*components
= NULL
;
247 Context
*context
= userdata
;
248 unsigned n_components
= 0;
259 r
= sd_bus_message_read(message
, "s", &arg0
);
263 r
= bus_kernel_parse_unique_name(message
->sender
, &id
);
267 r
= client_acquire(context
, id
, &c
);
269 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Reached limit of %u clients", CLIENTS_MAX
);
273 if (c
->n_matches
>= MATCHES_MAX
) {
274 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Reached limit of %u matches per client", MATCHES_MAX
);
278 r
= bus_match_parse(arg0
, &components
, &n_components
);
280 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_MATCH_RULE_INVALID
, "Match rule \"%s\" is not valid", arg0
);
284 r
= match_new(c
, components
, n_components
, &m
);
288 r
= bus_add_match_internal_kernel(bus
, id
, components
, n_components
, m
->cookie
);
292 bus_match_parse_free(components
, n_components
);
294 return sd_bus_reply_method_return(message
, NULL
);
297 bus_match_parse_free(components
, n_components
);
301 if (c
->n_matches
<= 0)
307 static int driver_remove_match(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
309 struct bus_match_component
*components
= NULL
;
310 _cleanup_free_
char *normalized
= NULL
;
311 Context
*context
= userdata
;
312 unsigned n_components
= 0;
323 r
= sd_bus_message_read(message
, "s", &arg0
);
327 r
= bus_kernel_parse_unique_name(message
->sender
, &id
);
331 c
= hashmap_get(context
->clients
, &id
);
333 return sd_bus_error_setf(error
, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND
, "You have not registered any matches.");
335 r
= bus_match_parse(arg0
, &components
, &n_components
);
337 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_MATCH_RULE_INVALID
, "Match rule \"%s\" is not valid", arg0
);
341 normalized
= bus_match_to_string(components
, n_components
);
347 m
= hashmap_get(c
->matches
, normalized
);
349 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND
, "Match rule \"%s\" not found.");
353 bus_remove_match_internal_kernel(bus
, id
, m
->cookie
);
356 r
= sd_bus_reply_method_return(message
, NULL
);
359 bus_match_parse_free(components
, n_components
);
361 if (c
->n_matches
<= 0)
367 static int get_creds(sd_bus
*bus
, sd_bus_message
*m
, uint64_t mask
, sd_bus_creds
**_creds
, sd_bus_error
*error
) {
368 _cleanup_bus_creds_unref_ sd_bus_creds
*c
= NULL
;
376 r
= sd_bus_message_read(m
, "s", &name
);
380 assert_return(service_name_is_valid(name
), -EINVAL
);
382 r
= sd_bus_get_owner(bus
, name
, mask
, &c
);
383 if (r
== -ENOENT
|| r
== -ENXIO
)
384 return sd_bus_error_setf(error
, SD_BUS_ERROR_NAME_HAS_NO_OWNER
, "Name %s is currently not owned by anyone.", name
);
388 if ((c
->mask
& mask
) != mask
)
397 static int driver_get_security_context(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
398 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
399 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
402 r
= get_creds(bus
, m
, SD_BUS_CREDS_SELINUX_CONTEXT
, &creds
, error
);
406 r
= sd_bus_message_new_method_return(m
, &reply
);
410 r
= sd_bus_message_append_array(reply
, 'y', creds
->label
, strlen(creds
->label
));
414 return sd_bus_send(bus
, reply
, NULL
);
417 static int driver_get_pid(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
418 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
421 r
= get_creds(bus
, m
, SD_BUS_CREDS_PID
, &creds
, error
);
425 return sd_bus_reply_method_return(m
, "u", (uint32_t) creds
->pid
);
428 static int driver_get_user(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
429 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
432 r
= get_creds(bus
, m
, SD_BUS_CREDS_UID
, &creds
, error
);
436 return sd_bus_reply_method_return(m
, "u", (uint32_t) creds
->uid
);
439 static int driver_get_name_owner(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
440 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
443 r
= get_creds(bus
, m
, SD_BUS_CREDS_UNIQUE_NAME
, &creds
, error
);
447 return sd_bus_reply_method_return(m
, "s", creds
->unique_name
);
450 static int driver_get_id(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
451 sd_id128_t server_id
;
452 char buf
[SD_ID128_STRING_MAX
];
455 r
= sd_bus_get_server_id(bus
, &server_id
);
459 return sd_bus_reply_method_return(m
, "s", sd_id128_to_string(server_id
, buf
));
462 static int driver_hello(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
463 return sd_bus_reply_method_return(m
, "s", m
->sender
);
466 static int return_strv(sd_bus
*bus
, sd_bus_message
*m
, char **l
) {
467 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
470 r
= sd_bus_message_new_method_return(m
, &reply
);
474 r
= sd_bus_message_append_strv(reply
, l
);
478 return sd_bus_send(bus
, reply
, NULL
);
481 static int driver_list_names(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
482 _cleanup_strv_free_
char **names
= NULL
;
485 r
= sd_bus_list_names(bus
, &names
, NULL
);
489 /* Let's sort the names list to make it stable */
492 return return_strv(bus
, m
, names
);
495 static int driver_list_activatable_names(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
496 _cleanup_strv_free_
char **names
= NULL
;
499 r
= sd_bus_list_names(bus
, NULL
, &names
);
503 /* Let's sort the names list to make it stable */
506 return return_strv(bus
, m
, names
);
509 static int driver_list_queued_owners(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
510 struct kdbus_cmd_name_list cmd
= {};
511 struct kdbus_name_list
*name_list
;
512 struct kdbus_cmd_name
*name
;
513 _cleanup_strv_free_
char **owners
= NULL
;
517 r
= sd_bus_message_read(m
, "s", &arg0
);
521 assert_return(service_name_is_valid(arg0
), -EINVAL
);
523 cmd
.flags
= KDBUS_NAME_LIST_QUEUED
;
525 r
= ioctl(bus
->input_fd
, KDBUS_CMD_NAME_LIST
, &cmd
);
529 name_list
= (struct kdbus_name_list
*) ((uint8_t *) bus
->kdbus_buffer
+ cmd
.offset
);
531 KDBUS_ITEM_FOREACH(name
, name_list
, names
) {
534 if (name
->size
<= sizeof(*name
))
537 if (!streq(name
->name
, arg0
))
540 if (asprintf(&n
, ":1.%llu", (unsigned long long) name
->owner_id
) < 0)
543 r
= strv_push(&owners
, n
);
550 r
= ioctl(bus
->input_fd
, KDBUS_CMD_FREE
, &cmd
.offset
);
554 return return_strv(bus
, m
, owners
);
557 static int driver_name_has_owner(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
561 r
= sd_bus_message_read(m
, "s", &name
);
565 assert_return(service_name_is_valid(name
), -EINVAL
);
567 r
= sd_bus_get_owner(bus
, name
, 0, NULL
);
568 if (r
< 0 && r
!= -ENOENT
&& r
!= -ENXIO
)
571 return sd_bus_reply_method_return(m
, "b", r
>= 0);
574 static int driver_request_name(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
575 struct kdbus_cmd_name
*n
;
582 r
= sd_bus_message_read(m
, "su", &name
, &flags
);
586 assert_return(service_name_is_valid(name
), -EINVAL
);
587 assert_return((flags
& ~(BUS_NAME_ALLOW_REPLACEMENT
|BUS_NAME_REPLACE_EXISTING
|BUS_NAME_DO_NOT_QUEUE
)) == 0, -EINVAL
);
590 size
= offsetof(struct kdbus_cmd_name
, name
) + l
+ 1;
593 memcpy(n
->name
, name
, l
+1);
594 kdbus_translate_request_name_flags(flags
, (uint64_t *) &n
->flags
);
596 /* This function is open-coded because we request the name 'on behalf'
597 * of the requesting connection */
598 r
= bus_kernel_parse_unique_name(m
->sender
, &id
);
604 r
= ioctl(bus
->input_fd
, KDBUS_CMD_NAME_ACQUIRE
, n
);
607 return sd_bus_reply_method_return(m
, "u", BUS_NAME_EXISTS
);
608 if (errno
== EALREADY
)
609 return sd_bus_reply_method_return(m
, "u", BUS_NAME_ALREADY_OWNER
);
614 if (n
->flags
& KDBUS_NAME_IN_QUEUE
)
615 return sd_bus_reply_method_return(m
, "u", BUS_NAME_IN_QUEUE
);
617 return sd_bus_reply_method_return(m
, "u", BUS_NAME_PRIMARY_OWNER
);
620 static int driver_release_name(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
621 struct kdbus_cmd_name
*n
;
627 r
= sd_bus_message_read(m
, "s", &name
);
631 assert_return(service_name_is_valid(name
), -EINVAL
);
634 size
= offsetof(struct kdbus_cmd_name
, name
) + l
+ 1;
637 memcpy(n
->name
, name
, l
+1);
639 /* This function is open-coded because we request the name 'on behalf'
640 * of the requesting connection */
641 r
= bus_kernel_parse_unique_name(m
->sender
, &id
);
647 r
= ioctl(bus
->input_fd
, KDBUS_CMD_NAME_RELEASE
, n
);
650 return sd_bus_reply_method_return(m
, "u", BUS_NAME_NON_EXISTENT
);
651 if (errno
== EADDRINUSE
)
652 return sd_bus_reply_method_return(m
, "u", BUS_NAME_NOT_OWNER
);
656 return sd_bus_reply_method_return(m
, "u", BUS_NAME_RELEASED
);
659 static int driver_start_service_by_name(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
660 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
661 _cleanup_strv_free_
char **t
= NULL
;
662 _cleanup_free_
char *path
= NULL
;
667 r
= sd_bus_message_read(m
, "su", &name
, &flags
);
671 assert_return(service_name_is_valid(name
), -EINVAL
);
672 assert_return(flags
== 0, -ENOTSUP
);
674 r
= sd_bus_get_owner(bus
, name
, 0, NULL
);
676 return sd_bus_reply_method_return(m
, "u", BUS_START_REPLY_ALREADY_RUNNING
);
680 u
= strappenda(name
, ".busname");
682 path
= unit_dbus_path_from_name(u
);
686 r
= sd_bus_get_property_strv(
688 "org.freedesktop.systemd1",
690 "org.freedesktop.systemd1.Unit",
697 if (!t
|| !t
[0] || t
[1])
700 r
= sd_bus_call_method(
702 "org.freedesktop.systemd1",
703 "/org/freedesktop/systemd1",
704 "org.freedesktop.systemd1.Manager",
714 return sd_bus_reply_method_return(m
, "u", BUS_START_REPLY_SUCCESS
);
717 static int driver_unsupported(sd_bus
*bus
, sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
718 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "%s() is not supported", sd_bus_message_get_member(m
));
721 static const sd_bus_vtable driver_vtable
[] = {
722 SD_BUS_VTABLE_START(0),
723 SD_BUS_METHOD("AddMatch", "s", NULL
, driver_add_match
, SD_BUS_VTABLE_UNPRIVILEGED
),
724 SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_context
, SD_BUS_VTABLE_UNPRIVILEGED
),
725 SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid
, SD_BUS_VTABLE_UNPRIVILEGED
),
726 SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user
, SD_BUS_VTABLE_UNPRIVILEGED
),
727 SD_BUS_METHOD("GetId", NULL
, "s", driver_get_id
, SD_BUS_VTABLE_UNPRIVILEGED
),
728 SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner
, SD_BUS_VTABLE_UNPRIVILEGED
),
729 SD_BUS_METHOD("Hello", NULL
, "s", driver_hello
, SD_BUS_VTABLE_UNPRIVILEGED
),
730 SD_BUS_METHOD("ListActivatableNames", NULL
, "as", driver_list_activatable_names
, SD_BUS_VTABLE_UNPRIVILEGED
),
731 SD_BUS_METHOD("ListNames", NULL
, "as", driver_list_names
, SD_BUS_VTABLE_UNPRIVILEGED
),
732 SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners
, SD_BUS_VTABLE_UNPRIVILEGED
),
733 SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner
, SD_BUS_VTABLE_UNPRIVILEGED
),
734 SD_BUS_METHOD("ReleaseName", "s", "u", driver_release_name
, SD_BUS_VTABLE_UNPRIVILEGED
),
735 SD_BUS_METHOD("ReloadConfig", NULL
, NULL
, driver_unsupported
, SD_BUS_VTABLE_DEPRECATED
),
736 SD_BUS_METHOD("RemoveMatch", "s", NULL
, driver_remove_match
, SD_BUS_VTABLE_UNPRIVILEGED
),
737 SD_BUS_METHOD("RequestName", "su", "u", driver_request_name
, SD_BUS_VTABLE_UNPRIVILEGED
),
738 SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name
, SD_BUS_VTABLE_UNPRIVILEGED
),
739 SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL
, driver_unsupported
, SD_BUS_VTABLE_DEPRECATED
),
740 SD_BUS_SIGNAL("NameAcquired", "s", SD_BUS_VTABLE_DEPRECATED
),
741 SD_BUS_SIGNAL("NameLost", "s", SD_BUS_VTABLE_DEPRECATED
),
742 SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
746 static int connect_bus(Context
*c
) {
751 r
= sd_bus_default_system(&c
->bus
);
753 log_error("Failed to create bus: %s", strerror(-r
));
757 if (!c
->bus
->is_kernel
) {
758 log_error("Not running on kdbus");
762 r
= sd_bus_add_object_vtable(c
->bus
, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable
, c
);
764 log_error("Failed to add manager object vtable: %s", strerror(-r
));
768 r
= sd_bus_request_name(c
->bus
, "org.freedesktop.DBus", 0);
770 log_error("Unable to request name: %s", strerror(-r
));
774 r
= sd_bus_attach_event(c
->bus
, c
->event
, 0);
776 log_error("Error while adding bus to event loop: %s", strerror(-r
));
783 static bool check_idle(void *userdata
) {
784 Context
*c
= userdata
;
787 return hashmap_isempty(c
->clients
);
790 int main(int argc
, char *argv
[]) {
791 Context context
= {};
795 log_set_target(LOG_TARGET_AUTO
);
796 log_parse_environment();
800 log_error("This program takes no arguments.");
805 r
= sd_event_default(&context
.event
);
807 log_error("Failed to allocate event loop: %s", strerror(-r
));
811 sd_event_set_watchdog(context
.event
, true);
813 r
= connect_bus(&context
);
817 r
= bus_event_loop_with_idle(context
.event
, context
.bus
, "org.freedesktop.DBus", DEFAULT_EXIT_USEC
, check_idle
, &context
);
819 log_error("Failed to run event loop: %s", strerror(-r
));
824 while ((c
= hashmap_first(context
.clients
)))
827 sd_bus_unref(context
.bus
);
828 sd_event_unref(context
.event
);
830 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;