mirror of
https://github.com/systemd/systemd.git
synced 2024-10-27 01:55:22 +03:00
Merge pull request #21333 from poettering/homed-report-fs-and-access-mode
homed: report actual home dir access mode and fs type in effect
This commit is contained in:
commit
1ca5a6c76e
5
TODO
5
TODO
@ -81,6 +81,10 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* extend src/basic/filesystems.[ch] so that it can be used to translate any fs
|
||||
magic into a string. Then use that to replace fstype_magic_to_name() in homed
|
||||
sources, and similar code.
|
||||
|
||||
* userdb: when synthesizing NSS records, pick "best" password from defined
|
||||
passwords, not just the first. i.e. if there are multiple defined, prefer
|
||||
unlocked over locked and prefer non-empty over empty.
|
||||
@ -1290,7 +1294,6 @@ Features:
|
||||
- make size of $XDG_RUNTIME_DIR configurable in user record
|
||||
- query password from kernel keyring first
|
||||
- update even if record is "absent"
|
||||
- add a "access mode" + "fstype" field to the "status" section of json identity records reflecting the actually used access mode and fstype, even on non-luks backends
|
||||
- move acct mgmt stuff from pam_systemd_home to pam_systemd?
|
||||
- when "homectl --pkcs11-token-uri=" is used, synthesize ssh-authorized-keys records for all keys we have private keys on the stick for
|
||||
- make slice for users configurable (requires logind rework)
|
||||
|
@ -866,6 +866,11 @@ on removable media the delay is selected very low to minimize the chance the
|
||||
home directory remains in unclean state if the storage device is removed from
|
||||
the system by the user).
|
||||
|
||||
`accessMode` → The access mode currently in effect for the home directory iself.
|
||||
|
||||
`fileSystemType` → The file system type backing the home directory: a short
|
||||
string, such as "btrfs", "ext4", "xfs".
|
||||
|
||||
## Fields in the `signature` section
|
||||
|
||||
As mentioned, the `signature` section of the user record may contain one or
|
||||
|
@ -17,9 +17,11 @@
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "home-util.h"
|
||||
#include "homed-home-bus.h"
|
||||
#include "homed-home.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "mkdir.h"
|
||||
#include "path-util.h"
|
||||
@ -32,9 +34,9 @@
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "user-record-pwquality.h"
|
||||
#include "user-record-sign.h"
|
||||
#include "user-record-util.h"
|
||||
#include "user-record-pwquality.h"
|
||||
#include "user-record.h"
|
||||
#include "user-util.h"
|
||||
|
||||
@ -2105,29 +2107,27 @@ static int home_get_disk_status_luks(
|
||||
uint64_t *ret_disk_usage,
|
||||
uint64_t *ret_disk_free,
|
||||
uint64_t *ret_disk_ceiling,
|
||||
uint64_t *ret_disk_floor) {
|
||||
uint64_t *ret_disk_floor,
|
||||
statfs_f_type_t *ret_fstype,
|
||||
mode_t *ret_access_mode) {
|
||||
|
||||
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX,
|
||||
disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX,
|
||||
stat_used = UINT64_MAX, fs_size = UINT64_MAX, header_size = 0;
|
||||
|
||||
mode_t access_mode = MODE_INVALID;
|
||||
statfs_f_type_t fstype = 0;
|
||||
struct statfs sfs;
|
||||
struct stat st;
|
||||
const char *hd;
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(ret_disk_size);
|
||||
assert(ret_disk_usage);
|
||||
assert(ret_disk_free);
|
||||
assert(ret_disk_ceiling);
|
||||
|
||||
if (state != HOME_ABSENT) {
|
||||
const char *ip;
|
||||
|
||||
ip = user_record_image_path(h->record);
|
||||
if (ip) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(ip, &st) < 0)
|
||||
log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", ip);
|
||||
else if (S_ISREG(st.st_mode)) {
|
||||
@ -2175,11 +2175,26 @@ static int home_get_disk_status_luks(
|
||||
if (!hd)
|
||||
goto finish;
|
||||
|
||||
if (stat(hd, &st) < 0) {
|
||||
log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", hd);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = stat_verify_directory(&st);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Home directory %s is not a directory, ignoring: %m", hd);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
access_mode = st.st_mode & 07777;
|
||||
|
||||
if (statfs(hd, &sfs) < 0) {
|
||||
log_debug_errno(errno, "Failed to statfs() %s, ignoring: %m", hd);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fstype = sfs.f_type;
|
||||
|
||||
disk_free = sfs.f_bsize * sfs.f_bavail;
|
||||
fs_size = sfs.f_bsize * sfs.f_blocks;
|
||||
if (disk_size != UINT64_MAX && disk_size > fs_size)
|
||||
@ -2209,11 +2224,20 @@ finish:
|
||||
if (disk_floor == UINT64_MAX)
|
||||
disk_floor = minimal_size_by_fs_name(user_record_file_system_type(h->record));
|
||||
|
||||
if (ret_disk_size)
|
||||
*ret_disk_size = disk_size;
|
||||
if (ret_disk_usage)
|
||||
*ret_disk_usage = disk_usage;
|
||||
if (ret_disk_free)
|
||||
*ret_disk_free = disk_free;
|
||||
if (ret_disk_ceiling)
|
||||
*ret_disk_ceiling = disk_ceiling;
|
||||
if (ret_disk_floor)
|
||||
*ret_disk_floor = disk_floor;
|
||||
if (ret_fstype)
|
||||
*ret_fstype = fstype;
|
||||
if (ret_access_mode)
|
||||
*ret_access_mode = access_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2225,20 +2249,20 @@ static int home_get_disk_status_directory(
|
||||
uint64_t *ret_disk_usage,
|
||||
uint64_t *ret_disk_free,
|
||||
uint64_t *ret_disk_ceiling,
|
||||
uint64_t *ret_disk_floor) {
|
||||
uint64_t *ret_disk_floor,
|
||||
statfs_f_type_t *ret_fstype,
|
||||
mode_t *ret_access_mode) {
|
||||
|
||||
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX,
|
||||
disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX;
|
||||
mode_t access_mode = MODE_INVALID;
|
||||
statfs_f_type_t fstype = 0;
|
||||
struct statfs sfs;
|
||||
struct dqblk req;
|
||||
const char *path = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret_disk_size);
|
||||
assert(ret_disk_usage);
|
||||
assert(ret_disk_free);
|
||||
assert(ret_disk_ceiling);
|
||||
assert(ret_disk_floor);
|
||||
assert(h);
|
||||
|
||||
if (HOME_STATE_IS_ACTIVE(state))
|
||||
path = user_record_home_directory(h->record);
|
||||
@ -2261,6 +2285,8 @@ static int home_get_disk_status_directory(
|
||||
|
||||
/* We don't initialize disk_usage from statfs() data here, since the device is likely not used
|
||||
* by us alone, and disk_usage should only reflect our own use. */
|
||||
|
||||
fstype = sfs.f_type;
|
||||
}
|
||||
|
||||
if (IN_SET(h->record->storage, USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME)) {
|
||||
@ -2349,15 +2375,109 @@ static int home_get_disk_status_directory(
|
||||
}
|
||||
|
||||
finish:
|
||||
if (ret_disk_size)
|
||||
*ret_disk_size = disk_size;
|
||||
if (ret_disk_usage)
|
||||
*ret_disk_usage = disk_usage;
|
||||
if (ret_disk_free)
|
||||
*ret_disk_free = disk_free;
|
||||
if (ret_disk_ceiling)
|
||||
*ret_disk_ceiling = disk_ceiling;
|
||||
if (ret_disk_floor)
|
||||
*ret_disk_floor = disk_floor;
|
||||
if (ret_fstype)
|
||||
*ret_fstype = fstype;
|
||||
if (ret_access_mode)
|
||||
*ret_access_mode = access_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int home_get_disk_status_internal(
|
||||
Home *h,
|
||||
HomeState state,
|
||||
uint64_t *ret_disk_size,
|
||||
uint64_t *ret_disk_usage,
|
||||
uint64_t *ret_disk_free,
|
||||
uint64_t *ret_disk_ceiling,
|
||||
uint64_t *ret_disk_floor,
|
||||
statfs_f_type_t *ret_fstype,
|
||||
mode_t *ret_access_mode) {
|
||||
|
||||
assert(h);
|
||||
assert(h->record);
|
||||
|
||||
switch (h->record->storage) {
|
||||
|
||||
case USER_LUKS:
|
||||
return home_get_disk_status_luks(h, state, ret_disk_size, ret_disk_usage, ret_disk_free, ret_disk_ceiling, ret_disk_floor, ret_fstype, ret_access_mode);
|
||||
|
||||
case USER_CLASSIC:
|
||||
case USER_DIRECTORY:
|
||||
case USER_SUBVOLUME:
|
||||
case USER_FSCRYPT:
|
||||
case USER_CIFS:
|
||||
return home_get_disk_status_directory(h, state, ret_disk_size, ret_disk_usage, ret_disk_free, ret_disk_ceiling, ret_disk_floor, ret_fstype, ret_access_mode);
|
||||
|
||||
default:
|
||||
/* don't know */
|
||||
|
||||
if (ret_disk_size)
|
||||
*ret_disk_size = UINT64_MAX;
|
||||
if (ret_disk_usage)
|
||||
*ret_disk_usage = UINT64_MAX;
|
||||
if (ret_disk_free)
|
||||
*ret_disk_free = UINT64_MAX;
|
||||
if (ret_disk_ceiling)
|
||||
*ret_disk_ceiling = UINT64_MAX;
|
||||
if (ret_disk_floor)
|
||||
*ret_disk_floor = UINT64_MAX;
|
||||
if (ret_fstype)
|
||||
*ret_fstype = 0;
|
||||
if (ret_access_mode)
|
||||
*ret_access_mode = MODE_INVALID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int home_get_disk_status(
|
||||
Home *h,
|
||||
uint64_t *ret_disk_size,
|
||||
uint64_t *ret_disk_usage,
|
||||
uint64_t *ret_disk_free,
|
||||
uint64_t *ret_disk_ceiling,
|
||||
uint64_t *ret_disk_floor,
|
||||
statfs_f_type_t *ret_fstype,
|
||||
mode_t *ret_access_mode) {
|
||||
|
||||
assert(h);
|
||||
|
||||
return home_get_disk_status_internal(
|
||||
h,
|
||||
home_get_state(h),
|
||||
ret_disk_size,
|
||||
ret_disk_usage,
|
||||
ret_disk_free,
|
||||
ret_disk_ceiling,
|
||||
ret_disk_floor,
|
||||
ret_fstype,
|
||||
ret_access_mode);
|
||||
}
|
||||
|
||||
static const char *fstype_magic_to_name(statfs_f_type_t magic) {
|
||||
/* For now, let's only translate the magic values of the file systems we actually are able to manage */
|
||||
|
||||
if (F_TYPE_EQUAL(magic, EXT4_SUPER_MAGIC))
|
||||
return "ext4";
|
||||
if (F_TYPE_EQUAL(magic, XFS_SUPER_MAGIC))
|
||||
return "xfs";
|
||||
if (F_TYPE_EQUAL(magic, BTRFS_SUPER_MAGIC))
|
||||
return "btrfs";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int home_augment_status(
|
||||
Home *h,
|
||||
UserRecordLoadFlags flags,
|
||||
@ -2366,6 +2486,9 @@ int home_augment_status(
|
||||
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX, disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *j = NULL, *v = NULL, *m = NULL, *status = NULL;
|
||||
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
statfs_f_type_t magic;
|
||||
const char *fstype;
|
||||
mode_t access_mode;
|
||||
HomeState state;
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
@ -2382,29 +2505,19 @@ int home_augment_status(
|
||||
|
||||
state = home_get_state(h);
|
||||
|
||||
switch (h->record->storage) {
|
||||
|
||||
case USER_LUKS:
|
||||
r = home_get_disk_status_luks(h, state, &disk_size, &disk_usage, &disk_free, &disk_ceiling, &disk_floor);
|
||||
r = home_get_disk_status_internal(
|
||||
h, state,
|
||||
&disk_size,
|
||||
&disk_usage,
|
||||
&disk_free,
|
||||
&disk_ceiling,
|
||||
&disk_floor,
|
||||
&magic,
|
||||
&access_mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case USER_CLASSIC:
|
||||
case USER_DIRECTORY:
|
||||
case USER_SUBVOLUME:
|
||||
case USER_FSCRYPT:
|
||||
case USER_CIFS:
|
||||
r = home_get_disk_status_directory(h, state, &disk_size, &disk_usage, &disk_free, &disk_ceiling, &disk_floor);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
; /* unset */
|
||||
}
|
||||
fstype = fstype_magic_to_name(magic);
|
||||
|
||||
if (disk_floor == UINT64_MAX || (disk_usage != UINT64_MAX && disk_floor < disk_usage))
|
||||
disk_floor = disk_usage;
|
||||
@ -2422,7 +2535,9 @@ int home_augment_status(
|
||||
JSON_BUILD_PAIR_CONDITION(disk_free != UINT64_MAX, "diskFree", JSON_BUILD_UNSIGNED(disk_free)),
|
||||
JSON_BUILD_PAIR_CONDITION(disk_ceiling != UINT64_MAX, "diskCeiling", JSON_BUILD_UNSIGNED(disk_ceiling)),
|
||||
JSON_BUILD_PAIR_CONDITION(disk_floor != UINT64_MAX, "diskFloor", JSON_BUILD_UNSIGNED(disk_floor)),
|
||||
JSON_BUILD_PAIR_CONDITION(h->signed_locally >= 0, "signedLocally", JSON_BUILD_BOOLEAN(h->signed_locally))
|
||||
JSON_BUILD_PAIR_CONDITION(h->signed_locally >= 0, "signedLocally", JSON_BUILD_BOOLEAN(h->signed_locally)),
|
||||
JSON_BUILD_PAIR_CONDITION(fstype, "fileSystemType", JSON_BUILD_STRING(fstype)),
|
||||
JSON_BUILD_PAIR_CONDITION(access_mode != MODE_INVALID, "accessMode", JSON_BUILD_UNSIGNED(access_mode))
|
||||
));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -7,6 +7,7 @@ typedef struct Home Home;
|
||||
#include "homed-operation.h"
|
||||
#include "list.h"
|
||||
#include "ordered-set.h"
|
||||
#include "stat-util.h"
|
||||
#include "user-record.h"
|
||||
|
||||
typedef enum HomeState {
|
||||
@ -190,6 +191,8 @@ int home_unlock(Home *h, UserRecord *secret, sd_bus_error *error);
|
||||
|
||||
HomeState home_get_state(Home *h);
|
||||
|
||||
int home_get_disk_status(Home *h, uint64_t *ret_disk_size,uint64_t *ret_disk_usage, uint64_t *ret_disk_free, uint64_t *ret_disk_ceiling, uint64_t *ret_disk_floor, statfs_f_type_t *ret_fstype, mode_t *ret_access_mode);
|
||||
|
||||
void home_process_notify(Home *h, char **l, int fd);
|
||||
|
||||
int home_killall(Home *h);
|
||||
|
@ -1371,6 +1371,8 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
|
||||
{ "rateLimitBeginUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
|
||||
{ "rateLimitCount", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
|
||||
{ "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
|
||||
{ "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
|
||||
{},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user