summaryrefslogtreecommitdiffstats
path: root/src/home/user-record-util.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:45 +0000
commitefeb864cb547a2cbf96dc0053a8bdb4d9190b364 (patch)
treec0b83368f18be983fcc763200c4c24d633244588 /src/home/user-record-util.c
parentReleasing progress-linux version 255.5-1~progress7.99u1. (diff)
downloadsystemd-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.c123
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;
+}