diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:45 +0000 |
commit | efeb864cb547a2cbf96dc0053a8bdb4d9190b364 (patch) | |
tree | c0b83368f18be983fcc763200c4c24d633244588 /src/home/user-record-util.c | |
parent | Releasing progress-linux version 255.5-1~progress7.99u1. (diff) | |
download | systemd-efeb864cb547a2cbf96dc0053a8bdb4d9190b364.tar.xz systemd-efeb864cb547a2cbf96dc0053a8bdb4d9190b364.zip |
Merging upstream version 256.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/home/user-record-util.c')
-rw-r--r-- | src/home/user-record-util.c | 123 |
1 files changed, 121 insertions, 2 deletions
diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 089cbb1..3ae0883 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -3,6 +3,7 @@ #include <sys/xattr.h> #include "errno-util.h" +#include "fd-util.h" #include "home-util.h" #include "id128-util.h" #include "libcrypt-util.h" @@ -10,6 +11,7 @@ #include "recovery-key.h" #include "mountpoint-util.h" #include "path-util.h" +#include "sha256.h" #include "stat-util.h" #include "user-record-util.h" #include "user-util.h" @@ -282,7 +284,7 @@ int user_record_add_binding( gid_t gid) { _cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL; - _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL; + _cleanup_free_ char *blob = NULL, *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL; sd_id128_t mid; int r; @@ -291,6 +293,10 @@ int user_record_add_binding( if (!h->json) return -EUNATCH; + blob = path_join(home_system_blob_dir(), h->user_name); + if (!blob) + return -ENOMEM; + r = sd_id128_get_machine(&mid); if (r < 0) return r; @@ -331,6 +337,7 @@ int user_record_add_binding( r = json_build(&new_binding_entry, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("blobDirectory", JSON_BUILD_STRING(blob)), JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(partition_uuid))), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(luks_uuid))), @@ -370,6 +377,8 @@ int user_record_add_binding( if (r < 0) return r; + free_and_replace(h->blob_directory, blob); + if (storage >= 0) h->storage = storage; @@ -428,7 +437,7 @@ int user_record_test_home_directory(UserRecord *h) { if (r == 0) return -ENOTDIR; - r = path_is_mount_point(hd, NULL, 0); + r = path_is_mount_point(hd); if (r < 0) return r; if (r > 0) @@ -1155,6 +1164,7 @@ int user_record_merge_secret(UserRecord *h, UserRecord *secret) { int r; assert(h); + assert(secret); /* Merges the secrets from 'secret' into 'h'. */ @@ -1382,6 +1392,15 @@ int user_record_is_supported(UserRecord *hr, sd_bus_error *error) { if (hr->service && !streq(hr->service, "io.systemd.Home")) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home."); + if (hr->blob_directory) { + /* This function is always called w/o binding section, so if hr->blob_dir is set then the caller set it themselves */ + assert((hr->mask & USER_RECORD_BINDING) == 0); + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage custom blob directories."); + } + + if (json_variant_by_key(hr->json, HOMEWORK_BLOB_FDMAP_FIELD)) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "User record contains unsafe internal fields."); + return 0; } @@ -1510,3 +1529,103 @@ int user_record_set_rebalance_weight(UserRecord *h, uint64_t weight) { h->mask |= USER_RECORD_PER_MACHINE; return 0; } + +int user_record_ensure_blob_manifest(UserRecord *h, Hashmap *blobs, const char **ret_failed) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_hashmap_free_ Hashmap *manifest = NULL; + const char *filename; + void *key, *value; + uint64_t total_size = 0; + int r; + + assert(h); + assert(h->json); + assert(blobs); + assert(ret_failed); + + /* Ensures that blobManifest exists (possibly creating it using the + * contents of blobs), and that the set of keys in both hashmaps are + * exactly the same. If it fails to handle one blob file, the filename + * is put it ret_failed for nicer error reporting. ret_failed is a pointer + * to the same memory blobs uses to store its keys, so it is valid for + * as long as blobs is valid and the corresponding key isn't removed! */ + + if (h->blob_manifest) { + /* blobManifest already exists. In this case we verify + * that the sets of keys are equal and that's it */ + + HASHMAP_FOREACH_KEY(value, key, h->blob_manifest) + if (!hashmap_contains(blobs, key)) + return -EINVAL; + HASHMAP_FOREACH_KEY(value, key, blobs) + if (!hashmap_contains(h->blob_manifest, key)) + return -EINVAL; + + return 0; + } + + /* blobManifest doesn't exist, so we need to create it */ + + HASHMAP_FOREACH_KEY(value, filename, blobs) { + _cleanup_free_ char *filename_dup = NULL; + _cleanup_free_ uint8_t *hash = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *hash_json = NULL; + int fd = PTR_TO_FD(value); + off_t initial, size; + + *ret_failed = filename; + + filename_dup = strdup(filename); + if (!filename_dup) + return -ENOMEM; + + hash = malloc(SHA256_DIGEST_SIZE); + if (!hash) + return -ENOMEM; + + initial = lseek(fd, 0, SEEK_CUR); + if (initial < 0) + return -errno; + + r = sha256_fd(fd, BLOB_DIR_MAX_SIZE, hash); + if (r < 0) + return r; + + size = lseek(fd, 0, SEEK_CUR); + if (size < 0) + return -errno; + if (!DEC_SAFE(&size, initial)) + return -EOVERFLOW; + + if (!INC_SAFE(&total_size, size)) + total_size = UINT64_MAX; + if (total_size > BLOB_DIR_MAX_SIZE) + return -EFBIG; + + if (lseek(fd, initial, SEEK_SET) < 0) + return -errno; + + r = json_variant_new_hex(&hash_json, hash, SHA256_DIGEST_SIZE); + if (r < 0) + return r; + + r = hashmap_ensure_put(&manifest, &path_hash_ops_free_free, filename_dup, hash); + if (r < 0) + return r; + TAKE_PTR(filename_dup); /* Ownership transfers to hashmap */ + TAKE_PTR(hash); + + r = json_variant_set_field(&v, filename, hash_json); + if (r < 0) + return r; + + *ret_failed = NULL; + } + + r = json_variant_set_field_non_null(&h->json, "blobManifest", v); + if (r < 0) + return r; + + h->blob_manifest = TAKE_PTR(manifest); + return 0; +} |