2019-07-04 18:35:39 +02:00
/* SPDX-License-Identifier: LGPL-2.1+ */
# include <linux/capability.h>
# include "alloc-util.h"
# include "bus-common-errors.h"
# include "bus-polkit.h"
# include "format-util.h"
# include "homed-bus.h"
# include "homed-home-bus.h"
# include "homed-manager-bus.h"
# include "homed-manager.h"
# include "strv.h"
# include "user-record-sign.h"
# include "user-record-util.h"
# include "user-util.h"
static int property_get_auto_login (
sd_bus * bus ,
const char * path ,
const char * interface ,
const char * property ,
sd_bus_message * reply ,
void * userdata ,
sd_bus_error * error ) {
Manager * m = userdata ;
Iterator i ;
Home * h ;
int r ;
assert ( bus ) ;
assert ( reply ) ;
assert ( m ) ;
r = sd_bus_message_open_container ( reply , ' a ' , " (sso) " ) ;
if ( r < 0 )
return r ;
HASHMAP_FOREACH ( h , m - > homes_by_name , i ) {
_cleanup_ ( strv_freep ) char * * seats = NULL ;
_cleanup_free_ char * home_path = NULL ;
char * * s ;
r = home_auto_login ( h , & seats ) ;
if ( r < 0 ) {
log_debug_errno ( r , " Failed to determine whether home '%s' is candidate for auto-login, ignoring: %m " , h - > user_name ) ;
continue ;
}
if ( ! r )
continue ;
r = bus_home_path ( h , & home_path ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to generate home bus path: %m " ) ;
STRV_FOREACH ( s , seats ) {
r = sd_bus_message_append ( reply , " (sso) " , h - > user_name , * s , home_path ) ;
if ( r < 0 )
return r ;
}
}
return sd_bus_message_close_container ( reply ) ;
}
static int method_get_home_by_name (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_free_ char * path = NULL ;
const char * user_name ;
Manager * m = userdata ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
r = sd_bus_message_read ( message , " s " , & user_name ) ;
if ( r < 0 )
return r ;
2020-04-04 12:23:02 +02:00
if ( ! valid_user_group_name ( user_name , 0 ) )
2019-07-04 18:35:39 +02:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " User name %s is not valid " , user_name ) ;
h = hashmap_get ( m - > homes_by_name , user_name ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for user %s known " , user_name ) ;
r = bus_home_path ( h , & path ) ;
if ( r < 0 )
return r ;
return sd_bus_reply_method_return (
message , " usussso " ,
( uint32_t ) h - > uid ,
home_state_to_string ( home_get_state ( h ) ) ,
h - > record ? ( uint32_t ) user_record_gid ( h - > record ) : GID_INVALID ,
h - > record ? user_record_real_name ( h - > record ) : NULL ,
h - > record ? user_record_home_directory ( h - > record ) : NULL ,
h - > record ? user_record_shell ( h - > record ) : NULL ,
path ) ;
}
static int method_get_home_by_uid (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_free_ char * path = NULL ;
Manager * m = userdata ;
uint32_t uid ;
int r ;
Home * h ;
assert ( message ) ;
assert ( m ) ;
r = sd_bus_message_read ( message , " u " , & uid ) ;
if ( r < 0 )
return r ;
if ( ! uid_is_valid ( uid ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " UID " UID_FMT " is not valid " , uid ) ;
h = hashmap_get ( m - > homes_by_uid , UID_TO_PTR ( uid ) ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for UID " UID_FMT " known " , uid ) ;
/* Note that we don't use bus_home_path() here, but build the path manually, since if we are queried
* for a UID we should also generate the bus path with a UID , and bus_home_path ( ) uses our more
* typical bus path by name . */
if ( asprintf ( & path , " /org/freedesktop/home1/home/ " UID_FMT , h - > uid ) < 0 )
return - ENOMEM ;
return sd_bus_reply_method_return (
message , " ssussso " ,
h - > user_name ,
home_state_to_string ( home_get_state ( h ) ) ,
h - > record ? ( uint32_t ) user_record_gid ( h - > record ) : GID_INVALID ,
h - > record ? user_record_real_name ( h - > record ) : NULL ,
h - > record ? user_record_home_directory ( h - > record ) : NULL ,
h - > record ? user_record_shell ( h - > record ) : NULL ,
path ) ;
}
static int method_list_homes (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_ ( sd_bus_message_unrefp ) sd_bus_message * reply = NULL ;
Manager * m = userdata ;
Iterator i ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
r = sd_bus_message_new_method_return ( message , & reply ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_open_container ( reply , ' a ' , " (susussso) " ) ;
if ( r < 0 )
return r ;
HASHMAP_FOREACH ( h , m - > homes_by_uid , i ) {
_cleanup_free_ char * path = NULL ;
r = bus_home_path ( h , & path ) ;
if ( r < 0 )
return r ;
r = sd_bus_message_append (
reply , " (susussso) " ,
h - > user_name ,
( uint32_t ) h - > uid ,
home_state_to_string ( home_get_state ( h ) ) ,
h - > record ? ( uint32_t ) user_record_gid ( h - > record ) : GID_INVALID ,
h - > record ? user_record_real_name ( h - > record ) : NULL ,
h - > record ? user_record_home_directory ( h - > record ) : NULL ,
h - > record ? user_record_shell ( h - > record ) : NULL ,
path ) ;
if ( r < 0 )
return r ;
}
r = sd_bus_message_close_container ( reply ) ;
if ( r < 0 )
return r ;
return sd_bus_send ( NULL , reply , NULL ) ;
}
static int method_get_user_record_by_name (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_free_ char * json = NULL , * path = NULL ;
Manager * m = userdata ;
const char * user_name ;
bool incomplete ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
r = sd_bus_message_read ( message , " s " , & user_name ) ;
if ( r < 0 )
return r ;
2020-04-04 12:23:02 +02:00
if ( ! valid_user_group_name ( user_name , 0 ) )
2019-07-04 18:35:39 +02:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " User name %s is not valid " , user_name ) ;
h = hashmap_get ( m - > homes_by_name , user_name ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for user %s known " , user_name ) ;
r = bus_home_get_record_json ( h , message , & json , & incomplete ) ;
if ( r < 0 )
return r ;
r = bus_home_path ( h , & path ) ;
if ( r < 0 )
return r ;
return sd_bus_reply_method_return (
message , " sbo " ,
json ,
incomplete ,
path ) ;
}
static int method_get_user_record_by_uid (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_free_ char * json = NULL , * path = NULL ;
Manager * m = userdata ;
bool incomplete ;
uint32_t uid ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
r = sd_bus_message_read ( message , " u " , & uid ) ;
if ( r < 0 )
return r ;
if ( ! uid_is_valid ( uid ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " UID " UID_FMT " is not valid " , uid ) ;
h = hashmap_get ( m - > homes_by_uid , UID_TO_PTR ( uid ) ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for UID " UID_FMT " known " , uid ) ;
r = bus_home_get_record_json ( h , message , & json , & incomplete ) ;
if ( r < 0 )
return r ;
if ( asprintf ( & path , " /org/freedesktop/home1/home/ " UID_FMT , h - > uid ) < 0 )
return - ENOMEM ;
return sd_bus_reply_method_return (
message , " sbo " ,
json ,
incomplete ,
path ) ;
}
static int generic_home_method (
Manager * m ,
sd_bus_message * message ,
sd_bus_message_handler_t handler ,
sd_bus_error * error ) {
const char * user_name ;
Home * h ;
int r ;
r = sd_bus_message_read ( message , " s " , & user_name ) ;
if ( r < 0 )
return r ;
2020-04-04 12:23:02 +02:00
if ( ! valid_user_group_name ( user_name , 0 ) )
2019-07-04 18:35:39 +02:00
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " User name %s is not valid " , user_name ) ;
h = hashmap_get ( m - > homes_by_name , user_name ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for user %s known " , user_name ) ;
return handler ( message , h , error ) ;
}
static int method_activate_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_activate , error ) ;
}
static int method_deactivate_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_deactivate , error ) ;
}
static int validate_and_allocate_home ( Manager * m , UserRecord * hr , Home * * ret , sd_bus_error * error ) {
_cleanup_ ( user_record_unrefp ) UserRecord * signed_hr = NULL ;
struct passwd * pw ;
struct group * gr ;
bool signed_locally ;
Home * other ;
int r ;
assert ( m ) ;
assert ( hr ) ;
assert ( ret ) ;
r = user_record_is_supported ( hr , error ) ;
if ( r < 0 )
return r ;
other = hashmap_get ( m - > homes_by_name , hr - > user_name ) ;
if ( other )
return sd_bus_error_setf ( error , BUS_ERROR_USER_NAME_EXISTS , " Specified user name %s exists already, refusing. " , hr - > user_name ) ;
pw = getpwnam ( hr - > user_name ) ;
if ( pw )
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 ) ;
gr = getgrnam ( hr - > user_name ) ;
if ( gr )
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 ) ;
r = manager_verify_user_record ( m , hr ) ;
switch ( r ) {
case USER_RECORD_UNSIGNED :
/* If the record is unsigned, then let's sign it with our own key */
r = manager_sign_user_record ( m , hr , & signed_hr , error ) ;
if ( r < 0 )
return r ;
hr = signed_hr ;
_fallthrough_ ;
case USER_RECORD_SIGNED_EXCLUSIVE :
signed_locally = true ;
break ;
case USER_RECORD_SIGNED :
case USER_RECORD_FOREIGN :
signed_locally = false ;
break ;
case - ENOKEY :
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 ) ;
default :
return sd_bus_error_set_errnof ( error , r , " Failed to validate signature for '%s': %m " , hr - > user_name ) ;
}
if ( uid_is_valid ( hr - > uid ) ) {
other = hashmap_get ( m - > homes_by_uid , UID_TO_PTR ( hr - > uid ) ) ;
if ( other )
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 ) ;
pw = getpwuid ( hr - > uid ) ;
if ( pw )
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 ) ;
gr = getgrgid ( hr - > uid ) ;
if ( gr )
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 ) ;
} else {
r = manager_augment_record_with_uid ( m , hr ) ;
if ( r < 0 )
return sd_bus_error_set_errnof ( error , r , " Failed to acquire UID for '%s': %m " , hr - > user_name ) ;
}
r = home_new ( m , hr , NULL , ret ) ;
if ( r < 0 )
return r ;
( * ret ) - > signed_locally = signed_locally ;
return r ;
}
static int method_register_home (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_ ( user_record_unrefp ) UserRecord * hr = NULL ;
Manager * m = userdata ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
r = bus_message_read_home_record ( message , USER_RECORD_LOAD_EMBEDDED , & hr , error ) ;
if ( r < 0 )
return r ;
r = bus_verify_polkit_async (
message ,
CAP_SYS_ADMIN ,
" org.freedesktop.home1.create-home " ,
NULL ,
true ,
UID_INVALID ,
& m - > polkit_registry ,
error ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* Will call us back */
r = validate_and_allocate_home ( m , hr , & h , error ) ;
if ( r < 0 )
return r ;
r = home_save_record ( h ) ;
if ( r < 0 ) {
home_free ( h ) ;
return r ;
}
return sd_bus_reply_method_return ( message , NULL ) ;
}
static int method_unregister_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_unregister , error ) ;
}
static int method_create_home (
sd_bus_message * message ,
void * userdata ,
sd_bus_error * error ) {
_cleanup_ ( user_record_unrefp ) UserRecord * hr = NULL ;
Manager * m = userdata ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
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 ) ;
if ( r < 0 )
return r ;
r = bus_verify_polkit_async (
message ,
CAP_SYS_ADMIN ,
" org.freedesktop.home1.create-home " ,
NULL ,
true ,
UID_INVALID ,
& m - > polkit_registry ,
error ) ;
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* Will call us back */
r = validate_and_allocate_home ( m , hr , & h , error ) ;
if ( r < 0 )
return r ;
r = home_create ( h , hr , error ) ;
if ( r < 0 )
goto fail ;
assert ( r = = 0 ) ;
h - > unregister_on_failure = true ;
assert ( ! h - > current_operation ) ;
r = home_set_current_message ( h , message ) ;
if ( r < 0 )
return r ;
return 1 ;
fail :
( void ) home_unlink_record ( h ) ;
h = home_free ( h ) ;
return r ;
}
static int method_realize_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_realize , error ) ;
}
static int method_remove_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_remove , error ) ;
}
static int method_fixate_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_fixate , error ) ;
}
static int method_authenticate_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_authenticate , error ) ;
}
static int method_update_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
_cleanup_ ( user_record_unrefp ) UserRecord * hr = NULL ;
Manager * m = userdata ;
Home * h ;
int r ;
assert ( message ) ;
assert ( m ) ;
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 ) ;
if ( r < 0 )
return r ;
assert ( hr - > user_name ) ;
h = hashmap_get ( m - > homes_by_name , hr - > user_name ) ;
if ( ! h )
return sd_bus_error_setf ( error , BUS_ERROR_NO_SUCH_HOME , " No home for user %s known " , hr - > user_name ) ;
return bus_home_method_update_record ( h , message , hr , error ) ;
}
static int method_resize_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_resize , error ) ;
}
static int method_change_password_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_change_password , error ) ;
}
static int method_lock_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_lock , error ) ;
}
static int method_unlock_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_unlock , error ) ;
}
static int method_acquire_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_acquire , error ) ;
}
static int method_ref_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_ref , error ) ;
}
static int method_release_home ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
return generic_home_method ( userdata , message , bus_home_method_release , error ) ;
}
static int method_lock_all_homes ( sd_bus_message * message , void * userdata , sd_bus_error * error ) {
_cleanup_ ( operation_unrefp ) Operation * o = NULL ;
bool waiting = false ;
Manager * m = userdata ;
Iterator i ;
Home * h ;
int r ;
assert ( m ) ;
/* This is called from logind when we are preparing for system suspend. We enqueue a lock operation
* for every suitable home we have and only when all of them completed we send a reply indicating
* completion . */
HASHMAP_FOREACH ( h , m - > homes_by_name , i ) {
/* Automatically suspend all homes that have at least one client referencing it that asked
* for " please suspend " , and no client that asked for " please do not suspend " . */
if ( h - > ref_event_source_dont_suspend | |
! h - > ref_event_source_please_suspend )
continue ;
if ( ! o ) {
o = operation_new ( OPERATION_LOCK_ALL , message ) ;
if ( ! o )
return - ENOMEM ;
}
2020-03-31 12:50:13 +02:00
log_info ( " Automatically locking home of user %s. " , h - > user_name ) ;
2019-07-04 18:35:39 +02:00
r = home_schedule_operation ( h , o , error ) ;
if ( r < 0 )
return r ;
waiting = true ;
}
if ( waiting ) /* At least one lock operation was enqeued, let's leave here without a reply: it will
* be sent as soon as the last of the lock operations completed . */
return 1 ;
return sd_bus_reply_method_return ( message , NULL ) ;
}
const sd_bus_vtable manager_vtable [ ] = {
SD_BUS_VTABLE_START ( 0 ) ,
SD_BUS_PROPERTY ( " AutoLogin " , " a(sso) " , property_get_auto_login , 0 , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
SD_BUS_METHOD ( " GetHomeByName " , " s " , " usussso " , method_get_home_by_name , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " GetHomeByUID " , " u " , " ssussso " , method_get_home_by_uid , SD_BUS_VTABLE_UNPRIVILEGED ) ,
SD_BUS_METHOD ( " GetUserRecordByName " , " s " , " sbo " , method_get_user_record_by_name , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " GetUserRecordByUID " , " u " , " sbo " , method_get_user_record_by_uid , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " ListHomes " , NULL , " a(susussso) " , method_list_homes , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2020-02-26 11:11:57 +01:00
/* The following methods directly execute an operation on a home area, without ref-counting, queing
* or anything , and are accessible through homectl . */
2019-07-04 18:35:39 +02:00
SD_BUS_METHOD ( " ActivateHome " , " ss " , NULL , method_activate_home , SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " DeactivateHome " , " s " , NULL , method_deactivate_home , 0 ) ,
SD_BUS_METHOD ( " RegisterHome " , " s " , NULL , method_register_home , SD_BUS_VTABLE_UNPRIVILEGED ) , /* Add JSON record to homed, but don't create actual $HOME */
SD_BUS_METHOD ( " UnregisterHome " , " s " , NULL , method_unregister_home , SD_BUS_VTABLE_UNPRIVILEGED ) , /* Remove JSON record from homed, but don't remove actual $HOME */
SD_BUS_METHOD ( " CreateHome " , " s " , NULL , method_create_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) , /* Add JSON record, and create $HOME for it */
SD_BUS_METHOD ( " RealizeHome " , " ss " , NULL , method_realize_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) , /* Create $HOME for already registered JSON entry */
SD_BUS_METHOD ( " RemoveHome " , " s " , NULL , method_remove_home , SD_BUS_VTABLE_UNPRIVILEGED ) , /* Remove JSON record and remove $HOME */
SD_BUS_METHOD ( " FixateHome " , " ss " , NULL , method_fixate_home , SD_BUS_VTABLE_SENSITIVE ) , /* Investigate $HOME and propagate contained JSON record into our database */
SD_BUS_METHOD ( " AuthenticateHome " , " ss " , NULL , method_authenticate_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) , /* Just check credentials */
SD_BUS_METHOD ( " UpdateHome " , " s " , NULL , method_update_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) , /* Update JSON record of existing user */
SD_BUS_METHOD ( " ResizeHome " , " sts " , NULL , method_resize_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " ChangePasswordHome " , " sss " , NULL , method_change_password_home , SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " LockHome " , " s " , NULL , method_lock_home , 0 ) , /* Prepare active home for system suspend: flush out passwords, suspend access */
SD_BUS_METHOD ( " UnlockHome " , " ss " , NULL , method_unlock_home , SD_BUS_VTABLE_SENSITIVE ) , /* Make $HOME usable after system resume again */
/* The following methods implement ref-counted activation, and are what the PAM module calls (and
* what " homectl with " runs ) . In contrast to the methods above which fail if an operation is already
* being executed on a home directory , these ones will queue the request , and are thus more
* reliable . Moreover , they are a bit smarter : AcquireHome ( ) will fixate , activate , unlock , or
* authenticate depending on the state of the home , so that the end result is always the same
* ( i . e . the home directory is accessible ) , and we always validate the specified passwords . RefHome ( )
* will not authenticate , and thus only works if home is already active . */
SD_BUS_METHOD ( " AcquireHome " , " ssb " , " h " , method_acquire_home , SD_BUS_VTABLE_SENSITIVE ) ,
SD_BUS_METHOD ( " RefHome " , " sb " , " h " , method_ref_home , 0 ) ,
SD_BUS_METHOD ( " ReleaseHome " , " s " , NULL , method_release_home , 0 ) ,
/* An operation that acts on all homes that allow it */
SD_BUS_METHOD ( " LockAllHomes " , NULL , NULL , method_lock_all_homes , 0 ) ,
SD_BUS_VTABLE_END
} ;
static int on_deferred_auto_login ( sd_event_source * s , void * userdata ) {
Manager * m = userdata ;
int r ;
assert ( m ) ;
m - > deferred_auto_login_event_source = sd_event_source_unref ( m - > deferred_auto_login_event_source ) ;
r = sd_bus_emit_properties_changed (
m - > bus ,
" /org/freedesktop/home1 " ,
" org.freedesktop.home1.Manager " ,
" AutoLogin " , NULL ) ;
if ( r < 0 )
log_warning_errno ( r , " Failed to send AutoLogin property change event, ignoring: %m " ) ;
return 0 ;
}
int bus_manager_emit_auto_login_changed ( Manager * m ) {
int r ;
assert ( m ) ;
if ( m - > deferred_auto_login_event_source )
return 0 ;
if ( ! m - > event )
return 0 ;
if ( IN_SET ( sd_event_get_state ( m - > event ) , SD_EVENT_FINISHED , SD_EVENT_EXITING ) )
return 0 ;
r = sd_event_add_defer ( m - > event , & m - > deferred_auto_login_event_source , on_deferred_auto_login , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate auto login event source: %m " ) ;
r = sd_event_source_set_priority ( m - > deferred_auto_login_event_source , SD_EVENT_PRIORITY_IDLE + 10 ) ;
if ( r < 0 )
log_warning_errno ( r , " Failed to tweak priority of event source, ignoring: %m " ) ;
( void ) sd_event_source_set_description ( m - > deferred_auto_login_event_source , " deferred-auto-login " ) ;
return 1 ;
}