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(
206 "org.freedesktop.home1.remove-home",
208 &h
->manager
->polkit_registry
,
213 return 1; /* Will call us back */
215 r
= home_unregister(h
, error
);
221 /* Note that home_unregister() destroyed 'h' here, so no more accesses */
223 return sd_bus_reply_method_return(message
, NULL
);
226 int bus_home_method_realize(
227 sd_bus_message
*message
,
229 sd_bus_error
*error
) {
231 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
232 Home
*h
= ASSERT_PTR(userdata
);
237 r
= bus_message_read_secret(message
, &secret
, error
);
241 r
= bus_verify_polkit_async(
243 "org.freedesktop.home1.create-home",
245 &h
->manager
->polkit_registry
,
250 return 1; /* Will call us back */
252 r
= home_create(h
, secret
, error
);
257 assert(!h
->current_operation
);
259 h
->unregister_on_failure
= false;
261 r
= home_set_current_message(h
, message
);
268 int bus_home_method_remove(
269 sd_bus_message
*message
,
271 sd_bus_error
*error
) {
273 Home
*h
= ASSERT_PTR(userdata
);
278 r
= bus_verify_polkit_async(
280 "org.freedesktop.home1.remove-home",
282 &h
->manager
->polkit_registry
,
287 return 1; /* Will call us back */
289 r
= home_remove(h
, error
);
292 if (r
> 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */
293 return sd_bus_reply_method_return(message
, NULL
);
295 assert(!h
->current_operation
);
297 r
= home_set_current_message(h
, message
);
304 int bus_home_method_fixate(
305 sd_bus_message
*message
,
307 sd_bus_error
*error
) {
309 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
310 Home
*h
= ASSERT_PTR(userdata
);
315 r
= bus_message_read_secret(message
, &secret
, error
);
319 r
= home_fixate(h
, secret
, error
);
324 assert(!h
->current_operation
);
326 r
= home_set_current_message(h
, message
);
333 int bus_home_method_authenticate(
334 sd_bus_message
*message
,
336 sd_bus_error
*error
) {
338 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
339 Home
*h
= ASSERT_PTR(userdata
);
344 r
= bus_message_read_secret(message
, &secret
, error
);
348 r
= bus_verify_polkit_async_full(
350 "org.freedesktop.home1.authenticate-home",
352 /* interactive= */ false,
354 &h
->manager
->polkit_registry
,
359 return 1; /* Will call us back */
361 r
= home_authenticate(h
, secret
, error
);
366 assert(!h
->current_operation
);
368 r
= home_set_current_message(h
, message
);
375 int bus_home_method_update_record(Home
*h
, sd_bus_message
*message
, UserRecord
*hr
, sd_bus_error
*error
) {
382 r
= user_record_is_supported(hr
, error
);
386 r
= bus_verify_polkit_async(
388 "org.freedesktop.home1.update-home",
390 &h
->manager
->polkit_registry
,
395 return 1; /* Will call us back */
397 r
= home_update(h
, hr
, error
);
402 assert(!h
->current_operation
);
404 r
= home_set_current_message(h
, message
);
411 int bus_home_method_update(
412 sd_bus_message
*message
,
414 sd_bus_error
*error
) {
416 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
417 Home
*h
= ASSERT_PTR(userdata
);
422 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
);
426 return bus_home_method_update_record(h
, message
, hr
, error
);
429 int bus_home_method_resize(
430 sd_bus_message
*message
,
432 sd_bus_error
*error
) {
434 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
435 Home
*h
= ASSERT_PTR(userdata
);
441 r
= sd_bus_message_read(message
, "t", &sz
);
445 r
= bus_message_read_secret(message
, &secret
, error
);
449 r
= bus_verify_polkit_async(
451 "org.freedesktop.home1.resize-home",
453 &h
->manager
->polkit_registry
,
458 return 1; /* Will call us back */
460 r
= home_resize(h
, sz
, secret
, /* automatic= */ false, error
);
465 assert(!h
->current_operation
);
467 r
= home_set_current_message(h
, message
);
474 int bus_home_method_change_password(
475 sd_bus_message
*message
,
477 sd_bus_error
*error
) {
479 _cleanup_(user_record_unrefp
) UserRecord
*new_secret
= NULL
, *old_secret
= NULL
;
480 Home
*h
= ASSERT_PTR(userdata
);
485 r
= bus_message_read_secret(message
, &new_secret
, error
);
489 r
= bus_message_read_secret(message
, &old_secret
, error
);
493 r
= bus_verify_polkit_async_full(
495 "org.freedesktop.home1.passwd-home",
497 /* interactive= */ false,
499 &h
->manager
->polkit_registry
,
504 return 1; /* Will call us back */
506 r
= home_passwd(h
, new_secret
, old_secret
, error
);
511 assert(!h
->current_operation
);
513 r
= home_set_current_message(h
, message
);
520 int bus_home_method_lock(
521 sd_bus_message
*message
,
523 sd_bus_error
*error
) {
525 Home
*h
= ASSERT_PTR(userdata
);
530 r
= home_lock(h
, error
);
533 if (r
> 0) /* Done */
534 return sd_bus_reply_method_return(message
, NULL
);
536 /* The operation is now in process, keep track of this message so that we can later reply to it. */
537 assert(!h
->current_operation
);
539 r
= home_set_current_message(h
, message
);
546 int bus_home_method_unlock(
547 sd_bus_message
*message
,
549 sd_bus_error
*error
) {
551 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
552 Home
*h
= ASSERT_PTR(userdata
);
557 r
= bus_message_read_secret(message
, &secret
, error
);
561 r
= home_unlock(h
, secret
, error
);
566 assert(!h
->current_operation
);
568 /* The operation is now in process, keep track of this message so that we can later reply to it. */
569 r
= home_set_current_message(h
, message
);
576 int bus_home_method_acquire(
577 sd_bus_message
*message
,
579 sd_bus_error
*error
) {
581 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
582 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
583 _cleanup_close_
int fd
= -EBADF
;
584 int r
, please_suspend
;
585 Home
*h
= ASSERT_PTR(userdata
);
589 r
= bus_message_read_secret(message
, &secret
, error
);
593 r
= sd_bus_message_read(message
, "b", &please_suspend
);
597 /* This operation might not be something we can executed immediately, hence queue it */
598 fd
= home_create_fifo(h
, please_suspend
);
600 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
602 o
= operation_new(OPERATION_ACQUIRE
, message
);
606 o
->secret
= TAKE_PTR(secret
);
607 o
->send_fd
= TAKE_FD(fd
);
609 r
= home_schedule_operation(h
, o
, error
);
616 int bus_home_method_ref(
617 sd_bus_message
*message
,
619 sd_bus_error
*error
) {
621 _cleanup_close_
int fd
= -EBADF
;
622 Home
*h
= ASSERT_PTR(userdata
);
624 int please_suspend
, r
;
628 r
= sd_bus_message_read(message
, "b", &please_suspend
);
632 state
= home_get_state(h
);
635 return sd_bus_error_setf(error
, BUS_ERROR_HOME_ABSENT
, "Home %s is currently missing or not plugged in.", h
->user_name
);
639 return sd_bus_error_setf(error
, BUS_ERROR_HOME_NOT_ACTIVE
, "Home %s not active.", h
->user_name
);
641 return sd_bus_error_setf(error
, BUS_ERROR_HOME_LOCKED
, "Home %s is currently locked.", h
->user_name
);
643 if (HOME_STATE_IS_ACTIVE(state
))
646 return sd_bus_error_setf(error
, BUS_ERROR_HOME_BUSY
, "An operation on home %s is currently being executed.", h
->user_name
);
649 fd
= home_create_fifo(h
, please_suspend
);
651 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
653 return sd_bus_reply_method_return(message
, "h", fd
);
656 int bus_home_method_release(
657 sd_bus_message
*message
,
659 sd_bus_error
*error
) {
661 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
662 Home
*h
= ASSERT_PTR(userdata
);
667 o
= operation_new(OPERATION_RELEASE
, message
);
671 r
= home_schedule_operation(h
, o
, error
);
678 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
679 assert_cc(sizeof(uid_t
) == sizeof(uint32_t));
681 int bus_home_path(Home
*h
, char **ret
) {
684 return sd_bus_path_encode("/org/freedesktop/home1/home", h
->user_name
, ret
);
687 static int bus_home_object_find(
690 const char *interface
,
693 sd_bus_error
*error
) {
695 _cleanup_free_
char *e
= NULL
;
696 Manager
*m
= userdata
;
701 r
= sd_bus_path_decode(path
, "/org/freedesktop/home1/home", &e
);
705 if (parse_uid(e
, &uid
) >= 0)
706 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
708 h
= hashmap_get(m
->homes_by_name
, e
);
716 static int bus_home_node_enumerator(
721 sd_bus_error
*error
) {
723 _cleanup_strv_free_
char **l
= NULL
;
724 Manager
*m
= userdata
;
731 l
= new0(char*, hashmap_size(m
->homes_by_uid
) + 1);
735 HASHMAP_FOREACH(h
, m
->homes_by_uid
) {
736 r
= bus_home_path(h
, l
+ k
);
743 *nodes
= TAKE_PTR(l
);
747 const sd_bus_vtable home_vtable
[] = {
748 SD_BUS_VTABLE_START(0),
750 SD_BUS_PROPERTY("UserName", "s",
751 NULL
, offsetof(Home
, user_name
),
752 SD_BUS_VTABLE_PROPERTY_CONST
),
753 SD_BUS_PROPERTY("UID", "u",
754 NULL
, offsetof(Home
, uid
),
755 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
756 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
757 property_get_unix_record
, 0,
758 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
759 SD_BUS_PROPERTY("State", "s",
760 property_get_state
, 0,
762 SD_BUS_PROPERTY("UserRecord", "(sb)",
763 property_get_user_record
, 0,
764 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
|SD_BUS_VTABLE_SENSITIVE
),
766 SD_BUS_METHOD_WITH_ARGS("Activate",
767 SD_BUS_ARGS("s", secret
),
769 bus_home_method_activate
,
770 SD_BUS_VTABLE_SENSITIVE
),
771 SD_BUS_METHOD("Deactivate", NULL
, NULL
, bus_home_method_deactivate
, 0),
772 SD_BUS_METHOD("Unregister", NULL
, NULL
, bus_home_method_unregister
, SD_BUS_VTABLE_UNPRIVILEGED
),
773 SD_BUS_METHOD_WITH_ARGS("Realize",
774 SD_BUS_ARGS("s", secret
),
776 bus_home_method_realize
,
777 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
779 SD_BUS_METHOD("Remove", NULL
, NULL
, bus_home_method_remove
, SD_BUS_VTABLE_UNPRIVILEGED
),
780 SD_BUS_METHOD_WITH_ARGS("Fixate",
781 SD_BUS_ARGS("s", secret
),
783 bus_home_method_fixate
,
784 SD_BUS_VTABLE_SENSITIVE
),
785 SD_BUS_METHOD_WITH_ARGS("Authenticate",
786 SD_BUS_ARGS("s", secret
),
788 bus_home_method_authenticate
,
789 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
790 SD_BUS_METHOD_WITH_ARGS("Update",
791 SD_BUS_ARGS("s", user_record
),
793 bus_home_method_update
,
794 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
795 SD_BUS_METHOD_WITH_ARGS("Resize",
796 SD_BUS_ARGS("t", size
, "s", secret
),
798 bus_home_method_resize
,
799 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
800 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
801 SD_BUS_ARGS("s", new_secret
, "s", old_secret
),
803 bus_home_method_change_password
,
804 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
805 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_home_method_lock
, 0),
806 SD_BUS_METHOD_WITH_ARGS("Unlock",
807 SD_BUS_ARGS("s", secret
),
809 bus_home_method_unlock
,
810 SD_BUS_VTABLE_SENSITIVE
),
811 SD_BUS_METHOD_WITH_ARGS("Acquire",
812 SD_BUS_ARGS("s", secret
, "b", please_suspend
),
813 SD_BUS_RESULT("h", send_fd
),
814 bus_home_method_acquire
,
815 SD_BUS_VTABLE_SENSITIVE
),
816 SD_BUS_METHOD_WITH_ARGS("Ref",
817 SD_BUS_ARGS("b", please_suspend
),
818 SD_BUS_RESULT("h", send_fd
),
821 SD_BUS_METHOD("Release", NULL
, NULL
, bus_home_method_release
, 0),
825 const BusObjectImplementation home_object
= {
826 "/org/freedesktop/home1/home",
827 "org.freedesktop.home1.Home",
828 .fallback_vtables
= BUS_FALLBACK_VTABLES({home_vtable
, bus_home_object_find
}),
829 .node_enumerator
= bus_home_node_enumerator
,
833 static int on_deferred_change(sd_event_source
*s
, void *userdata
) {
834 _cleanup_free_
char *path
= NULL
;
835 Home
*h
= ASSERT_PTR(userdata
);
838 h
->deferred_change_event_source
= sd_event_source_disable_unref(h
->deferred_change_event_source
);
840 r
= bus_home_path(h
, &path
);
842 log_warning_errno(r
, "Failed to generate home bus path, ignoring: %m");
847 r
= sd_bus_emit_properties_changed_strv(h
->manager
->bus
, path
, "org.freedesktop.home1.Home", NULL
);
849 r
= sd_bus_emit_object_added(h
->manager
->bus
, path
);
851 log_warning_errno(r
, "Failed to send home change event, ignoring: %m");
858 int bus_home_emit_change(Home
*h
) {
863 if (h
->deferred_change_event_source
)
866 if (!h
->manager
->event
)
869 if (IN_SET(sd_event_get_state(h
->manager
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
872 r
= sd_event_add_defer(h
->manager
->event
, &h
->deferred_change_event_source
, on_deferred_change
, h
);
874 return log_error_errno(r
, "Failed to allocate deferred change event source: %m");
876 r
= sd_event_source_set_priority(h
->deferred_change_event_source
, SD_EVENT_PRIORITY_IDLE
+5);
878 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
880 (void) sd_event_source_set_description(h
->deferred_change_event_source
, "deferred-change-event");
884 int bus_home_emit_remove(Home
*h
) {
885 _cleanup_free_
char *path
= NULL
;
896 if (!h
->manager
->bus
)
899 r
= bus_home_path(h
, &path
);
903 r
= sd_bus_emit_object_removed(h
->manager
->bus
, path
);
907 h
->announced
= false;