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
, 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
);
373 r
= manager_verify_user_record(m
, hr
);
376 case USER_RECORD_UNSIGNED
:
377 /* If the record is unsigned, then let's sign it with our own key */
378 r
= manager_sign_user_record(m
, hr
, &signed_hr
, error
);
385 case USER_RECORD_SIGNED_EXCLUSIVE
:
386 signed_locally
= true;
389 case USER_RECORD_SIGNED
:
390 case USER_RECORD_FOREIGN
:
391 signed_locally
= false;
395 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
);
398 return sd_bus_error_set_errnof(error
, r
, "Failed to validate signature for '%s': %m", hr
->user_name
);
401 if (uid_is_valid(hr
->uid
)) {
402 _cleanup_free_
struct passwd
*pw
= NULL
;
403 _cleanup_free_
struct group
*gr
= NULL
;
405 other
= hashmap_get(m
->homes_by_uid
, UID_TO_PTR(hr
->uid
));
407 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
);
409 r
= getpwuid_malloc(hr
->uid
, &pw
);
411 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
);
415 r
= getgrgid_malloc(hr
->uid
, &gr
);
417 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
);
421 r
= manager_augment_record_with_uid(m
, hr
);
423 return sd_bus_error_set_errnof(error
, r
, "Failed to acquire UID for '%s': %m", hr
->user_name
);
426 r
= home_new(m
, hr
, NULL
, ret
);
430 (*ret
)->signed_locally
= signed_locally
;
434 static int method_register_home(
435 sd_bus_message
*message
,
437 sd_bus_error
*error
) {
439 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
440 Manager
*m
= ASSERT_PTR(userdata
);
441 _cleanup_(home_freep
) Home
*h
= NULL
;
446 r
= bus_message_read_home_record(message
, USER_RECORD_LOAD_EMBEDDED
|USER_RECORD_PERMISSIVE
, &hr
, error
);
450 r
= bus_verify_polkit_async(
452 "org.freedesktop.home1.create-home",
459 return 1; /* Will call us back */
461 r
= validate_and_allocate_home(m
, hr
, &h
, error
);
465 r
= home_save_record(h
);
471 return sd_bus_reply_method_return(message
, NULL
);
474 static int method_unregister_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
475 return generic_home_method(userdata
, message
, bus_home_method_unregister
, error
);
478 static int method_create_home(
479 sd_bus_message
*message
,
481 sd_bus_error
*error
) {
483 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
484 Manager
*m
= ASSERT_PTR(userdata
);
490 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
);
494 r
= bus_verify_polkit_async(
496 "org.freedesktop.home1.create-home",
503 return 1; /* Will call us back */
505 r
= validate_and_allocate_home(m
, hr
, &h
, error
);
509 r
= home_create(h
, hr
, error
);
514 h
->unregister_on_failure
= true;
515 assert(!h
->current_operation
);
517 r
= home_set_current_message(h
, message
);
524 (void) home_unlink_record(h
);
529 static int method_realize_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
530 return generic_home_method(userdata
, message
, bus_home_method_realize
, error
);
533 static int method_remove_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
534 return generic_home_method(userdata
, message
, bus_home_method_remove
, error
);
537 static int method_fixate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
538 return generic_home_method(userdata
, message
, bus_home_method_fixate
, error
);
541 static int method_authenticate_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
542 return generic_home_method(userdata
, message
, bus_home_method_authenticate
, error
);
545 static int method_update_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
546 _cleanup_(user_record_unrefp
) UserRecord
*hr
= NULL
;
547 Manager
*m
= ASSERT_PTR(userdata
);
553 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
);
557 assert(hr
->user_name
);
559 h
= hashmap_get(m
->homes_by_name
, hr
->user_name
);
561 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_HOME
, "No home for user %s known", hr
->user_name
);
563 return bus_home_method_update_record(h
, message
, hr
, error
);
566 static int method_resize_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
567 return generic_home_method(userdata
, message
, bus_home_method_resize
, error
);
570 static int method_change_password_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
571 return generic_home_method(userdata
, message
, bus_home_method_change_password
, error
);
574 static int method_lock_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
575 return generic_home_method(userdata
, message
, bus_home_method_lock
, error
);
578 static int method_unlock_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
579 return generic_home_method(userdata
, message
, bus_home_method_unlock
, error
);
582 static int method_acquire_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
583 return generic_home_method(userdata
, message
, bus_home_method_acquire
, error
);
586 static int method_ref_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
587 return generic_home_method(userdata
, message
, bus_home_method_ref
, error
);
590 static int method_release_home(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
591 return generic_home_method(userdata
, message
, bus_home_method_release
, error
);
594 static int method_lock_all_homes(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
595 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
596 bool waiting
= false;
597 Manager
*m
= ASSERT_PTR(userdata
);
601 /* This is called from logind when we are preparing for system suspend. We enqueue a lock operation
602 * for every suitable home we have and only when all of them completed we send a reply indicating
605 HASHMAP_FOREACH(h
, m
->homes_by_name
) {
607 if (!home_shall_suspend(h
))
611 o
= operation_new(OPERATION_LOCK_ALL
, message
);
616 log_info("Automatically locking home of user %s.", h
->user_name
);
618 r
= home_schedule_operation(h
, o
, error
);
625 if (waiting
) /* At least one lock operation was enqeued, let's leave here without a reply: it will
626 * be sent as soon as the last of the lock operations completed. */
629 return sd_bus_reply_method_return(message
, NULL
);
632 static int method_deactivate_all_homes(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
633 _cleanup_(operation_unrefp
) Operation
*o
= NULL
;
634 bool waiting
= false;
635 Manager
*m
= ASSERT_PTR(userdata
);
639 /* This is called from systemd-homed-activate.service's ExecStop= command to ensure that all home
640 * directories are shutdown before the system goes down. Note that we don't do this from
641 * systemd-homed.service itself since we want to allow restarting of it without tearing down all home
644 HASHMAP_FOREACH(h
, m
->homes_by_name
) {
647 o
= operation_new(OPERATION_DEACTIVATE_ALL
, message
);
652 log_info("Automatically deactivating home of user %s.", h
->user_name
);
654 r
= home_schedule_operation(h
, o
, error
);
661 if (waiting
) /* At least one lock operation was enqeued, let's leave here without a reply: it will be
662 * sent as soon as the last of the deactivation operations completed. */
665 return sd_bus_reply_method_return(message
, NULL
);
668 static int method_rebalance(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
669 Manager
*m
= ASSERT_PTR(userdata
);
672 r
= manager_schedule_rebalance(m
, /* immediately= */ true);
674 return sd_bus_reply_method_errorf(message
, BUS_ERROR_REBALANCE_NOT_NEEDED
, "No home directories need rebalancing.");
678 /* Keep a reference to this message, so that we can reply to it once we are done */
679 r
= set_ensure_put(&m
->rebalance_queued_method_calls
, &bus_message_hash_ops
, message
);
681 return log_error_errno(r
, "Failed to track rebalance bus message: %m");
683 sd_bus_message_ref(message
);
687 static const sd_bus_vtable manager_vtable
[] = {
688 SD_BUS_VTABLE_START(0),
690 SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
692 SD_BUS_METHOD_WITH_ARGS("GetHomeByName",
693 SD_BUS_ARGS("s", user_name
),
694 SD_BUS_RESULT("u", uid
,
701 method_get_home_by_name
,
702 SD_BUS_VTABLE_UNPRIVILEGED
),
703 SD_BUS_METHOD_WITH_ARGS("GetHomeByUID",
704 SD_BUS_ARGS("u", uid
),
705 SD_BUS_RESULT("s", user_name
,
712 method_get_home_by_uid
,
713 SD_BUS_VTABLE_UNPRIVILEGED
),
714 SD_BUS_METHOD_WITH_ARGS("GetUserRecordByName",
715 SD_BUS_ARGS("s", user_name
),
716 SD_BUS_RESULT("s", user_record
, "b", incomplete
, "o", bus_path
),
717 method_get_user_record_by_name
,
718 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
719 SD_BUS_METHOD_WITH_ARGS("GetUserRecordByUID",
720 SD_BUS_ARGS("u", uid
),
721 SD_BUS_RESULT("s", user_record
, "b", incomplete
, "o", bus_path
),
722 method_get_user_record_by_uid
,
723 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
724 SD_BUS_METHOD_WITH_ARGS("ListHomes",
726 SD_BUS_RESULT("a(susussso)", home_areas
),
728 SD_BUS_VTABLE_UNPRIVILEGED
),
730 /* The following methods directly execute an operation on a home area, without ref-counting, queueing
731 * or anything, and are accessible through homectl. */
732 SD_BUS_METHOD_WITH_ARGS("ActivateHome",
733 SD_BUS_ARGS("s", user_name
, "s", secret
),
735 method_activate_home
,
736 SD_BUS_VTABLE_SENSITIVE
),
737 SD_BUS_METHOD_WITH_ARGS("DeactivateHome",
738 SD_BUS_ARGS("s", user_name
),
740 method_deactivate_home
,
743 /* Add the JSON record to homed, but don't create actual $HOME */
744 SD_BUS_METHOD_WITH_ARGS("RegisterHome",
745 SD_BUS_ARGS("s", user_record
),
747 method_register_home
,
748 SD_BUS_VTABLE_UNPRIVILEGED
),
750 /* Remove the JSON record from homed, but don't remove actual $HOME */
751 SD_BUS_METHOD_WITH_ARGS("UnregisterHome",
752 SD_BUS_ARGS("s", user_name
),
754 method_unregister_home
,
755 SD_BUS_VTABLE_UNPRIVILEGED
),
757 /* Add JSON record, and create $HOME for it */
758 SD_BUS_METHOD_WITH_ARGS("CreateHome",
759 SD_BUS_ARGS("s", user_record
),
762 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
764 /* Create $HOME for already registered JSON entry */
765 SD_BUS_METHOD_WITH_ARGS("RealizeHome",
766 SD_BUS_ARGS("s", user_name
, "s", secret
),
769 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
771 /* Remove the JSON record and remove $HOME */
772 SD_BUS_METHOD_WITH_ARGS("RemoveHome",
773 SD_BUS_ARGS("s", user_name
),
776 SD_BUS_VTABLE_UNPRIVILEGED
),
778 /* Investigate $HOME and propagate contained JSON record into our database */
779 SD_BUS_METHOD_WITH_ARGS("FixateHome",
780 SD_BUS_ARGS("s", user_name
, "s", secret
),
783 SD_BUS_VTABLE_SENSITIVE
),
785 /* Just check credentials */
786 SD_BUS_METHOD_WITH_ARGS("AuthenticateHome",
787 SD_BUS_ARGS("s", user_name
, "s", secret
),
789 method_authenticate_home
,
790 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
792 /* Update the JSON record of existing user */
793 SD_BUS_METHOD_WITH_ARGS("UpdateHome",
794 SD_BUS_ARGS("s", user_record
),
797 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
799 SD_BUS_METHOD_WITH_ARGS("ResizeHome",
800 SD_BUS_ARGS("s", user_name
, "t", size
, "s", secret
),
803 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
805 SD_BUS_METHOD_WITH_ARGS("ChangePasswordHome",
806 SD_BUS_ARGS("s", user_name
, "s", new_secret
, "s", old_secret
),
808 method_change_password_home
,
809 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
811 /* Prepare active home for system suspend: flush out passwords, suspend access */
812 SD_BUS_METHOD_WITH_ARGS("LockHome",
813 SD_BUS_ARGS("s", user_name
),
818 /* Make $HOME usable after system resume again */
819 SD_BUS_METHOD_WITH_ARGS("UnlockHome",
820 SD_BUS_ARGS("s", user_name
, "s", secret
),
823 SD_BUS_VTABLE_SENSITIVE
),
825 /* The following methods implement ref-counted activation, and are what the PAM module and "homectl
826 * with" use. In contrast to the methods above which fail if an operation is already being executed
827 * on a home directory, these ones will queue the request, and are thus more reliable. Moreover,
828 * they are a bit smarter: AcquireHome() will fixate, activate, unlock, or authenticate depending on
829 * the state of the home area, so that the end result is always the same (i.e. the home directory is
830 * accessible), and we always validate the specified passwords. RefHome() will not authenticate, and
831 * thus only works if the home area is already active. */
832 SD_BUS_METHOD_WITH_ARGS("AcquireHome",
833 SD_BUS_ARGS("s", user_name
, "s", secret
, "b", please_suspend
),
834 SD_BUS_RESULT("h", send_fd
),
836 SD_BUS_VTABLE_UNPRIVILEGED
|SD_BUS_VTABLE_SENSITIVE
),
837 SD_BUS_METHOD_WITH_ARGS("RefHome",
838 SD_BUS_ARGS("s", user_name
, "b", please_suspend
),
839 SD_BUS_RESULT("h", send_fd
),
842 SD_BUS_METHOD_WITH_ARGS("ReleaseHome",
843 SD_BUS_ARGS("s", user_name
),
848 /* An operation that acts on all homes that allow it */
849 SD_BUS_METHOD("LockAllHomes", NULL
, NULL
, method_lock_all_homes
, 0),
850 SD_BUS_METHOD("DeactivateAllHomes", NULL
, NULL
, method_deactivate_all_homes
, 0),
851 SD_BUS_METHOD("Rebalance", NULL
, NULL
, method_rebalance
, 0),
856 const BusObjectImplementation manager_object
= {
857 "/org/freedesktop/home1",
858 "org.freedesktop.home1.Manager",
859 .vtables
= BUS_VTABLES(manager_vtable
),
860 .children
= BUS_IMPLEMENTATIONS(&home_object
),
863 static int on_deferred_auto_login(sd_event_source
*s
, void *userdata
) {
864 Manager
*m
= ASSERT_PTR(userdata
);
867 m
->deferred_auto_login_event_source
= sd_event_source_disable_unref(m
->deferred_auto_login_event_source
);
869 r
= sd_bus_emit_properties_changed(
871 "/org/freedesktop/home1",
872 "org.freedesktop.home1.Manager",
875 log_warning_errno(r
, "Failed to send AutoLogin property change event, ignoring: %m");
880 int bus_manager_emit_auto_login_changed(Manager
*m
) {
884 if (m
->deferred_auto_login_event_source
)
890 if (IN_SET(sd_event_get_state(m
->event
), SD_EVENT_FINISHED
, SD_EVENT_EXITING
))
893 r
= sd_event_add_defer(m
->event
, &m
->deferred_auto_login_event_source
, on_deferred_auto_login
, m
);
895 return log_error_errno(r
, "Failed to allocate auto login event source: %m");
897 r
= sd_event_source_set_priority(m
->deferred_auto_login_event_source
, SD_EVENT_PRIORITY_IDLE
+10);
899 log_warning_errno(r
, "Failed to tweak priority of event source, ignoring: %m");
901 (void) sd_event_source_set_description(m
->deferred_auto_login_event_source
, "deferred-auto-login");