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
) {
30 return sd_bus_message_append(
34 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
35 h
->record
? user_record_real_name(h
->record
) : NULL
,
36 h
->record
? user_record_home_directory(h
->record
) : NULL
,
37 h
->record
? user_record_shell(h
->record
) : NULL
);
40 static int property_get_state(
43 const char *interface
,
45 sd_bus_message
*reply
,
47 sd_bus_error
*error
) {
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 int bus_home_get_record_json(
81 sd_bus_message
*message
,
83 bool *ret_incomplete
) {
85 _cleanup_(user_record_unrefp
) UserRecord
*augmented
= NULL
;
86 UserRecordLoadFlags flags
;
92 trusted
= bus_home_client_is_trusted(h
, message
);
94 log_warning_errno(trusted
, "Failed to determine whether client is trusted, assuming untrusted.");
98 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
;
100 flags
|= USER_RECORD_ALLOW_PRIVILEGED
;
102 flags
|= USER_RECORD_STRIP_PRIVILEGED
;
104 r
= home_augment_status(h
, flags
, &augmented
);
108 r
= json_variant_format(augmented
->json
, 0, ret
);
113 *ret_incomplete
= augmented
->incomplete
;
118 static int property_get_user_record(
121 const char *interface
,
122 const char *property
,
123 sd_bus_message
*reply
,
125 sd_bus_error
*error
) {
127 _cleanup_free_
char *json
= NULL
;
136 r
= bus_home_get_record_json(h
, sd_bus_get_current_message(bus
), &json
, &incomplete
);
140 return sd_bus_message_append(reply
, "(sb)", json
, incomplete
);
143 int bus_home_method_activate(
144 sd_bus_message
*message
,
146 sd_bus_error
*error
) {
148 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
155 r
= bus_message_read_secret(message
, &secret
, error
);
159 r
= home_activate(h
, secret
, error
);
164 assert(!h
->current_operation
);
166 /* The operation is now in process, keep track of this message so that we can later reply to it. */
167 r
= home_set_current_message(h
, message
);
174 int bus_home_method_deactivate(
175 sd_bus_message
*message
,
177 sd_bus_error
*error
) {
185 r
= home_deactivate(h
, false, error
);
190 assert(!h
->current_operation
);
192 r
= home_set_current_message(h
, message
);
199 int bus_home_method_unregister(
200 sd_bus_message
*message
,
202 sd_bus_error
*error
) {
210 r
= bus_verify_polkit_async(
213 "org.freedesktop.home1.remove-home",
217 &h
->manager
->polkit_registry
,
222 return 1; /* Will call us back */
224 r
= home_unregister(h
, error
);
230 /* Note that home_unregister() destroyed 'h' here, so no more accesses */
232 return sd_bus_reply_method_return(message
, NULL
);
235 int bus_home_method_realize(
236 sd_bus_message
*message
,
238 sd_bus_error
*error
) {
240 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
247 r
= bus_message_read_secret(message
, &secret
, error
);
251 r
= bus_verify_polkit_async(
254 "org.freedesktop.home1.create-home",
258 &h
->manager
->polkit_registry
,
263 return 1; /* Will call us back */
265 r
= home_create(h
, secret
, error
);
270 assert(!h
->current_operation
);
272 h
->unregister_on_failure
= false;
274 r
= home_set_current_message(h
, message
);
281 int bus_home_method_remove(
282 sd_bus_message
*message
,
284 sd_bus_error
*error
) {
292 r
= bus_verify_polkit_async(
295 "org.freedesktop.home1.remove-home",
299 &h
->manager
->polkit_registry
,
304 return 1; /* Will call us back */
306 r
= home_remove(h
, error
);
309 if (r
> 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */
310 return sd_bus_reply_method_return(message
, NULL
);
312 assert(!h
->current_operation
);
314 r
= home_set_current_message(h
, message
);
321 int bus_home_method_fixate(
322 sd_bus_message
*message
,
324 sd_bus_error
*error
) {
326 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
333 r
= bus_message_read_secret(message
, &secret
, error
);
337 r
= home_fixate(h
, secret
, error
);
342 assert(!h
->current_operation
);
344 r
= home_set_current_message(h
, message
);
351 int bus_home_method_authenticate(
352 sd_bus_message
*message
,
354 sd_bus_error
*error
) {
356 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
363 r
= bus_message_read_secret(message
, &secret
, error
);
367 r
= bus_verify_polkit_async(
370 "org.freedesktop.home1.authenticate-home",
374 &h
->manager
->polkit_registry
,
379 return 1; /* Will call us back */
381 r
= home_authenticate(h
, secret
, error
);
386 assert(!h
->current_operation
);
388 r
= home_set_current_message(h
, message
);
395 int bus_home_method_update_record(Home
*h
, sd_bus_message
*message
, UserRecord
*hr
, sd_bus_error
*error
) {
402 r
= user_record_is_supported(hr
, error
);
406 r
= bus_verify_polkit_async(
409 "org.freedesktop.home1.update-home",
413 &h
->manager
->polkit_registry
,
418 return 1; /* Will call us back */
420 r
= home_update(h
, hr
, error
);
425 assert(!h
->current_operation
);
427 r
= home_set_current_message(h
, message
);
434 int bus_home_method_update(
435 sd_bus_message
*message
,
437 sd_bus_error
*error
) {
439 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
446 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
);
450 return bus_home_method_update_record(h
, message
, hr
, error
);
453 int bus_home_method_resize(
454 sd_bus_message
*message
,
456 sd_bus_error
*error
) {
458 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
466 r
= sd_bus_message_read(message
, "t", &sz
);
470 r
= bus_message_read_secret(message
, &secret
, error
);
474 r
= bus_verify_polkit_async(
477 "org.freedesktop.home1.resize-home",
481 &h
->manager
->polkit_registry
,
486 return 1; /* Will call us back */
488 r
= home_resize(h
, sz
, secret
, /* automatic= */ false, error
);
493 assert(!h
->current_operation
);
495 r
= home_set_current_message(h
, message
);
502 int bus_home_method_change_password(
503 sd_bus_message
*message
,
505 sd_bus_error
*error
) {
507 _cleanup_(user_record_unrefp
) UserRecord
*new_secret
= NULL
, *old_secret
= NULL
;
514 r
= bus_message_read_secret(message
, &new_secret
, error
);
518 r
= bus_message_read_secret(message
, &old_secret
, error
);
522 r
= bus_verify_polkit_async(
525 "org.freedesktop.home1.passwd-home",
529 &h
->manager
->polkit_registry
,
534 return 1; /* Will call us back */
536 r
= home_passwd(h
, new_secret
, old_secret
, error
);
541 assert(!h
->current_operation
);
543 r
= home_set_current_message(h
, message
);
550 int bus_home_method_lock(
551 sd_bus_message
*message
,
553 sd_bus_error
*error
) {
561 r
= home_lock(h
, error
);
564 if (r
> 0) /* Done */
565 return sd_bus_reply_method_return(message
, NULL
);
567 /* The operation is now in process, keep track of this message so that we can later reply to it. */
568 assert(!h
->current_operation
);
570 r
= home_set_current_message(h
, message
);
577 int bus_home_method_unlock(
578 sd_bus_message
*message
,
580 sd_bus_error
*error
) {
582 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
589 r
= bus_message_read_secret(message
, &secret
, error
);
593 r
= home_unlock(h
, secret
, error
);
598 assert(!h
->current_operation
);
600 /* The operation is now in process, keep track of this message so that we can later reply to it. */
601 r
= home_set_current_message(h
, message
);
608 int bus_home_method_acquire(
609 sd_bus_message
*message
,
611 sd_bus_error
*error
) {
613 _cleanup_(user_record_unrefp
) UserRecord
*secret
= NULL
;
614 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
615 _cleanup_close_
int fd
= -1;
616 int r
, please_suspend
;
622 r
= bus_message_read_secret(message
, &secret
, error
);
626 r
= sd_bus_message_read(message
, "b", &please_suspend
);
630 /* This operation might not be something we can executed immediately, hence queue it */
631 fd
= home_create_fifo(h
, please_suspend
);
633 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
635 o
= operation_new(OPERATION_ACQUIRE
, message
);
639 o
->secret
= TAKE_PTR(secret
);
640 o
->send_fd
= TAKE_FD(fd
);
642 r
= home_schedule_operation(h
, o
, error
);
649 int bus_home_method_ref(
650 sd_bus_message
*message
,
652 sd_bus_error
*error
) {
654 _cleanup_close_
int fd
= -1;
657 int please_suspend
, r
;
662 r
= sd_bus_message_read(message
, "b", &please_suspend
);
666 state
= home_get_state(h
);
669 return sd_bus_error_setf(error
, BUS_ERROR_HOME_ABSENT
, "Home %s is currently missing or not plugged in.", h
->user_name
);
673 return sd_bus_error_setf(error
, BUS_ERROR_HOME_NOT_ACTIVE
, "Home %s not active.", h
->user_name
);
675 return sd_bus_error_setf(error
, BUS_ERROR_HOME_LOCKED
, "Home %s is currently locked.", h
->user_name
);
677 if (HOME_STATE_IS_ACTIVE(state
))
680 return sd_bus_error_setf(error
, BUS_ERROR_HOME_BUSY
, "An operation on home %s is currently being executed.", h
->user_name
);
683 fd
= home_create_fifo(h
, please_suspend
);
685 return sd_bus_reply_method_errnof(message
, fd
, "Failed to allocate FIFO for %s: %m", h
->user_name
);
687 return sd_bus_reply_method_return(message
, "h", fd
);
690 int bus_home_method_release(
691 sd_bus_message
*message
,
693 sd_bus_error
*error
) {
695 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
702 o
= operation_new(OPERATION_RELEASE
, message
);
706 r
= home_schedule_operation(h
, o
, error
);
713 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
714 assert_cc(sizeof(uid_t
) == sizeof(uint32_t));
716 int bus_home_path(Home
*h
, char **ret
) {
719 return sd_bus_path_encode("/org/freedesktop/home1/home", h
->user_name
, ret
);
722 static int bus_home_object_find(
725 const char *interface
,
728 sd_bus_error
*error
) {
730 _cleanup_free_
char *e
= NULL
;
731 Manager
*m
= userdata
;
736 r
= sd_bus_path_decode(path
, "/org/freedesktop/home1/home", &e
);
740 if (parse_uid(e
, &uid
) >= 0)
741 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
743 h
= hashmap_get(m
->homes_by_name
, e
);
751 static int bus_home_node_enumerator(
756 sd_bus_error
*error
) {
758 _cleanup_strv_free_
char **l
= NULL
;
759 Manager
*m
= userdata
;
766 l
= new0(char*, hashmap_size(m
->homes_by_uid
) + 1);
770 HASHMAP_FOREACH(h
, m
->homes_by_uid
) {
771 r
= bus_home_path(h
, l
+ k
);
776 *nodes
= TAKE_PTR(l
);
780 const sd_bus_vtable home_vtable
[] = {
781 SD_BUS_VTABLE_START(0),
783 SD_BUS_PROPERTY("UserName", "s",
784 NULL
, offsetof(Home
, user_name
),
785 SD_BUS_VTABLE_PROPERTY_CONST
),
786 SD_BUS_PROPERTY("UID", "u",
787 NULL
, offsetof(Home
, uid
),
788 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
789 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
790 property_get_unix_record
, 0,
791 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
792 SD_BUS_PROPERTY("State", "s",
793 property_get_state
, 0,
795 SD_BUS_PROPERTY("UserRecord", "(sb)",
796 property_get_user_record
, 0,
797 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
|SD_BUS_VTABLE_SENSITIVE
),
799 SD_BUS_METHOD_WITH_ARGS("Activate",
800 SD_BUS_ARGS("s", secret
),
802 bus_home_method_activate
,
803 SD_BUS_VTABLE_SENSITIVE
),
804 SD_BUS_METHOD("Deactivate", NULL
, NULL
, bus_home_method_deactivate
, 0),
805 SD_BUS_METHOD("Unregister", NULL
, NULL
, bus_home_method_unregister
, SD_BUS_VTABLE_UNPRIVILEGED
),
806 SD_BUS_METHOD_WITH_ARGS("Realize",
807 SD_BUS_ARGS("s", secret
),
809 bus_home_method_realize
,
810 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
812 SD_BUS_METHOD("Remove", NULL
, NULL
, bus_home_method_remove
, SD_BUS_VTABLE_UNPRIVILEGED
),
813 SD_BUS_METHOD_WITH_ARGS("Fixate",
814 SD_BUS_ARGS("s", secret
),
816 bus_home_method_fixate
,
817 SD_BUS_VTABLE_SENSITIVE
),
818 SD_BUS_METHOD_WITH_ARGS("Authenticate",
819 SD_BUS_ARGS("s", secret
),
821 bus_home_method_authenticate
,
822 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
823 SD_BUS_METHOD_WITH_ARGS("Update",
824 SD_BUS_ARGS("s", user_record
),
826 bus_home_method_update
,
827 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
828 SD_BUS_METHOD_WITH_ARGS("Resize",
829 SD_BUS_ARGS("t", size
, "s", secret
),
831 bus_home_method_resize
,
832 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
833 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
834 SD_BUS_ARGS("s", new_secret
, "s", old_secret
),
836 bus_home_method_change_password
,
837 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
838 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_home_method_lock
, 0),
839 SD_BUS_METHOD_WITH_ARGS("Unlock",
840 SD_BUS_ARGS("s", secret
),
842 bus_home_method_unlock
,
843 SD_BUS_VTABLE_SENSITIVE
),
844 SD_BUS_METHOD_WITH_ARGS("Acquire",
845 SD_BUS_ARGS("s", secret
, "b", please_suspend
),
846 SD_BUS_RESULT("h", send_fd
),
847 bus_home_method_acquire
,
848 SD_BUS_VTABLE_SENSITIVE
),
849 SD_BUS_METHOD_WITH_ARGS("Ref",
850 SD_BUS_ARGS("b", please_suspend
),
851 SD_BUS_RESULT("h", send_fd
),
854 SD_BUS_METHOD("Release", NULL
, NULL
, bus_home_method_release
, 0),
858 const BusObjectImplementation home_object
= {
859 "/org/freedesktop/home1/home",
860 "org.freedesktop.home1.Home",
861 .fallback_vtables
= BUS_FALLBACK_VTABLES({home_vtable
, bus_home_object_find
}),
862 .node_enumerator
= bus_home_node_enumerator
,
866 static int on_deferred_change(sd_event_source
*s
, void *userdata
) {
867 _cleanup_free_
char *path
= NULL
;
873 h
->deferred_change_event_source
= sd_event_source_disable_unref(h
->deferred_change_event_source
);
875 r
= bus_home_path(h
, &path
);
877 log_warning_errno(r
, "Failed to generate home bus path, ignoring: %m");
882 r
= sd_bus_emit_properties_changed_strv(h
->manager
->bus
, path
, "org.freedesktop.home1.Home", NULL
);
884 r
= sd_bus_emit_object_added(h
->manager
->bus
, path
);
886 log_warning_errno(r
, "Failed to send home change event, ignoring: %m");
893 int bus_home_emit_change(Home
*h
) {
898 if (h
->deferred_change_event_source
)
901 if (!h
->manager
->event
)
904 if (IN_SET(sd_event_get_state(h
->manager
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
907 r
= sd_event_add_defer(h
->manager
->event
, &h
->deferred_change_event_source
, on_deferred_change
, h
);
909 return log_error_errno(r
, "Failed to allocate deferred change event source: %m");
911 r
= sd_event_source_set_priority(h
->deferred_change_event_source
, SD_EVENT_PRIORITY_IDLE
+5);
913 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
915 (void) sd_event_source_set_description(h
->deferred_change_event_source
, "deferred-change-event");
919 int bus_home_emit_remove(Home
*h
) {
920 _cleanup_free_
char *path
= NULL
;
931 if (!h
->manager
->bus
)
934 r
= bus_home_path(h
, &path
);
938 r
= sd_bus_emit_object_removed(h
->manager
->bus
, path
);
942 h
->announced
= false;