+static int isLUKS2(const char *type)
+{
+ return (type && !strcmp(type, CRYPT_LUKS2));
+}
+
+static int luks2_metadata_copy(struct reenc_ctx *rc)
+{
+ const char *json, *type;
+ crypt_token_info ti;
+ uint32_t flags;
+ int i, r = -EINVAL;
+ struct crypt_device *cd_old = NULL, *cd_new = NULL;
+
+ if (crypt_init(&cd_old, rc->header_file_tmp) ||
+ crypt_load(cd_old, CRYPT_LUKS2, NULL))
+ goto out;
+
+ if (crypt_init(&cd_new, rc->header_file_new) ||
+ crypt_load(cd_new, CRYPT_LUKS2, NULL))
+ goto out;
+
+ /*
+ * we have to erase keyslots missing in new header so that we can
+ * transfer tokens from old header to new one
+ */
+ for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS2); i++)
+ if (!rc->p[i].password && crypt_keyslot_status(cd_old, i) == CRYPT_SLOT_ACTIVE) {
+ r = crypt_keyslot_destroy(cd_old, i);
+ if (r < 0)
+ goto out;
+ }
+
+ for (i = 0; i < MAX_TOKEN; i++) {
+ ti = crypt_token_status(cd_old, i, &type);
+ switch (ti) {
+ case CRYPT_TOKEN_INVALID:
+ log_dbg("Internal error.");
+ r = -EINVAL;
+ goto out;
+ case CRYPT_TOKEN_INACTIVE:
+ break;
+ case CRYPT_TOKEN_INTERNAL_UNKNOWN:
+ log_err(_("This version of cryptsetup-reencrypt can't handle new internal token type %s."), type);
+ r = -EINVAL;
+ goto out;
+ case CRYPT_TOKEN_INTERNAL:
+ /* fallthrough */
+ case CRYPT_TOKEN_EXTERNAL:
+ /* fallthrough */
+ case CRYPT_TOKEN_EXTERNAL_UNKNOWN:
+ if (crypt_token_json_get(cd_old, i, &json) != i) {
+ log_dbg("Failed to get %s token (%d).", type, i);
+ r = -EINVAL;
+ goto out;
+ }
+ if (crypt_token_json_set(cd_new, i, json) != i) {
+ log_dbg("Failed to create %s token (%d).", type, i);
+ r = -EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_ACTIVATION, &flags))) {
+ log_err(_("Failed to read activation flags from backup header."));
+ goto out;
+ }
+ if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_ACTIVATION, flags))) {
+ log_err(_("Failed to write activation flags to new header."));
+ goto out;
+ }
+ if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_REQUIREMENTS, &flags))) {
+ log_err(_("Failed to read requirements from backup header."));
+ goto out;
+ }
+ if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_REQUIREMENTS, flags)))
+ log_err(_("Failed to read requirements from backup header."));
+out:
+ crypt_free(cd_old);
+ crypt_free(cd_new);
+ unlink(rc->header_file_tmp);
+
+ return r;
+}
+