1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/capability.h>
5 #include "bus-common-errors.h"
6 #include "bus-polkit.h"
8 #include "format-util.h"
10 #include "homed-bus.h"
11 #include "homed-home-bus.h"
12 #include "homed-home.h"
14 #include "user-record-util.h"
15 #include "user-util.h"
17 static int property_get_unix_record(
20 const char *interface
,
22 sd_bus_message
*reply
,
24 sd_bus_error
*error
) {
26 Home
*h
= ASSERT_PTR(userdata
);
31 return sd_bus_message_append(
35 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
36 h
->record
? user_record_real_name(h
->record
) : NULL
,
37 h
->record
? user_record_home_directory(h
->record
) : NULL
,
38 h
->record
? user_record_shell(h
->record
) : NULL
);
41 static int property_get_state(
44 const char *interface
,
46 sd_bus_message
*reply
,
48 sd_bus_error
*error
) {
50 Home
*h
= ASSERT_PTR(userdata
);
55 return sd_bus_message_append(reply
, "s", home_state_to_string(home_get_state(h
)));
58 int bus_home_client_is_trusted(Home
*h
, sd_bus_message
*message
) {
59 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
68 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
72 r
= sd_bus_creds_get_euid(creds
, &euid
);
76 return euid
== 0 || h
->uid
== euid
;
79 static int home_verify_polkit_async(
81 sd_bus_message
*message
,
84 sd_bus_error
*error
) {
91 const char *details
[] = {
92 "uid", FORMAT_UID(h
->uid
),
93 "username", h
->user_name
,
97 return bus_verify_polkit_async_full(
103 &h
->manager
->polkit_registry
,
107 int bus_home_get_record_json(
109 sd_bus_message
*message
,
111 bool *ret_incomplete
) {
113 _cleanup_(user_record_unrefp
) UserRecord
*augmented
= NULL
;
114 UserRecordLoadFlags flags
;
120 trusted
= bus_home_client_is_trusted(h
, message
);
122 log_warning_errno(trusted
, "Failed to determine whether client is trusted, assuming untrusted.");
126 flags
= USER_RECORD_REQUIRE_REGULAR
|USER_RECORD_ALLOW_PER_MACHINE
|USER_RECORD_ALLOW_BINDING
|USER_RECORD_STRIP_SECRET
|USER_RECORD_ALLOW_STATUS
|USER_RECORD_ALLOW_SIGNATURE
|USER_RECORD_PERMISSIVE
;
128 flags
|= USER_RECORD_ALLOW_PRIVILEGED
;
130 flags
|= USER_RECORD_STRIP_PRIVILEGED
;
132 r
= home_augment_status(h
, flags
, &augmented
);
136 r
= json_variant_format(augmented
->json
, 0, ret
);
141 *ret_incomplete
= augmented
->incomplete
;
146 static int property_get_user_record(
149 const char *interface
,
150 const char *property
,
151 sd_bus_message
*reply
,
153 sd_bus_error
*error
) {
155 _cleanup_free_
char *json
= NULL
;
156 Home
*h
= ASSERT_PTR(userdata
);
163 r
= bus_home_get_record_json(h
, sd_bus_get_current_message(bus
), &json
, &incomplete
);
167 return sd_bus_message_append(reply
, "(sb)", json
, incomplete
);
170 int bus_home_method_activate(
171 sd_bus_message
*message
,
173 sd_bus_error
*error
) {
175 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
176 Home
*h
= ASSERT_PTR(userdata
);
182 if_referenced
= endswith(sd_bus_message_get_member(message
), "IfReferenced");
184 r
= bus_verify_polkit_async_full(
186 "org.freedesktop.home1.activate-home",
190 &h
->manager
->polkit_registry
,
195 return 1; /* Will call us back */
197 r
= bus_message_read_secret(message
, &secret
, error
);
201 r
= home_activate(h
, if_referenced
, secret
, error
);
206 assert(!h
->current_operation
);
208 /* The operation is now in process, keep track of this message so that we can later reply to it. */
209 r
= home_set_current_message(h
, message
);
216 int bus_home_method_deactivate(
217 sd_bus_message
*message
,
219 sd_bus_error
*error
) {
221 Home
*h
= ASSERT_PTR(userdata
);
226 r
= home_deactivate(h
, false, error
);
231 assert(!h
->current_operation
);
233 r
= home_set_current_message(h
, message
);
240 int bus_home_method_unregister(
241 sd_bus_message
*message
,
243 sd_bus_error
*error
) {
245 Home
*h
= ASSERT_PTR(userdata
);
250 r
= home_verify_polkit_async(
253 "org.freedesktop.home1.remove-home",
259 return 1; /* Will call us back */
261 r
= home_unregister(h
, error
);
267 /* Note that home_unregister() destroyed 'h' here, so no more accesses */
269 return sd_bus_reply_method_return(message
, NULL
);
272 int bus_home_method_realize(
273 sd_bus_message
*message
,
275 sd_bus_error
*error
) {
277 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
278 Home
*h
= ASSERT_PTR(userdata
);
283 r
= bus_message_read_secret(message
, &secret
, error
);
287 r
= home_verify_polkit_async(
290 "org.freedesktop.home1.create-home",
296 return 1; /* Will call us back */
298 r
= home_create(h
, secret
, NULL
, 0, error
);
303 assert(!h
->current_operation
);
305 h
->unregister_on_failure
= false;
307 r
= home_set_current_message(h
, message
);
314 int bus_home_method_remove(
315 sd_bus_message
*message
,
317 sd_bus_error
*error
) {
319 Home
*h
= ASSERT_PTR(userdata
);
324 r
= home_verify_polkit_async(
327 "org.freedesktop.home1.remove-home",
333 return 1; /* Will call us back */
335 r
= home_remove(h
, error
);
338 if (r
> 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */
339 return sd_bus_reply_method_return(message
, NULL
);
341 assert(!h
->current_operation
);
343 r
= home_set_current_message(h
, message
);
350 int bus_home_method_fixate(
351 sd_bus_message
*message
,
353 sd_bus_error
*error
) {
355 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
356 Home
*h
= ASSERT_PTR(userdata
);
361 r
= bus_message_read_secret(message
, &secret
, error
);
365 r
= home_fixate(h
, secret
, error
);
370 assert(!h
->current_operation
);
372 r
= home_set_current_message(h
, message
);
379 int bus_home_method_authenticate(
380 sd_bus_message
*message
,
382 sd_bus_error
*error
) {
384 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
385 Home
*h
= ASSERT_PTR(userdata
);
390 r
= bus_message_read_secret(message
, &secret
, error
);
394 r
= home_verify_polkit_async(
397 "org.freedesktop.home1.authenticate-home",
403 return 1; /* Will call us back */
405 r
= home_authenticate(h
, secret
, error
);
410 assert(!h
->current_operation
);
412 r
= home_set_current_message(h
, message
);
419 int bus_home_update_record(
421 sd_bus_message
*message
,
425 sd_bus_error
*error
) {
432 r
= user_record_is_supported(hr
, error
);
436 if ((flags
& ~SD_HOMED_UPDATE_FLAGS_ALL
) != 0)
437 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid flags provided.");
439 r
= home_verify_polkit_async(
442 "org.freedesktop.home1.update-home",
448 return 1; /* Will call us back */
450 r
= home_update(h
, hr
, blobs
, flags
, error
);
455 assert(!h
->current_operation
);
457 r
= home_set_current_message(h
, message
);
461 h
->current_operation
->call_flags
= flags
;
466 int bus_home_method_update(
467 sd_bus_message
*message
,
469 sd_bus_error
*error
) {
471 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
472 _cleanup_hashmap_free_ Hashmap
*blobs
= NULL
;
474 Home
*h
= ASSERT_PTR(userdata
);
479 r
= bus_message_read_home_record(message
, USER_RECORD_REQUIRE_REGULAR
|USER_RECORD_ALLOW_SECRET
|USER_RECORD_ALLOW_PRIVILEGED
|USER_RECORD_ALLOW_PER_MACHINE
|USER_RECORD_ALLOW_SIGNATURE
|USER_RECORD_PERMISSIVE
, &hr
, error
);
483 if (endswith(sd_bus_message_get_member(message
), "Ex")) {
484 r
= bus_message_read_blobs(message
, &blobs
, error
);
488 r
= sd_bus_message_read(message
, "t", &flags
);
493 return bus_home_update_record(h
, message
, hr
, blobs
, flags
, error
);
496 int bus_home_method_resize(
497 sd_bus_message
*message
,
499 sd_bus_error
*error
) {
501 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
502 Home
*h
= ASSERT_PTR(userdata
);
508 r
= sd_bus_message_read(message
, "t", &sz
);
512 r
= bus_message_read_secret(message
, &secret
, error
);
516 r
= home_verify_polkit_async(
519 "org.freedesktop.home1.resize-home",
525 return 1; /* Will call us back */
527 r
= home_resize(h
, sz
, secret
, error
);
532 assert(!h
->current_operation
);
534 r
= home_set_current_message(h
, message
);
541 int bus_home_method_change_password(
542 sd_bus_message
*message
,
544 sd_bus_error
*error
) {
546 _cleanup_(user_record_unrefp
) UserRecord
*new_secret
= NULL
, *old_secret
= NULL
;
547 Home
*h
= ASSERT_PTR(userdata
);
552 r
= bus_message_read_secret(message
, &new_secret
, error
);
556 r
= bus_message_read_secret(message
, &old_secret
, error
);
560 r
= home_verify_polkit_async(
563 "org.freedesktop.home1.passwd-home",
569 return 1; /* Will call us back */
571 r
= home_passwd(h
, new_secret
, old_secret
, error
);
576 assert(!h
->current_operation
);
578 r
= home_set_current_message(h
, message
);
585 int bus_home_method_lock(
586 sd_bus_message
*message
,
588 sd_bus_error
*error
) {
590 Home
*h
= ASSERT_PTR(userdata
);
595 r
= home_lock(h
, error
);
598 if (r
> 0) /* Done */
599 return sd_bus_reply_method_return(message
, NULL
);
601 /* The operation is now in process, keep track of this message so that we can later reply to it. */
602 assert(!h
->current_operation
);
604 r
= home_set_current_message(h
, message
);
611 int bus_home_method_unlock(
612 sd_bus_message
*message
,
614 sd_bus_error
*error
) {
616 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
617 Home
*h
= ASSERT_PTR(userdata
);
622 r
= bus_message_read_secret(message
, &secret
, error
);
626 r
= home_unlock(h
, secret
, error
);
631 assert(!h
->current_operation
);
633 /* The operation is now in process, keep track of this message so that we can later reply to it. */
634 r
= home_set_current_message(h
, message
);
641 int bus_home_method_acquire(
642 sd_bus_message
*message
,
644 sd_bus_error
*error
) {
646 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
647 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
648 _cleanup_close_
int fd
= -EBADF
;
649 int r
, please_suspend
;
650 Home
*h
= ASSERT_PTR(userdata
);
654 r
= bus_message_read_secret(message
, &secret
, error
);
658 r
= sd_bus_message_read(message
, "b", &please_suspend
);
662 /* This operation might not be something we can executed immediately, hence queue it */
663 fd
= home_create_fifo(h
, please_suspend
);
665 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
667 o
= operation_new(OPERATION_ACQUIRE
, message
);
671 o
->secret
= TAKE_PTR(secret
);
672 o
->send_fd
= TAKE_FD(fd
);
674 r
= home_schedule_operation(h
, o
, error
);
681 int bus_home_method_ref(
682 sd_bus_message
*message
,
684 sd_bus_error
*error
) {
686 _cleanup_close_
int fd
= -EBADF
;
687 Home
*h
= ASSERT_PTR(userdata
);
688 int please_suspend
, r
;
693 /* In unrestricted mode we'll add a reference to the home even if it's not active */
694 unrestricted
= strstr(sd_bus_message_get_member(message
), "Unrestricted");
696 r
= sd_bus_message_read(message
, "b", &please_suspend
);
703 state
= home_get_state(h
);
707 return sd_bus_error_setf(error
, BUS_ERROR_HOME_ABSENT
, "Home %s is currently missing or not plugged in.", h
->user_name
);
711 return sd_bus_error_setf(error
, BUS_ERROR_HOME_NOT_ACTIVE
, "Home %s not active.", h
->user_name
);
713 return sd_bus_error_setf(error
, BUS_ERROR_HOME_LOCKED
, "Home %s is currently locked.", h
->user_name
);
715 if (HOME_STATE_IS_ACTIVE(state
))
718 return sd_bus_error_setf(error
, BUS_ERROR_HOME_BUSY
, "An operation on home %s is currently being executed.", h
->user_name
);
722 fd
= home_create_fifo(h
, please_suspend
);
724 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
726 return sd_bus_reply_method_return(message
, "h", fd
);
729 int bus_home_method_release(
730 sd_bus_message
*message
,
732 sd_bus_error
*error
) {
734 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
735 Home
*h
= ASSERT_PTR(userdata
);
740 o
= operation_new(OPERATION_RELEASE
, message
);
744 r
= home_schedule_operation(h
, o
, error
);
751 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
752 assert_cc(sizeof(uid_t
) == sizeof(uint32_t));
754 int bus_home_path(Home
*h
, char **ret
) {
757 return sd_bus_path_encode("/org/freedesktop/home1/home", h
->user_name
, ret
);
760 static int bus_home_object_find(
763 const char *interface
,
766 sd_bus_error
*error
) {
768 _cleanup_free_
char *e
= NULL
;
769 Manager
*m
= userdata
;
774 r
= sd_bus_path_decode(path
, "/org/freedesktop/home1/home", &e
);
778 if (parse_uid(e
, &uid
) >= 0)
779 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
781 h
= hashmap_get(m
->homes_by_name
, e
);
789 static int bus_home_node_enumerator(
794 sd_bus_error
*error
) {
796 _cleanup_strv_free_
char **l
= NULL
;
797 Manager
*m
= userdata
;
804 l
= new0(char*, hashmap_size(m
->homes_by_uid
) + 1);
808 HASHMAP_FOREACH(h
, m
->homes_by_uid
) {
809 r
= bus_home_path(h
, l
+ k
);
816 *nodes
= TAKE_PTR(l
);
820 const sd_bus_vtable home_vtable
[] = {
821 SD_BUS_VTABLE_START(0),
823 SD_BUS_PROPERTY("UserName", "s",
824 NULL
, offsetof(Home
, user_name
),
825 SD_BUS_VTABLE_PROPERTY_CONST
),
826 SD_BUS_PROPERTY("UID", "u",
827 NULL
, offsetof(Home
, uid
),
828 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
829 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
830 property_get_unix_record
, 0,
831 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
832 SD_BUS_PROPERTY("State", "s",
833 property_get_state
, 0,
835 SD_BUS_PROPERTY("UserRecord", "(sb)",
836 property_get_user_record
, 0,
837 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
|SD_BUS_VTABLE_SENSITIVE
),
839 SD_BUS_METHOD_WITH_ARGS("Activate",
840 SD_BUS_ARGS("s", secret
),
842 bus_home_method_activate
,
843 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
844 SD_BUS_METHOD_WITH_ARGS("ActivateIfReferenced",
845 SD_BUS_ARGS("s", secret
),
847 bus_home_method_activate
,
848 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
849 SD_BUS_METHOD("Deactivate", NULL
, NULL
, bus_home_method_deactivate
, 0),
850 SD_BUS_METHOD("Unregister", NULL
, NULL
, bus_home_method_unregister
, SD_BUS_VTABLE_UNPRIVILEGED
),
851 SD_BUS_METHOD_WITH_ARGS("Realize",
852 SD_BUS_ARGS("s", secret
),
854 bus_home_method_realize
,
855 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
857 SD_BUS_METHOD("Remove", NULL
, NULL
, bus_home_method_remove
, SD_BUS_VTABLE_UNPRIVILEGED
),
858 SD_BUS_METHOD_WITH_ARGS("Fixate",
859 SD_BUS_ARGS("s", secret
),
861 bus_home_method_fixate
,
862 SD_BUS_VTABLE_SENSITIVE
),
863 SD_BUS_METHOD_WITH_ARGS("Authenticate",
864 SD_BUS_ARGS("s", secret
),
866 bus_home_method_authenticate
,
867 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
868 SD_BUS_METHOD_WITH_ARGS("Update",
869 SD_BUS_ARGS("s", user_record
),
871 bus_home_method_update
,
872 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
873 SD_BUS_METHOD_WITH_ARGS("UpdateEx",
874 SD_BUS_ARGS("s", user_record
, "a{sh}", blobs
, "t", flags
),
876 bus_home_method_update
,
877 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
878 SD_BUS_METHOD_WITH_ARGS("Resize",
879 SD_BUS_ARGS("t", size
, "s", secret
),
881 bus_home_method_resize
,
882 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
883 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
884 SD_BUS_ARGS("s", new_secret
, "s", old_secret
),
886 bus_home_method_change_password
,
887 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
888 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_home_method_lock
, 0),
889 SD_BUS_METHOD_WITH_ARGS("Unlock",
890 SD_BUS_ARGS("s", secret
),
892 bus_home_method_unlock
,
893 SD_BUS_VTABLE_SENSITIVE
),
894 SD_BUS_METHOD_WITH_ARGS("Acquire",
895 SD_BUS_ARGS("s", secret
, "b", please_suspend
),
896 SD_BUS_RESULT("h", send_fd
),
897 bus_home_method_acquire
,
898 SD_BUS_VTABLE_SENSITIVE
),
899 SD_BUS_METHOD_WITH_ARGS("Ref",
900 SD_BUS_ARGS("b", please_suspend
),
901 SD_BUS_RESULT("h", send_fd
),
904 SD_BUS_METHOD_WITH_ARGS("RefUnrestricted",
905 SD_BUS_ARGS("b", please_suspend
),
906 SD_BUS_RESULT("h", send_fd
),
909 SD_BUS_METHOD("Release", NULL
, NULL
, bus_home_method_release
, 0),
913 const BusObjectImplementation home_object
= {
914 "/org/freedesktop/home1/home",
915 "org.freedesktop.home1.Home",
916 .fallback_vtables
= BUS_FALLBACK_VTABLES({home_vtable
, bus_home_object_find
}),
917 .node_enumerator
= bus_home_node_enumerator
,
921 static int on_deferred_change(sd_event_source
*s
, void *userdata
) {
922 _cleanup_free_
char *path
= NULL
;
923 Home
*h
= ASSERT_PTR(userdata
);
926 h
->deferred_change_event_source
= sd_event_source_disable_unref(h
->deferred_change_event_source
);
928 r
= bus_home_path(h
, &path
);
930 log_warning_errno(r
, "Failed to generate home bus path, ignoring: %m");
935 r
= sd_bus_emit_properties_changed_strv(h
->manager
->bus
, path
, "org.freedesktop.home1.Home", NULL
);
937 r
= sd_bus_emit_object_added(h
->manager
->bus
, path
);
939 log_warning_errno(r
, "Failed to send home change event, ignoring: %m");
946 int bus_home_emit_change(Home
*h
) {
951 if (h
->deferred_change_event_source
)
954 if (!h
->manager
->event
)
957 if (IN_SET(sd_event_get_state(h
->manager
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
960 r
= sd_event_add_defer(h
->manager
->event
, &h
->deferred_change_event_source
, on_deferred_change
, h
);
962 return log_error_errno(r
, "Failed to allocate deferred change event source: %m");
964 r
= sd_event_source_set_priority(h
->deferred_change_event_source
, SD_EVENT_PRIORITY_IDLE
+5);
966 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
968 (void) sd_event_source_set_description(h
->deferred_change_event_source
, "deferred-change-event");
972 int bus_home_emit_remove(Home
*h
) {
973 _cleanup_free_
char *path
= NULL
;
984 if (!h
->manager
->bus
)
987 r
= bus_home_path(h
, &path
);
991 r
= sd_bus_emit_object_removed(h
->manager
->bus
, path
);
995 h
->announced
= false;