JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(user_name)),
JSON_BUILD_PAIR_CONDITION(!!rr, "realm", JSON_BUILD_STRING(realm)),
- JSON_BUILD_PAIR("disposition", JSON_BUILD_STRING("regular")),
+ JSON_BUILD_PAIR("disposition", JSON_BUILD_CONST_STRING("regular")),
JSON_BUILD_PAIR("binding", JSON_BUILD_OBJECT(
JSON_BUILD_PAIR(SD_ID128_TO_STRING(mid), JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("imagePath", JSON_BUILD_STRING(image_path)),
JSON_BUILD_PAIR_CONDITION(h->disposition >= 0, "disposition", JSON_BUILD_STRING(user_disposition_to_string(user_record_disposition(h)))),
JSON_BUILD_PAIR("status", JSON_BUILD_OBJECT(
JSON_BUILD_PAIR(SD_ID128_TO_STRING(mid), JSON_BUILD_OBJECT(
- JSON_BUILD_PAIR("service", JSON_BUILD_STRING("io.systemd.Home"))))))));
+ JSON_BUILD_PAIR("service", JSON_BUILD_CONST_STRING("io.systemd.Home"))))))));
if (r < 0)
return r;
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;
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;
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(ID128_TO_UUID_STRING(partition_uuid))),
- JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(ID128_TO_UUID_STRING(luks_uuid))),
- JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(ID128_TO_UUID_STRING(fs_uuid))),
+ 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))),
+ JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(fs_uuid))),
JSON_BUILD_PAIR_CONDITION(!!luks_cipher, "luksCipher", JSON_BUILD_STRING(luks_cipher)),
JSON_BUILD_PAIR_CONDITION(!!luks_cipher_mode, "luksCipherMode", JSON_BUILD_STRING(luks_cipher_mode)),
JSON_BUILD_PAIR_CONDITION(luks_volume_key_size != UINT64_MAX, "luksVolumeKeySize", JSON_BUILD_UNSIGNED(luks_volume_key_size)),
/* Merge the new entry with an old one, if that exists */
be = json_variant_ref(json_variant_by_key(binding, SD_ID128_TO_STRING(mid)));
if (be) {
- r = json_variant_merge(&be, new_binding_entry);
+ r = json_variant_merge_object(&be, new_binding_entry);
if (r < 0)
return r;
if (r < 0)
return r;
+ free_and_replace(h->blob_directory, blob);
+
if (storage >= 0)
h->storage = storage;
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)
}
/* Otherwise it's not OK */
- r = dir_is_empty(hd);
+ r = dir_is_empty(hd, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return r;
if (r == 0)
n = getxattr(ip, "user.home-dirty", x, sizeof(x));
if (n < 0) {
- if (errno != ENODATA)
+ if (!ERRNO_IS_XATTR_ABSENT(errno))
log_debug_errno(errno, "Unable to read dirty xattr off image file, ignoring: %m");
} else if (n == 1 && x[0] == '1')
}
int user_record_test_password(UserRecord *h, UserRecord *secret) {
- char **i;
int r;
assert(h);
}
int user_record_test_recovery_key(UserRecord *h, UserRecord *secret) {
- char **i;
int r;
assert(h);
if (!h->json)
return -EUNATCH;
- if (disk_size < USER_DISK_SIZE_MIN || disk_size > USER_DISK_SIZE_MAX)
- return -ERANGE;
-
r = sd_id128_get_machine(&mid);
if (r < 0)
return r;
int user_record_make_hashed_password(UserRecord *h, char **secret, bool extend) {
_cleanup_(json_variant_unrefp) JsonVariant *priv = NULL;
_cleanup_strv_free_ char **np = NULL;
- char **i;
int r;
assert(h);
int user_record_set_password(UserRecord *h, char **password, bool prepend) {
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
- _cleanup_(strv_free_erasep) char **e = NULL;
+ _cleanup_strv_free_erase_ char **e = NULL;
int r;
assert(h);
int user_record_set_token_pin(UserRecord *h, char **pin, bool prepend) {
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
- _cleanup_(strv_free_erasep) char **e = NULL;
+ _cleanup_strv_free_erase_ char **e = NULL;
int r;
assert(h);
int r;
assert(h);
+ assert(secret);
/* Merges the secrets from 'secret' into 'h'. */
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.");
+ }
+
+ return 0;
+}
+
+bool user_record_shall_rebalance(UserRecord *h) {
+ assert(h);
+
+ if (user_record_rebalance_weight(h) == REBALANCE_WEIGHT_OFF)
+ return false;
+
+ if (user_record_storage(h) != USER_LUKS)
+ return false;
+
+ if (!path_startswith(user_record_image_path(h), get_home_root())) /* This is the only pool we rebalance in */
+ return false;
+
+ return true;
+}
+
+int user_record_set_rebalance_weight(UserRecord *h, uint64_t weight) {
+ _cleanup_(json_variant_unrefp) JsonVariant *new_per_machine_array = NULL, *machine_id_variant = NULL,
+ *machine_id_array = NULL, *per_machine_entry = NULL;
+ _cleanup_free_ JsonVariant **array = NULL;
+ size_t idx = SIZE_MAX, n;
+ JsonVariant *per_machine;
+ sd_id128_t mid;
+ int r;
+
+ assert(h);
+
+ if (!h->json)
+ return -EUNATCH;
+
+ r = sd_id128_get_machine(&mid);
+ if (r < 0)
+ return r;
+
+ r = json_variant_new_id128(&machine_id_variant, mid);
+ if (r < 0)
+ return r;
+
+ r = json_variant_new_array(&machine_id_array, (JsonVariant*[]) { machine_id_variant }, 1);
+ if (r < 0)
+ return r;
+
+ per_machine = json_variant_by_key(h->json, "perMachine");
+ if (per_machine) {
+ if (!json_variant_is_array(per_machine))
+ return -EINVAL;
+
+ n = json_variant_elements(per_machine);
+
+ array = new(JsonVariant*, n + 1);
+ if (!array)
+ return -ENOMEM;
+
+ for (size_t i = 0; i < n; i++) {
+ JsonVariant *m;
+
+ array[i] = json_variant_by_index(per_machine, i);
+
+ if (!json_variant_is_object(array[i]))
+ return -EINVAL;
+
+ m = json_variant_by_key(array[i], "matchMachineId");
+ if (!m) {
+ /* No machineId field? Let's ignore this, but invalidate what we found so far */
+ idx = SIZE_MAX;
+ continue;
+ }
+
+ if (json_variant_equal(m, machine_id_variant) ||
+ json_variant_equal(m, machine_id_array)) {
+ /* Matches exactly what we are looking for. Let's use this */
+ idx = i;
+ continue;
+ }
+
+ r = per_machine_id_match(m, JSON_PERMISSIVE);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ /* Also matches what we are looking for, but with a broader match. In this
+ * case let's ignore this entry, and add a new specific one to the end. */
+ idx = SIZE_MAX;
+ }
+
+ if (idx == SIZE_MAX)
+ idx = n++; /* Nothing suitable found, place new entry at end */
+ else
+ per_machine_entry = json_variant_ref(array[idx]);
+
+ } else {
+ array = new(JsonVariant*, 1);
+ if (!array)
+ return -ENOMEM;
+
+ idx = 0;
+ n = 1;
+ }
+
+ if (!per_machine_entry) {
+ r = json_variant_set_field(&per_machine_entry, "matchMachineId", machine_id_array);
+ if (r < 0)
+ return r;
+ }
+
+ if (weight == REBALANCE_WEIGHT_UNSET)
+ r = json_variant_set_field(&per_machine_entry, "rebalanceWeight", NULL); /* set explicitly to NULL (so that the perMachine setting we are setting here can override the global setting) */
+ else
+ r = json_variant_set_field_unsigned(&per_machine_entry, "rebalanceWeight", weight);
+ if (r < 0)
+ return r;
+
+ assert(idx < n);
+ array[idx] = per_machine_entry;
+
+ r = json_variant_new_array(&new_per_machine_array, array, n);
+ if (r < 0)
+ return r;
+
+ r = json_variant_set_field(&h->json, "perMachine", new_per_machine_array);
+ if (r < 0)
+ return r;
+
+ h->rebalance_weight = weight;
+ h->mask |= USER_RECORD_PER_MACHINE;
return 0;
}