1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/capability.h>
5 #include "alloc-util.h"
6 #include "bus-common-errors.h"
7 #include "bus-polkit.h"
8 #include "format-util.h"
10 #include "homed-home-bus.h"
11 #include "homed-manager-bus.h"
12 #include "homed-manager.h"
14 #include "user-record-sign.h"
15 #include "user-record-util.h"
16 #include "user-util.h"
18 static int property_get_auto_login(
21 const char *interface
,
23 sd_bus_message
*reply
,
25 sd_bus_error
*error
) {
27 Manager
*m
= ASSERT_PTR(userdata
);
34 r
= sd_bus_message_open_container(reply
, 'a', "(sso)");
38 HASHMAP_FOREACH(h
, m
->homes_by_name
) {
39 _cleanup_strv_free_
char **seats
= NULL
;
40 _cleanup_free_
char *home_path
= NULL
;
42 r
= home_auto_login(h
, &seats
);
44 log_debug_errno(r
, "Failed to determine whether home '%s' is candidate for auto-login, ignoring: %m", h
->user_name
);
50 r
= bus_home_path(h
, &home_path
);
52 return log_error_errno(r
, "Failed to generate home bus path: %m");
54 STRV_FOREACH(s
, seats
) {
55 r
= sd_bus_message_append(reply
, "(sso)", h
->user_name
, *s
, home_path
);
61 return sd_bus_message_close_container(reply
);
64 static int lookup_user_name(
66 sd_bus_message
*message
,
67 const char *user_name
,
79 if (isempty(user_name
)) {
80 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
83 /* If an empty user name is specified, then identify caller's EUID and find home by that. */
85 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
89 r
= sd_bus_creds_get_euid(creds
, &uid
);
93 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
95 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "Client's UID " UID_FMT
" not managed.", uid
);
99 if (!valid_user_group_name(user_name
, 0))
100 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "User name %s is not valid", user_name
);
102 h
= hashmap_get(m
->homes_by_name
, user_name
);
104 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "No home for user %s known", user_name
);
111 static int method_get_home_by_name(
112 sd_bus_message
*message
,
114 sd_bus_error
*error
) {
116 _cleanup_free_
char *path
= NULL
;
117 const char *user_name
;
118 Manager
*m
= ASSERT_PTR(userdata
);
124 r
= sd_bus_message_read(message
, "s", &user_name
);
128 r
= lookup_user_name(m
, message
, user_name
, error
, &h
);
132 r
= bus_home_path(h
, &path
);
136 return sd_bus_reply_method_return(
139 home_state_to_string(home_get_state(h
)),
140 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
141 h
->record
? user_record_real_name(h
->record
) : NULL
,
142 h
->record
? user_record_home_directory(h
->record
) : NULL
,
143 h
->record
? user_record_shell(h
->record
) : NULL
,
147 static int method_get_home_by_uid(
148 sd_bus_message
*message
,
150 sd_bus_error
*error
) {
152 _cleanup_free_
char *path
= NULL
;
153 Manager
*m
= ASSERT_PTR(userdata
);
160 r
= sd_bus_message_read(message
, "u", &uid
);
163 if (!uid_is_valid(uid
))
164 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "UID " UID_FMT
" is not valid", uid
);
166 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
168 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "No home for UID " UID_FMT
" known", uid
);
170 /* Note that we don't use bus_home_path() here, but build the path manually, since if we are queried
171 * for a UID we should also generate the bus path with a UID, and bus_home_path() uses our more
172 * typical bus path by name. */
173 if (asprintf(&path
, "/org/freedesktop/home1/home/" UID_FMT
, h
->uid
) < 0)
176 return sd_bus_reply_method_return(
179 home_state_to_string(home_get_state(h
)),
180 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
181 h
->record
? user_record_real_name(h
->record
) : NULL
,
182 h
->record
? user_record_home_directory(h
->record
) : NULL
,
183 h
->record
? user_record_shell(h
->record
) : NULL
,
187 static int method_list_homes(
188 sd_bus_message
*message
,
190 sd_bus_error
*error
) {
192 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
193 Manager
*m
= ASSERT_PTR(userdata
);
199 r
= sd_bus_message_new_method_return(message
, &reply
);
203 r
= sd_bus_message_open_container(reply
, 'a', "(susussso)");
207 HASHMAP_FOREACH(h
, m
->homes_by_uid
) {
208 _cleanup_free_
char *path
= NULL
;
210 r
= bus_home_path(h
, &path
);
214 r
= sd_bus_message_append(
218 home_state_to_string(home_get_state(h
)),
219 h
->record
? (uint32_t) user_record_gid(h
->record
) : GID_INVALID
,
220 h
->record
? user_record_real_name(h
->record
) : NULL
,
221 h
->record
? user_record_home_directory(h
->record
) : NULL
,
222 h
->record
? user_record_shell(h
->record
) : NULL
,
228 r
= sd_bus_message_close_container(reply
);
232 return sd_bus_send(NULL
, reply
, NULL
);
235 static int method_get_user_record_by_name(
236 sd_bus_message
*message
,
238 sd_bus_error
*error
) {
240 _cleanup_free_
char *json
= NULL
, *path
= NULL
;
241 Manager
*m
= ASSERT_PTR(userdata
);
242 const char *user_name
;
249 r
= sd_bus_message_read(message
, "s", &user_name
);
253 r
= lookup_user_name(m
, message
, user_name
, error
, &h
);
257 r
= bus_home_get_record_json(h
, message
, &json
, &incomplete
);
261 r
= bus_home_path(h
, &path
);
265 return sd_bus_reply_method_return(
272 static int method_get_user_record_by_uid(
273 sd_bus_message
*message
,
275 sd_bus_error
*error
) {
277 _cleanup_free_
char *json
= NULL
, *path
= NULL
;
278 Manager
*m
= ASSERT_PTR(userdata
);
286 r
= sd_bus_message_read(message
, "u", &uid
);
289 if (!uid_is_valid(uid
))
290 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "UID " UID_FMT
" is not valid", uid
);
292 h
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(uid
));
294 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "No home for UID " UID_FMT
" known", uid
);
296 r
= bus_home_get_record_json(h
, message
, &json
, &incomplete
);
300 if (asprintf(&path
, "/org/freedesktop/home1/home/" UID_FMT
, h
->uid
) < 0)
303 return sd_bus_reply_method_return(
310 static int generic_home_method(
312 sd_bus_message
*message
,
313 sd_bus_message_handler_t handler
,
314 sd_bus_error
*error
) {
316 const char *user_name
;
324 r
= sd_bus_message_read(message
, "s", &user_name
);
328 r
= lookup_user_name(m
, message
, user_name
, error
, &h
);
332 return handler(message
, h
, error
);
335 static int method_activate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
336 return generic_home_method(userdata
, message
, bus_home_method_activate
, error
);
339 static int method_deactivate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
340 return generic_home_method(userdata
, message
, bus_home_method_deactivate
, error
);
343 static int validate_and_allocate_home(Manager
*m
, UserRecord
*hr
, Hashmap
*blobs
, Home
**ret
, sd_bus_error
*error
) {
344 _cleanup_(user_record_unrefp
) UserRecord
*signed_hr
= NULL
;
353 r
= user_record_is_supported(hr
, error
);
357 other
= hashmap_get(m
->homes_by_name
, hr
->user_name
);
359 return sd_bus_error_setf(error
, BUS_ERROR_USER_NAME_EXISTS
, "Specified user name %s exists already, refusing.", hr
->user_name
);
361 r
= getpwnam_malloc(hr
->user_name
, /* ret= */ NULL
);
363 return sd_bus_error_setf(error
, BUS_ERROR_USER_NAME_EXISTS
, "Specified user name %s exists in the NSS user database, refusing.", hr
->user_name
);
367 r
= getgrnam_malloc(hr
->user_name
, /* ret= */ NULL
);
369 return sd_bus_error_setf(error
, BUS_ERROR_USER_NAME_EXISTS
, "Specified user name %s conflicts with an NSS group by the same name, refusing.", hr
->user_name
);
374 const char *failed
= NULL
;
375 r
= user_record_ensure_blob_manifest(hr
, blobs
, &failed
);
377 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Provided blob files do not correspond to blob manifest.");
379 return sd_bus_error_set_errnof(error
, r
, "Failed to generate hash for blob %s: %m", strnull(failed
));
382 r
= manager_verify_user_record(m
, hr
);
385 case USER_RECORD_UNSIGNED
:
386 /* If the record is unsigned, then let's sign it with our own key */
387 r
= manager_sign_user_record(m
, hr
, &signed_hr
, error
);
394 case USER_RECORD_SIGNED_EXCLUSIVE
:
395 signed_locally
= true;
398 case USER_RECORD_SIGNED
:
399 case USER_RECORD_FOREIGN
:
400 signed_locally
= false;
404 return sd_bus_error_setf(error
, BUS_ERROR_BAD_SIGNATURE
, "Specified user record for %s is signed by a key we don't recognize, refusing.", hr
->user_name
);
407 return sd_bus_error_set_errnof(error
, r
, "Failed to validate signature for '%s': %m", hr
->user_name
);
410 if (uid_is_valid(hr
->uid
)) {
411 _cleanup_free_
struct passwd
*pw
= NULL
;
412 _cleanup_free_
struct group
*gr
= NULL
;
414 other
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(hr
->uid
));
416 return sd_bus_error_setf(error
, BUS_ERROR_UID_IN_USE
, "Specified UID " UID_FMT
" already in use by home %s, refusing.", hr
->uid
, other
->user_name
);
418 r
= getpwuid_malloc(hr
->uid
, &pw
);
420 return sd_bus_error_setf(error
, BUS_ERROR_UID_IN_USE
, "Specified UID " UID_FMT
" already in use by NSS user %s, refusing.", hr
->uid
, pw
->pw_name
);
424 r
= getgrgid_malloc(hr
->uid
, &gr
);
426 return sd_bus_error_setf(error
, BUS_ERROR_UID_IN_USE
, "Specified UID " UID_FMT
" already in use as GID by NSS group %s, refusing.", hr
->uid
, gr
->gr_name
);
430 r
= manager_augment_record_with_uid(m
, hr
);
432 return sd_bus_error_set_errnof(error
, r
, "Failed to acquire UID for '%s': %m", hr
->user_name
);
435 r
= home_new(m
, hr
, NULL
, ret
);
439 (*ret
)->signed_locally
= signed_locally
;
443 static int method_register_home(
444 sd_bus_message
*message
,
446 sd_bus_error
*error
) {
448 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
449 Manager
*m
= ASSERT_PTR(userdata
);
450 _cleanup_(home_freep
) Home
*h
= NULL
;
455 r
= bus_message_read_home_record(message
, USER_RECORD_LOAD_EMBEDDED
|USER_RECORD_PERMISSIVE
, &hr
, error
);
459 r
= bus_verify_polkit_async(
461 "org.freedesktop.home1.create-home",
468 return 1; /* Will call us back */
470 r
= validate_and_allocate_home(m
, hr
, NULL
, &h
, error
);
474 r
= home_save_record(h
);
480 return sd_bus_reply_method_return(message
, NULL
);
483 static int method_unregister_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
484 return generic_home_method(userdata
, message
, bus_home_method_unregister
, error
);
488 static int method_create_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
489 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
490 _cleanup_hashmap_free_ Hashmap
*blobs
= NULL
;
492 Manager
*m
= ASSERT_PTR(userdata
);
498 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
, &hr
, error
);
502 if (endswith(sd_bus_message_get_member(message
), "Ex")) {
503 r
= bus_message_read_blobs(message
, &blobs
, error
);
507 r
= sd_bus_message_read(message
, "t", &flags
);
511 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Provided flags are unsupported.");
514 r
= bus_verify_polkit_async(
516 "org.freedesktop.home1.create-home",
523 return 1; /* Will call us back */
525 r
= validate_and_allocate_home(m
, hr
, blobs
, &h
, error
);
529 r
= home_create(h
, hr
, blobs
, flags
, error
);
534 h
->unregister_on_failure
= true;
535 assert(!h
->current_operation
);
537 r
= home_set_current_message(h
, message
);
544 (void) home_unlink_record(h
);
549 static int method_realize_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
550 return generic_home_method(userdata
, message
, bus_home_method_realize
, error
);
553 static int method_remove_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
554 return generic_home_method(userdata
, message
, bus_home_method_remove
, error
);
557 static int method_fixate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
558 return generic_home_method(userdata
, message
, bus_home_method_fixate
, error
);
561 static int method_authenticate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
562 return generic_home_method(userdata
, message
, bus_home_method_authenticate
, error
);
565 static int method_update_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
566 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
567 _cleanup_hashmap_free_ Hashmap
*blobs
= NULL
;
569 Manager
*m
= ASSERT_PTR(userdata
);
575 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
);
579 if (endswith(sd_bus_message_get_member(message
), "Ex")) {
580 r
= bus_message_read_blobs(message
, &blobs
, error
);
584 r
= sd_bus_message_read(message
, "t", &flags
);
589 assert(hr
->user_name
);
591 h
= hashmap_get(m
->homes_by_name
, hr
->user_name
);
593 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "No home for user %s known", hr
->user_name
);
595 return bus_home_update_record(h
, message
, hr
, blobs
, flags
, error
);
598 static int method_resize_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
599 return generic_home_method(userdata
, message
, bus_home_method_resize
, error
);
602 static int method_change_password_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
603 return generic_home_method(userdata
, message
, bus_home_method_change_password
, error
);
606 static int method_lock_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
607 return generic_home_method(userdata
, message
, bus_home_method_lock
, error
);
610 static int method_unlock_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
611 return generic_home_method(userdata
, message
, bus_home_method_unlock
, error
);
614 static int method_acquire_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
615 return generic_home_method(userdata
, message
, bus_home_method_acquire
, error
);
618 static int method_ref_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
619 return generic_home_method(userdata
, message
, bus_home_method_ref
, error
);
622 static int method_release_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
623 return generic_home_method(userdata
, message
, bus_home_method_release
, error
);
626 static int method_lock_all_homes(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
627 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
628 bool waiting
= false;
629 Manager
*m
= ASSERT_PTR(userdata
);
633 /* This is called from logind when we are preparing for system suspend. We enqueue a lock operation
634 * for every suitable home we have and only when all of them completed we send a reply indicating
637 HASHMAP_FOREACH(h
, m
->homes_by_name
) {
639 if (!home_shall_suspend(h
))
643 o
= operation_new(OPERATION_LOCK_ALL
, message
);
648 log_info("Automatically locking home of user %s.", h
->user_name
);
650 r
= home_schedule_operation(h
, o
, error
);
657 if (waiting
) /* At least one lock operation was enqeued, let's leave here without a reply: it will
658 * be sent as soon as the last of the lock operations completed. */
661 return sd_bus_reply_method_return(message
, NULL
);
664 static int method_deactivate_all_homes(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
665 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
666 bool waiting
= false;
667 Manager
*m
= ASSERT_PTR(userdata
);
671 /* This is called from systemd-homed-activate.service's ExecStop= command to ensure that all home
672 * directories are shutdown before the system goes down. Note that we don't do this from
673 * systemd-homed.service itself since we want to allow restarting of it without tearing down all home
676 HASHMAP_FOREACH(h
, m
->homes_by_name
) {
679 o
= operation_new(OPERATION_DEACTIVATE_ALL
, message
);
684 log_info("Automatically deactivating home of user %s.", h
->user_name
);
686 r
= home_schedule_operation(h
, o
, error
);
693 if (waiting
) /* At least one lock operation was enqeued, let's leave here without a reply: it will be
694 * sent as soon as the last of the deactivation operations completed. */
697 return sd_bus_reply_method_return(message
, NULL
);
700 static int method_rebalance(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
701 Manager
*m
= ASSERT_PTR(userdata
);
704 r
= manager_schedule_rebalance(m
, /* immediately= */ true);
706 return sd_bus_reply_method_errorf(message
, BUS_ERROR_REBALANCE_NOT_NEEDED
, "No home directories need rebalancing.");
710 /* Keep a reference to this message, so that we can reply to it once we are done */
711 r
= set_ensure_put(&m
->rebalance_queued_method_calls
, &bus_message_hash_ops
, message
);
713 return log_error_errno(r
, "Failed to track rebalance bus message: %m");
715 sd_bus_message_ref(message
);
719 static const sd_bus_vtable manager_vtable
[] = {
720 SD_BUS_VTABLE_START(0),
722 SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
724 SD_BUS_METHOD_WITH_ARGS("GetHomeByName",
725 SD_BUS_ARGS("s", user_name
),
726 SD_BUS_RESULT("u", uid
,
733 method_get_home_by_name
,
734 SD_BUS_VTABLE_UNPRIVILEGED
),
735 SD_BUS_METHOD_WITH_ARGS("GetHomeByUID",
736 SD_BUS_ARGS("u", uid
),
737 SD_BUS_RESULT("s", user_name
,
744 method_get_home_by_uid
,
745 SD_BUS_VTABLE_UNPRIVILEGED
),
746 SD_BUS_METHOD_WITH_ARGS("GetUserRecordByName",
747 SD_BUS_ARGS("s", user_name
),
748 SD_BUS_RESULT("s", user_record
, "b", incomplete
, "o", bus_path
),
749 method_get_user_record_by_name
,
750 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
751 SD_BUS_METHOD_WITH_ARGS("GetUserRecordByUID",
752 SD_BUS_ARGS("u", uid
),
753 SD_BUS_RESULT("s", user_record
, "b", incomplete
, "o", bus_path
),
754 method_get_user_record_by_uid
,
755 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
756 SD_BUS_METHOD_WITH_ARGS("ListHomes",
758 SD_BUS_RESULT("a(susussso)", home_areas
),
760 SD_BUS_VTABLE_UNPRIVILEGED
),
762 /* The following methods directly execute an operation on a home area, without ref-counting, queueing
763 * or anything, and are accessible through homectl. */
764 SD_BUS_METHOD_WITH_ARGS("ActivateHome",
765 SD_BUS_ARGS("s", user_name
, "s", secret
),
767 method_activate_home
,
768 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
769 SD_BUS_METHOD_WITH_ARGS("ActivateHomeIfReferenced",
770 SD_BUS_ARGS("s", user_name
, "s", secret
),
772 method_activate_home
,
773 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
774 SD_BUS_METHOD_WITH_ARGS("DeactivateHome",
775 SD_BUS_ARGS("s", user_name
),
777 method_deactivate_home
,
780 /* Add the JSON record to homed, but don't create actual $HOME */
781 SD_BUS_METHOD_WITH_ARGS("RegisterHome",
782 SD_BUS_ARGS("s", user_record
),
784 method_register_home
,
785 SD_BUS_VTABLE_UNPRIVILEGED
),
787 /* Remove the JSON record from homed, but don't remove actual $HOME */
788 SD_BUS_METHOD_WITH_ARGS("UnregisterHome",
789 SD_BUS_ARGS("s", user_name
),
791 method_unregister_home
,
792 SD_BUS_VTABLE_UNPRIVILEGED
),
794 /* Add JSON record, and create $HOME for it */
795 SD_BUS_METHOD_WITH_ARGS("CreateHome",
796 SD_BUS_ARGS("s", user_record
),
799 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
800 SD_BUS_METHOD_WITH_ARGS("CreateHomeEx",
801 SD_BUS_ARGS("s", user_record
, "a{sh}", blobs
, "t", flags
),
804 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
806 /* Create $HOME for already registered JSON entry */
807 SD_BUS_METHOD_WITH_ARGS("RealizeHome",
808 SD_BUS_ARGS("s", user_name
, "s", secret
),
811 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
813 /* Remove the JSON record and remove $HOME */
814 SD_BUS_METHOD_WITH_ARGS("RemoveHome",
815 SD_BUS_ARGS("s", user_name
),
818 SD_BUS_VTABLE_UNPRIVILEGED
),
820 /* Investigate $HOME and propagate contained JSON record into our database */
821 SD_BUS_METHOD_WITH_ARGS("FixateHome",
822 SD_BUS_ARGS("s", user_name
, "s", secret
),
825 SD_BUS_VTABLE_SENSITIVE
),
827 /* Just check credentials */
828 SD_BUS_METHOD_WITH_ARGS("AuthenticateHome",
829 SD_BUS_ARGS("s", user_name
, "s", secret
),
831 method_authenticate_home
,
832 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
834 /* Update the JSON record of existing user */
835 SD_BUS_METHOD_WITH_ARGS("UpdateHome",
836 SD_BUS_ARGS("s", user_record
),
839 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
840 SD_BUS_METHOD_WITH_ARGS("UpdateHomeEx",
841 SD_BUS_ARGS("s", user_record
, "a{sh}", blobs
, "t", flags
),
844 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
846 SD_BUS_METHOD_WITH_ARGS("ResizeHome",
847 SD_BUS_ARGS("s", user_name
, "t", size
, "s", secret
),
850 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
852 SD_BUS_METHOD_WITH_ARGS("ChangePasswordHome",
853 SD_BUS_ARGS("s", user_name
, "s", new_secret
, "s", old_secret
),
855 method_change_password_home
,
856 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
858 /* Prepare active home for system suspend: flush out passwords, suspend access */
859 SD_BUS_METHOD_WITH_ARGS("LockHome",
860 SD_BUS_ARGS("s", user_name
),
865 /* Make $HOME usable after system resume again */
866 SD_BUS_METHOD_WITH_ARGS("UnlockHome",
867 SD_BUS_ARGS("s", user_name
, "s", secret
),
870 SD_BUS_VTABLE_SENSITIVE
),
872 /* The following methods implement ref-counted activation, and are what the PAM module and "homectl
873 * with" use. In contrast to the methods above which fail if an operation is already being executed
874 * on a home directory, these ones will queue the request, and are thus more reliable. Moreover,
875 * they are a bit smarter: AcquireHome() will fixate, activate, unlock, or authenticate depending on
876 * the state of the home area, so that the end result is always the same (i.e. the home directory is
877 * accessible), and we always validate the specified passwords. RefHome() will not authenticate, and
878 * thus only works if the home area is already active. */
879 SD_BUS_METHOD_WITH_ARGS("AcquireHome",
880 SD_BUS_ARGS("s", user_name
, "s", secret
, "b", please_suspend
),
881 SD_BUS_RESULT("h", send_fd
),
883 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
884 SD_BUS_METHOD_WITH_ARGS("RefHome",
885 SD_BUS_ARGS("s", user_name
, "b", please_suspend
),
886 SD_BUS_RESULT("h", send_fd
),
889 SD_BUS_METHOD_WITH_ARGS("RefHomeUnrestricted",
890 SD_BUS_ARGS("s", user_name
, "b", please_suspend
),
891 SD_BUS_RESULT("h", send_fd
),
894 SD_BUS_METHOD_WITH_ARGS("ReleaseHome",
895 SD_BUS_ARGS("s", user_name
),
900 /* An operation that acts on all homes that allow it */
901 SD_BUS_METHOD("LockAllHomes", NULL
, NULL
, method_lock_all_homes
, 0),
902 SD_BUS_METHOD("DeactivateAllHomes", NULL
, NULL
, method_deactivate_all_homes
, 0),
903 SD_BUS_METHOD("Rebalance", NULL
, NULL
, method_rebalance
, 0),
908 const BusObjectImplementation manager_object
= {
909 "/org/freedesktop/home1",
910 "org.freedesktop.home1.Manager",
911 .vtables
= BUS_VTABLES(manager_vtable
),
912 .children
= BUS_IMPLEMENTATIONS(&home_object
),
915 static int on_deferred_auto_login(sd_event_source
*s
, void *userdata
) {
916 Manager
*m
= ASSERT_PTR(userdata
);
919 m
->deferred_auto_login_event_source
= sd_event_source_disable_unref(m
->deferred_auto_login_event_source
);
921 r
= sd_bus_emit_properties_changed(
923 "/org/freedesktop/home1",
924 "org.freedesktop.home1.Manager",
927 log_warning_errno(r
, "Failed to send AutoLogin property change event, ignoring: %m");
932 int bus_manager_emit_auto_login_changed(Manager
*m
) {
936 if (m
->deferred_auto_login_event_source
)
942 if (IN_SET(sd_event_get_state(m
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
945 r
= sd_event_add_defer(m
->event
, &m
->deferred_auto_login_event_source
, on_deferred_auto_login
, m
);
947 return log_error_errno(r
, "Failed to allocate auto login event source: %m");
949 r
= sd_event_source_set_priority(m
->deferred_auto_login_event_source
, SD_EVENT_PRIORITY_IDLE
+10);
951 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
953 (void) sd_event_source_set_description(m
->deferred_auto_login_event_source
, "deferred-auto-login");