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"
9 #include "homed-home-bus.h"
10 #include "homed-home.h"
12 #include "user-record-util.h"
13 #include "user-util.h"
15 static int property_get_unix_record(
18 const char *interface
,
20 sd_bus_message
*reply
,
22 sd_bus_error
*error
) {
24 Home
*h
= ASSERT_PTR(userdata
);
29 return sd_bus_message_append(
33 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
34 h
->record
? user_record_real_name(h
->record
) : NULL
,
35 h
->record
? user_record_home_directory(h
->record
) : NULL
,
36 h
->record
? user_record_shell(h
->record
) : NULL
);
39 static int property_get_state(
42 const char *interface
,
44 sd_bus_message
*reply
,
46 sd_bus_error
*error
) {
48 Home
*h
= ASSERT_PTR(userdata
);
53 return sd_bus_message_append(reply
, "s", home_state_to_string(home_get_state(h
)));
56 int bus_home_client_is_trusted(Home
*h
, sd_bus_message
*message
) {
57 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
66 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
70 r
= sd_bus_creds_get_euid(creds
, &euid
);
74 return euid
== 0 || h
->uid
== euid
;
77 int bus_home_get_record_json(
79 sd_bus_message
*message
,
81 bool *ret_incomplete
) {
83 _cleanup_(user_record_unrefp
) UserRecord
*augmented
= NULL
;
84 UserRecordLoadFlags flags
;
90 trusted
= bus_home_client_is_trusted(h
, message
);
92 log_warning_errno(trusted
, "Failed to determine whether client is trusted, assuming untrusted.");
96 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
;
98 flags
|= USER_RECORD_ALLOW_PRIVILEGED
;
100 flags
|= USER_RECORD_STRIP_PRIVILEGED
;
102 r
= home_augment_status(h
, flags
, &augmented
);
106 r
= json_variant_format(augmented
->json
, 0, ret
);
111 *ret_incomplete
= augmented
->incomplete
;
116 static int property_get_user_record(
119 const char *interface
,
120 const char *property
,
121 sd_bus_message
*reply
,
123 sd_bus_error
*error
) {
125 _cleanup_free_
char *json
= NULL
;
126 Home
*h
= ASSERT_PTR(userdata
);
133 r
= bus_home_get_record_json(h
, sd_bus_get_current_message(bus
), &json
, &incomplete
);
137 return sd_bus_message_append(reply
, "(sb)", json
, incomplete
);
140 int bus_home_method_activate(
141 sd_bus_message
*message
,
143 sd_bus_error
*error
) {
145 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
146 Home
*h
= ASSERT_PTR(userdata
);
151 r
= bus_message_read_secret(message
, &secret
, error
);
155 r
= home_activate(h
, secret
, error
);
160 assert(!h
->current_operation
);
162 /* The operation is now in process, keep track of this message so that we can later reply to it. */
163 r
= home_set_current_message(h
, message
);
170 int bus_home_method_deactivate(
171 sd_bus_message
*message
,
173 sd_bus_error
*error
) {
175 Home
*h
= ASSERT_PTR(userdata
);
180 r
= home_deactivate(h
, false, error
);
185 assert(!h
->current_operation
);
187 r
= home_set_current_message(h
, message
);
194 int bus_home_method_unregister(
195 sd_bus_message
*message
,
197 sd_bus_error
*error
) {
199 Home
*h
= ASSERT_PTR(userdata
);
204 r
= bus_verify_polkit_async(
207 "org.freedesktop.home1.remove-home",
211 &h
->manager
->polkit_registry
,
216 return 1; /* Will call us back */
218 r
= home_unregister(h
, error
);
224 /* Note that home_unregister() destroyed 'h' here, so no more accesses */
226 return sd_bus_reply_method_return(message
, NULL
);
229 int bus_home_method_realize(
230 sd_bus_message
*message
,
232 sd_bus_error
*error
) {
234 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
235 Home
*h
= ASSERT_PTR(userdata
);
240 r
= bus_message_read_secret(message
, &secret
, error
);
244 r
= bus_verify_polkit_async(
247 "org.freedesktop.home1.create-home",
251 &h
->manager
->polkit_registry
,
256 return 1; /* Will call us back */
258 r
= home_create(h
, secret
, error
);
263 assert(!h
->current_operation
);
265 h
->unregister_on_failure
= false;
267 r
= home_set_current_message(h
, message
);
274 int bus_home_method_remove(
275 sd_bus_message
*message
,
277 sd_bus_error
*error
) {
279 Home
*h
= ASSERT_PTR(userdata
);
284 r
= bus_verify_polkit_async(
287 "org.freedesktop.home1.remove-home",
291 &h
->manager
->polkit_registry
,
296 return 1; /* Will call us back */
298 r
= home_remove(h
, error
);
301 if (r
> 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */
302 return sd_bus_reply_method_return(message
, NULL
);
304 assert(!h
->current_operation
);
306 r
= home_set_current_message(h
, message
);
313 int bus_home_method_fixate(
314 sd_bus_message
*message
,
316 sd_bus_error
*error
) {
318 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
319 Home
*h
= ASSERT_PTR(userdata
);
324 r
= bus_message_read_secret(message
, &secret
, error
);
328 r
= home_fixate(h
, secret
, error
);
333 assert(!h
->current_operation
);
335 r
= home_set_current_message(h
, message
);
342 int bus_home_method_authenticate(
343 sd_bus_message
*message
,
345 sd_bus_error
*error
) {
347 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
348 Home
*h
= ASSERT_PTR(userdata
);
353 r
= bus_message_read_secret(message
, &secret
, error
);
357 r
= bus_verify_polkit_async(
360 "org.freedesktop.home1.authenticate-home",
364 &h
->manager
->polkit_registry
,
369 return 1; /* Will call us back */
371 r
= home_authenticate(h
, secret
, error
);
376 assert(!h
->current_operation
);
378 r
= home_set_current_message(h
, message
);
385 int bus_home_method_update_record(Home
*h
, sd_bus_message
*message
, UserRecord
*hr
, sd_bus_error
*error
) {
392 r
= user_record_is_supported(hr
, error
);
396 r
= bus_verify_polkit_async(
399 "org.freedesktop.home1.update-home",
403 &h
->manager
->polkit_registry
,
408 return 1; /* Will call us back */
410 r
= home_update(h
, hr
, error
);
415 assert(!h
->current_operation
);
417 r
= home_set_current_message(h
, message
);
424 int bus_home_method_update(
425 sd_bus_message
*message
,
427 sd_bus_error
*error
) {
429 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
430 Home
*h
= ASSERT_PTR(userdata
);
435 r
= bus_message_read_home_record(message
, USER_RECORD_REQUIRE_REGULAR
|USER_RECORD_REQUIRE_SECRET
|USER_RECORD_ALLOW_PRIVILEGED
|USER_RECORD_ALLOW_PER_MACHINE
|USER_RECORD_ALLOW_SIGNATURE
|USER_RECORD_PERMISSIVE
, &hr
, error
);
439 return bus_home_method_update_record(h
, message
, hr
, error
);
442 int bus_home_method_resize(
443 sd_bus_message
*message
,
445 sd_bus_error
*error
) {
447 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
448 Home
*h
= ASSERT_PTR(userdata
);
454 r
= sd_bus_message_read(message
, "t", &sz
);
458 r
= bus_message_read_secret(message
, &secret
, error
);
462 r
= bus_verify_polkit_async(
465 "org.freedesktop.home1.resize-home",
469 &h
->manager
->polkit_registry
,
474 return 1; /* Will call us back */
476 r
= home_resize(h
, sz
, secret
, /* automatic= */ false, error
);
481 assert(!h
->current_operation
);
483 r
= home_set_current_message(h
, message
);
490 int bus_home_method_change_password(
491 sd_bus_message
*message
,
493 sd_bus_error
*error
) {
495 _cleanup_(user_record_unrefp
) UserRecord
*new_secret
= NULL
, *old_secret
= NULL
;
496 Home
*h
= ASSERT_PTR(userdata
);
501 r
= bus_message_read_secret(message
, &new_secret
, error
);
505 r
= bus_message_read_secret(message
, &old_secret
, error
);
509 r
= bus_verify_polkit_async(
512 "org.freedesktop.home1.passwd-home",
516 &h
->manager
->polkit_registry
,
521 return 1; /* Will call us back */
523 r
= home_passwd(h
, new_secret
, old_secret
, error
);
528 assert(!h
->current_operation
);
530 r
= home_set_current_message(h
, message
);
537 int bus_home_method_lock(
538 sd_bus_message
*message
,
540 sd_bus_error
*error
) {
542 Home
*h
= ASSERT_PTR(userdata
);
547 r
= home_lock(h
, error
);
550 if (r
> 0) /* Done */
551 return sd_bus_reply_method_return(message
, NULL
);
553 /* The operation is now in process, keep track of this message so that we can later reply to it. */
554 assert(!h
->current_operation
);
556 r
= home_set_current_message(h
, message
);
563 int bus_home_method_unlock(
564 sd_bus_message
*message
,
566 sd_bus_error
*error
) {
568 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
569 Home
*h
= ASSERT_PTR(userdata
);
574 r
= bus_message_read_secret(message
, &secret
, error
);
578 r
= home_unlock(h
, secret
, error
);
583 assert(!h
->current_operation
);
585 /* The operation is now in process, keep track of this message so that we can later reply to it. */
586 r
= home_set_current_message(h
, message
);
593 int bus_home_method_acquire(
594 sd_bus_message
*message
,
596 sd_bus_error
*error
) {
598 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
599 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
600 _cleanup_close_
int fd
= -EBADF
;
601 int r
, please_suspend
;
602 Home
*h
= ASSERT_PTR(userdata
);
606 r
= bus_message_read_secret(message
, &secret
, error
);
610 r
= sd_bus_message_read(message
, "b", &please_suspend
);
614 /* This operation might not be something we can executed immediately, hence queue it */
615 fd
= home_create_fifo(h
, please_suspend
);
617 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
619 o
= operation_new(OPERATION_ACQUIRE
, message
);
623 o
->secret
= TAKE_PTR(secret
);
624 o
->send_fd
= TAKE_FD(fd
);
626 r
= home_schedule_operation(h
, o
, error
);
633 int bus_home_method_ref(
634 sd_bus_message
*message
,
636 sd_bus_error
*error
) {
638 _cleanup_close_
int fd
= -EBADF
;
639 Home
*h
= ASSERT_PTR(userdata
);
641 int please_suspend
, r
;
645 r
= sd_bus_message_read(message
, "b", &please_suspend
);
649 state
= home_get_state(h
);
652 return sd_bus_error_setf(error
, BUS_ERROR_HOME_ABSENT
, "Home %s is currently missing or not plugged in.", h
->user_name
);
656 return sd_bus_error_setf(error
, BUS_ERROR_HOME_NOT_ACTIVE
, "Home %s not active.", h
->user_name
);
658 return sd_bus_error_setf(error
, BUS_ERROR_HOME_LOCKED
, "Home %s is currently locked.", h
->user_name
);
660 if (HOME_STATE_IS_ACTIVE(state
))
663 return sd_bus_error_setf(error
, BUS_ERROR_HOME_BUSY
, "An operation on home %s is currently being executed.", h
->user_name
);
666 fd
= home_create_fifo(h
, please_suspend
);
668 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
670 return sd_bus_reply_method_return(message
, "h", fd
);
673 int bus_home_method_release(
674 sd_bus_message
*message
,
676 sd_bus_error
*error
) {
678 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
679 Home
*h
= ASSERT_PTR(userdata
);
684 o
= operation_new(OPERATION_RELEASE
, message
);
688 r
= home_schedule_operation(h
, o
, error
);
695 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
696 assert_cc(sizeof(uid_t
) == sizeof(uint32_t));
698 int bus_home_path(Home
*h
, char **ret
) {
701 return sd_bus_path_encode("/org/freedesktop/home1/home", h
->user_name
, ret
);
704 static int bus_home_object_find(
707 const char *interface
,
710 sd_bus_error
*error
) {
712 _cleanup_free_
char *e
= NULL
;
713 Manager
*m
= userdata
;
718 r
= sd_bus_path_decode(path
, "/org/freedesktop/home1/home", &e
);
722 if (parse_uid(e
, &uid
) >= 0)
723 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
725 h
= hashmap_get(m
->homes_by_name
, e
);
733 static int bus_home_node_enumerator(
738 sd_bus_error
*error
) {
740 _cleanup_strv_free_
char **l
= NULL
;
741 Manager
*m
= userdata
;
748 l
= new0(char*, hashmap_size(m
->homes_by_uid
) + 1);
752 HASHMAP_FOREACH(h
, m
->homes_by_uid
) {
753 r
= bus_home_path(h
, l
+ k
);
760 *nodes
= TAKE_PTR(l
);
764 const sd_bus_vtable home_vtable
[] = {
765 SD_BUS_VTABLE_START(0),
767 SD_BUS_PROPERTY("UserName", "s",
768 NULL
, offsetof(Home
, user_name
),
769 SD_BUS_VTABLE_PROPERTY_CONST
),
770 SD_BUS_PROPERTY("UID", "u",
771 NULL
, offsetof(Home
, uid
),
772 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
773 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
774 property_get_unix_record
, 0,
775 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
776 SD_BUS_PROPERTY("State", "s",
777 property_get_state
, 0,
779 SD_BUS_PROPERTY("UserRecord", "(sb)",
780 property_get_user_record
, 0,
781 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
|SD_BUS_VTABLE_SENSITIVE
),
783 SD_BUS_METHOD_WITH_ARGS("Activate",
784 SD_BUS_ARGS("s", secret
),
786 bus_home_method_activate
,
787 SD_BUS_VTABLE_SENSITIVE
),
788 SD_BUS_METHOD("Deactivate", NULL
, NULL
, bus_home_method_deactivate
, 0),
789 SD_BUS_METHOD("Unregister", NULL
, NULL
, bus_home_method_unregister
, SD_BUS_VTABLE_UNPRIVILEGED
),
790 SD_BUS_METHOD_WITH_ARGS("Realize",
791 SD_BUS_ARGS("s", secret
),
793 bus_home_method_realize
,
794 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
796 SD_BUS_METHOD("Remove", NULL
, NULL
, bus_home_method_remove
, SD_BUS_VTABLE_UNPRIVILEGED
),
797 SD_BUS_METHOD_WITH_ARGS("Fixate",
798 SD_BUS_ARGS("s", secret
),
800 bus_home_method_fixate
,
801 SD_BUS_VTABLE_SENSITIVE
),
802 SD_BUS_METHOD_WITH_ARGS("Authenticate",
803 SD_BUS_ARGS("s", secret
),
805 bus_home_method_authenticate
,
806 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
807 SD_BUS_METHOD_WITH_ARGS("Update",
808 SD_BUS_ARGS("s", user_record
),
810 bus_home_method_update
,
811 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
812 SD_BUS_METHOD_WITH_ARGS("Resize",
813 SD_BUS_ARGS("t", size
, "s", secret
),
815 bus_home_method_resize
,
816 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
817 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
818 SD_BUS_ARGS("s", new_secret
, "s", old_secret
),
820 bus_home_method_change_password
,
821 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
822 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_home_method_lock
, 0),
823 SD_BUS_METHOD_WITH_ARGS("Unlock",
824 SD_BUS_ARGS("s", secret
),
826 bus_home_method_unlock
,
827 SD_BUS_VTABLE_SENSITIVE
),
828 SD_BUS_METHOD_WITH_ARGS("Acquire",
829 SD_BUS_ARGS("s", secret
, "b", please_suspend
),
830 SD_BUS_RESULT("h", send_fd
),
831 bus_home_method_acquire
,
832 SD_BUS_VTABLE_SENSITIVE
),
833 SD_BUS_METHOD_WITH_ARGS("Ref",
834 SD_BUS_ARGS("b", please_suspend
),
835 SD_BUS_RESULT("h", send_fd
),
838 SD_BUS_METHOD("Release", NULL
, NULL
, bus_home_method_release
, 0),
842 const BusObjectImplementation home_object
= {
843 "/org/freedesktop/home1/home",
844 "org.freedesktop.home1.Home",
845 .fallback_vtables
= BUS_FALLBACK_VTABLES({home_vtable
, bus_home_object_find
}),
846 .node_enumerator
= bus_home_node_enumerator
,
850 static int on_deferred_change(sd_event_source
*s
, void *userdata
) {
851 _cleanup_free_
char *path
= NULL
;
852 Home
*h
= ASSERT_PTR(userdata
);
855 h
->deferred_change_event_source
= sd_event_source_disable_unref(h
->deferred_change_event_source
);
857 r
= bus_home_path(h
, &path
);
859 log_warning_errno(r
, "Failed to generate home bus path, ignoring: %m");
864 r
= sd_bus_emit_properties_changed_strv(h
->manager
->bus
, path
, "org.freedesktop.home1.Home", NULL
);
866 r
= sd_bus_emit_object_added(h
->manager
->bus
, path
);
868 log_warning_errno(r
, "Failed to send home change event, ignoring: %m");
875 int bus_home_emit_change(Home
*h
) {
880 if (h
->deferred_change_event_source
)
883 if (!h
->manager
->event
)
886 if (IN_SET(sd_event_get_state(h
->manager
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
889 r
= sd_event_add_defer(h
->manager
->event
, &h
->deferred_change_event_source
, on_deferred_change
, h
);
891 return log_error_errno(r
, "Failed to allocate deferred change event source: %m");
893 r
= sd_event_source_set_priority(h
->deferred_change_event_source
, SD_EVENT_PRIORITY_IDLE
+5);
895 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
897 (void) sd_event_source_set_description(h
->deferred_change_event_source
, "deferred-change-event");
901 int bus_home_emit_remove(Home
*h
) {
902 _cleanup_free_
char *path
= NULL
;
913 if (!h
->manager
->bus
)
916 r
= bus_home_path(h
, &path
);
920 r
= sd_bus_emit_object_removed(h
->manager
->bus
, path
);
924 h
->announced
= false;