Support init_by_name for verity.
authorMilan Broz <gmazyland@gmail.com>
Fri, 8 Jun 2012 14:38:26 +0000 (16:38 +0200)
committerMilan Broz <gmazyland@gmail.com>
Fri, 8 Jun 2012 14:38:26 +0000 (16:38 +0200)
lib/libdevmapper.c
lib/loopaes/loopaes.c
lib/luks1/keyencryption.c
lib/luks1/keymanage.c
lib/setup.c
lib/utils_dm.h
lib/verity/verity.c
src/cryptsetup.c
src/veritysetup.c

index f2e66a4..e7d4a07 100644 (file)
@@ -256,12 +256,31 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
                sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
 }
 
+static int hex_to_bytes(const char *hex, char *result)
+{
+       char buf[3] = "xx\0", *endp;
+       int i, len;
+
+       len = strlen(hex) / 2;
+       for (i = 0; i < len; i++) {
+               memcpy(buf, &hex[i * 2], 2);
+               result[i] = strtoul(buf, &endp, 16);
+               if (endp != &buf[2])
+                       return -EINVAL;
+       }
+       return i;
+}
+
+/* http://code.google.com/p/cryptsetup/wiki/DMCrypt */
 static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd)
 {
        int r, max_size, null_cipher = 0;
        char *params, *hexkey;
        const char *features = "";
 
+       if (!dmd)
+               return NULL;
+
        if (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) {
                if (dm_flags() & DM_DISCARDS_SUPPORTED) {
                        features = " 1 allow_discards";
@@ -283,14 +302,14 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd)
                hex_key(hexkey, dmd->u.crypt.vk->keylength, dmd->u.crypt.vk->key);
 
        max_size = strlen(hexkey) + strlen(dmd->u.crypt.cipher) +
-                  strlen(dmd->u.crypt.device) + strlen(features) + 64;
+                  strlen(dmd->data_device) + strlen(features) + 64;
        params = crypt_safe_alloc(max_size);
        if (!params)
                goto out;
 
        r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s",
                     dmd->u.crypt.cipher, hexkey, dmd->u.crypt.iv_offset,
-                    dmd->u.crypt.device, dmd->u.crypt.offset, features);
+                    dmd->data_device, dmd->u.crypt.offset, features);
        if (r < 0 || r >= max_size) {
                crypt_safe_free(params);
                params = NULL;
@@ -299,12 +318,17 @@ out:
        crypt_safe_free(hexkey);
        return params;
 }
+
+/* http://code.google.com/p/cryptsetup/wiki/DMVerity */
 static char *get_dm_verity_params(struct crypt_params_verity *vp,
                                   struct crypt_dm_active_device *dmd)
 {
        int max_size, r;
        char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
 
+       if (!vp || !dmd)
+               return NULL;
+
        hexroot = crypt_safe_alloc(dmd->u.verity.root_hash_size * 2 + 1);
        if (!hexroot)
                goto out;
@@ -316,7 +340,7 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
        hex_key(hexsalt, vp->salt_size, vp->salt);
 
        max_size = strlen(hexroot) + strlen(hexsalt) +
-                  strlen(dmd->u.verity.data_device) +
+                  strlen(dmd->data_device) +
                   strlen(dmd->u.verity.hash_device) +
                   strlen(vp->hash_name) + 128;
 
@@ -326,7 +350,7 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
 
        r = snprintf(params, max_size,
                     "%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s",
-                    vp->version, dmd->u.verity.data_device,
+                    vp->version, dmd->data_device,
                     dmd->u.verity.hash_device,
                     vp->data_block_size, vp->hash_block_size,
                     vp->data_size, dmd->u.verity.hash_offset,
@@ -581,7 +605,6 @@ out_no_removal:
 int dm_create_device(const char *name,
                     const char *type,
                     struct crypt_dm_active_device *dmd,
-                    void *params,
                     int reload)
 {
        char *table_params = NULL;
@@ -589,12 +612,12 @@ int dm_create_device(const char *name,
        if (dmd->target == DM_CRYPT)
                table_params = get_dm_crypt_params(dmd);
        else if (dmd->target == DM_VERITY)
-               table_params = get_dm_verity_params(params, dmd);
+               table_params = get_dm_verity_params(dmd->u.verity.vp, dmd);
 
        if (!table_params)
                return -EINVAL;
 
-       return _dm_create_device(name, type, dmd->u.crypt.device, dmd->flags,
+       return _dm_create_device(name, type, dmd->data_device, dmd->flags,
                                 dmd->uuid, dmd->size, table_params, reload);
 }
 
@@ -626,11 +649,18 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi,
 
        next = dm_get_next_target(dmt, next, &start, &length,
                                  &target_type, &params);
-       if (!target_type || strcmp(target_type, target) != 0 ||
-           start != 0 || next)
-               r = -EINVAL;
-       else
-               r = 0;
+
+       if (!target_type || start != 0 || next)
+               goto out;
+
+       if (target && strcmp(target_type, target))
+               goto out;
+
+       /* for target == NULL check all supported */
+       if (!target && (strcmp(target_type, DM_CRYPT_TARGET) &&
+                       strcmp(target_type, DM_VERITY_TARGET)))
+               goto out;
+       r = 0;
 out:
        if (!r && status_line && !(*status_line = strdup(params)))
                r = -ENOMEM;
@@ -646,7 +676,7 @@ int dm_status_device(const char *name)
        int r;
        struct dm_info dmi;
 
-       r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
+       r = dm_status_dmi(name, &dmi, NULL, NULL);
        if (r < 0)
                return r;
 
@@ -684,6 +714,7 @@ int dm_status_verity_ok(const char *name)
        return r;
 }
 
+/* FIXME use hex wrapper, user val wrappers for line parsing */
 static int _dm_query_crypt(uint32_t get_flags,
                           struct dm_info *dmi,
                           char *params,
@@ -693,11 +724,12 @@ static int _dm_query_crypt(uint32_t get_flags,
        char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
        unsigned int i;
 
+       memset(dmd, 0, sizeof(*dmd));
        dmd->target = DM_CRYPT;
 
        rcipher = strsep(&params, " ");
        /* cipher */
-       if (get_flags & DM_ACTIVE_CIPHER)
+       if (get_flags & DM_ACTIVE_CRYPT_CIPHER)
                dmd->u.crypt.cipher = strdup(rcipher);
 
        /* skip */
@@ -714,7 +746,7 @@ static int _dm_query_crypt(uint32_t get_flags,
        /* device */
        rdevice = strsep(&params, " ");
        if (get_flags & DM_ACTIVE_DEVICE)
-               dmd->u.crypt.device = crypt_lookup_dev(rdevice);
+               dmd->data_device = crypt_lookup_dev(rdevice);
 
        /*offset */
        if (!params)
@@ -750,17 +782,17 @@ static int _dm_query_crypt(uint32_t get_flags,
        }
 
        /* Never allow to return empty key */
-       if ((get_flags & DM_ACTIVE_KEY) && dmi->suspended) {
+       if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi->suspended) {
                log_dbg("Cannot read volume key while suspended.");
                return -EINVAL;
        }
 
-       if (get_flags & DM_ACTIVE_KEYSIZE) {
+       if (get_flags & DM_ACTIVE_CRYPT_KEYSIZE) {
                dmd->u.crypt.vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL);
                if (!dmd->u.crypt.vk)
                        return -ENOMEM;
 
-               if (get_flags & DM_ACTIVE_KEY) {
+               if (get_flags & DM_ACTIVE_CRYPT_KEY) {
                        buffer[2] = '\0';
                        for(i = 0; i < dmd->u.crypt.vk->keylength; i++) {
                                memcpy(buffer, &key_[i * 2], 2);
@@ -783,8 +815,109 @@ static int _dm_query_verity(uint32_t get_flags,
                             char *params,
                             struct crypt_dm_active_device *dmd)
 {
+       struct crypt_params_verity *vp = NULL;
+       uint32_t val32;
+       uint64_t val64;
+       size_t len;
+       char *str, *str2;
+
+       if (get_flags & DM_ACTIVE_VERITY_PARAMS)
+               vp = dmd->u.verity.vp;
+
+       memset(dmd, 0, sizeof(*dmd));
+
        dmd->target = DM_VERITY;
-       return -EINVAL;
+       dmd->u.verity.vp = vp;
+
+       /* version */
+       val32 = strtoul(params, &params, 10);
+       if (*params != ' ')
+               return -EINVAL;
+       if (vp)
+               vp->version = val32;
+       params++;
+
+       /* data device */
+       str = strsep(&params, " ");
+       if (!params)
+               return -EINVAL;
+       if (get_flags & DM_ACTIVE_DEVICE)
+               dmd->data_device = crypt_lookup_dev(str);
+
+       /* hash device */
+       str = strsep(&params, " ");
+       if (!params)
+               return -EINVAL;
+       if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE)
+               dmd->u.verity.hash_device = crypt_lookup_dev(str);
+
+       /* data block size*/
+       val32 = strtoul(params, &params, 10);
+       if (*params != ' ')
+               return -EINVAL;
+       if (vp)
+               vp->data_block_size = val32;
+       params++;
+
+       /* hash block size */
+       val32 = strtoul(params, &params, 10);
+       if (*params != ' ')
+               return -EINVAL;
+       if (vp)
+               vp->hash_block_size = val32;
+       params++;
+
+       /* data blocks */
+       val64 = strtoull(params, &params, 10);
+       if (*params != ' ')
+               return -EINVAL;
+       if (vp)
+               vp->data_size = val64;
+       params++;
+
+       /* hash start */
+       val64 = strtoull(params, &params, 10);
+       if (*params != ' ')
+               return -EINVAL;
+       dmd->u.verity.hash_offset = val64;
+       params++;
+
+       /* hash algorithm */
+       str = strsep(&params, " ");
+       if (!params)
+               return -EINVAL;
+       if (vp)
+               vp->hash_name = strdup(str);
+
+       /* root digest */
+       str = strsep(&params, " ");
+       if (!params)
+               return -EINVAL;
+       len = strlen(str) / 2;
+       dmd->u.verity.root_hash_size = len;
+       if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH) {
+               if (!(str2 = malloc(len)))
+                       return -ENOMEM;
+               if (hex_to_bytes(str, str2) != len)
+                       return -EINVAL;
+               dmd->u.verity.root_hash = str2;
+       }
+
+       /* salt */
+       str = strsep(&params, " ");
+       if (params)
+               return -EINVAL;
+       if (vp) {
+               len = strlen(str) / 2;
+               vp->salt_size = len;
+               if (!(str2 = malloc(len)))
+                       return -ENOMEM;
+               if (hex_to_bytes(str, str2) != len)
+                       return -EINVAL;
+               vp->salt = str2;
+       }
+
+       return 0;
 }
 
 int dm_query_device(const char *name, uint32_t get_flags,
@@ -798,8 +931,6 @@ int dm_query_device(const char *name, uint32_t get_flags,
        void *next = NULL;
        int r = -EINVAL;
 
-       memset(dmd, 0, sizeof(*dmd));
-
        if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
                goto out;
        if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
index 7a5f67b..35345eb 100644 (file)
@@ -196,8 +196,8 @@ int LOOPAES_activate(struct crypt_device *cd,
                .uuid   = crypt_get_uuid(cd),
                .size   = 0,
                .flags  = flags,
+               .data_device = crypt_get_device_name(cd),
                .u.crypt  = {
-                       .device = crypt_get_device_name(cd),
                        .cipher = NULL,
                        .vk     = vk,
                        .offset = crypt_get_data_offset(cd),
@@ -206,7 +206,7 @@ int LOOPAES_activate(struct crypt_device *cd,
        };
 
 
-       r = device_check_and_adjust(cd, dmd.u.crypt.device, DEV_EXCL,
+       r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
                                    &dmd.size, &dmd.u.crypt.offset, &flags);
        if (r)
                return r;
@@ -225,7 +225,7 @@ int LOOPAES_activate(struct crypt_device *cd,
        log_dbg("Trying to activate loop-AES device %s using cipher %s.",
                name, dmd.u.crypt.cipher);
 
-       r = dm_create_device(name, CRYPT_LOOPAES, &dmd, NULL, 0);
+       r = dm_create_device(name, CRYPT_LOOPAES, &dmd, 0);
 
        if (!r && !(dm_flags() & req_flags)) {
                log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
index a2e0d31..c634b68 100644 (file)
@@ -62,8 +62,8 @@ static int setup_mapping(const char *cipher, const char *name,
                .uuid   = NULL,
                .size   = 0,
                .flags  = 0,
+               .data_device = device,
                .u.crypt = {
-                       .device = device,
                        .cipher = cipher,
                        .vk     = vk,
                        .offset = sector,
@@ -86,7 +86,7 @@ static int setup_mapping(const char *cipher, const char *name,
        dmd.size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
        cleaner_size = dmd.size;
 
-       return dm_create_device(name, "TEMP", &dmd, NULL, 0);
+       return dm_create_device(name, "TEMP", &dmd, 0);
 }
 
 static void sigint_handler(int sig __attribute__((unused)))
index 95a4d27..50db7aa 100644 (file)
@@ -1037,8 +1037,8 @@ int LUKS1_activate(struct crypt_device *cd,
                .uuid   = crypt_get_uuid(cd),
                .flags  = flags,
                .size   = 0,
+               .data_device = crypt_get_device_name(cd),
                .u.crypt = {
-                       .device = crypt_get_device_name(cd),
                        .cipher = NULL,
                        .vk     = vk,
                        .offset = crypt_get_data_offset(cd),
@@ -1051,7 +1051,7 @@ int LUKS1_activate(struct crypt_device *cd,
        else
                device_check = DEV_EXCL;
 
-       r = device_check_and_adjust(cd, dmd.u.crypt.device, device_check,
+       r = device_check_and_adjust(cd, dmd.data_device, device_check,
                                    &dmd.size, &dmd.u.crypt.offset,
                                    &dmd.flags);
        if (r)
@@ -1062,7 +1062,7 @@ int LUKS1_activate(struct crypt_device *cd,
                return -ENOMEM;
 
        dmd.u.crypt.cipher = dm_cipher;
-       r = dm_create_device(name, CRYPT_LUKS1, &dmd, NULL, 0);
+       r = dm_create_device(name, CRYPT_LUKS1, &dmd, 0);
 
        free(dm_cipher);
        return r;
index 0d930ef..21053fd 100644 (file)
@@ -305,8 +305,8 @@ int PLAIN_activate(struct crypt_device *cd,
                .uuid   = crypt_get_uuid(cd),
                .size   = size,
                .flags  = flags,
+               .data_device = crypt_get_device_name(cd),
                .u.crypt  = {
-                       .device = crypt_get_device_name(cd),
                        .cipher = NULL,
                        .vk     = vk,
                        .offset = crypt_get_data_offset(cd),
@@ -319,7 +319,7 @@ int PLAIN_activate(struct crypt_device *cd,
        else
                device_check = DEV_EXCL;
 
-       r = device_check_and_adjust(cd, dmd.u.crypt.device, device_check,
+       r = device_check_and_adjust(cd, dmd.data_device, device_check,
                                    &dmd.size, &dmd.u.crypt.offset, &dmd.flags);
        if (r)
                return r;
@@ -335,7 +335,7 @@ int PLAIN_activate(struct crypt_device *cd,
        log_dbg("Trying to activate PLAIN device %s using cipher %s.",
                name, dmd.u.crypt.cipher);
 
-       r = dm_create_device(name, CRYPT_PLAIN, &dmd, NULL, 0);
+       r = dm_create_device(name, CRYPT_PLAIN, &dmd, 0);
 
        // FIXME
        if (!cd->plain_uuid && dm_query_device(name, DM_ACTIVE_UUID, &dmd) >= 0)
@@ -677,15 +677,121 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
        return r;
 }
 
+static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
+{
+       struct crypt_dm_active_device dmd = {};
+       char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
+       int key_nums, r;
+
+       r = dm_query_device(name, DM_ACTIVE_DEVICE |
+                                  DM_ACTIVE_UUID |
+                                  DM_ACTIVE_CRYPT_CIPHER |
+                                  DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
+       if (r < 0)
+               goto out;
+
+       if (isPLAIN(cd->type)) {
+               cd->plain_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
+               cd->plain_hdr.hash = NULL; /* no way to get this */
+               cd->plain_hdr.offset = dmd.u.crypt.offset;
+               cd->plain_hdr.skip = dmd.u.crypt.iv_offset;
+               cd->plain_key_size = dmd.u.crypt.vk->keylength;
+
+               r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, NULL, cipher_mode);
+               if (!r) {
+                       cd->plain_cipher = strdup(cipher);
+                       cd->plain_cipher_mode = strdup(cipher_mode);
+               }
+       } else if (isLOOPAES(cd->type)) {
+               cd->loopaes_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
+               cd->loopaes_hdr.offset = dmd.u.crypt.offset;
+
+               r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher,
+                                             &key_nums, cipher_mode);
+               if (!r) {
+                       cd->loopaes_cipher = strdup(cipher);
+                       cd->loopaes_cipher_mode = strdup(cipher_mode);
+                       /* version 3 uses last key for IV */
+                       if (dmd.u.crypt.vk->keylength % key_nums)
+                               key_nums++;
+                       cd->loopaes_key_size = dmd.u.crypt.vk->keylength / key_nums;
+               }
+       } else if (isLUKS(cd->type)) {
+               if (mdata_device(cd)) {
+                       r = _crypt_load_luks1(cd, 0, 0);
+                       if (r < 0) {
+                               log_dbg("LUKS device header does not match active device.");
+                               free(cd->type);
+                               cd->type = NULL;
+                               r = 0;
+                               goto out;
+                       }
+                       /* check whether UUIDs match each other */
+                       r = crypt_uuid_cmp(dmd.uuid, cd->hdr.uuid);
+                       if (r < 0) {
+                               log_dbg("LUKS device header uuid: %s mismatches DM returned uuid %s",
+                                       cd->hdr.uuid, dmd.uuid);
+                               free(cd->type);
+                               cd->type = NULL;
+                               r = 0;
+                               goto out;
+                       }
+               }
+       }
+out:
+       crypt_free_volume_key(dmd.u.crypt.vk);
+       free(CONST_CAST(void*)dmd.u.crypt.cipher);
+       free(CONST_CAST(void*)dmd.data_device);
+       free(CONST_CAST(void*)dmd.uuid);
+       return r;
+}
+
+static int _init_by_name_verity(struct crypt_device *cd, const char *name)
+{
+       struct crypt_params_verity params = {};
+       struct crypt_dm_active_device dmd = {
+               .target = DM_VERITY,
+               .u.verity.vp = &params,
+       };
+       int r;
+
+       r = dm_query_device(name, DM_ACTIVE_DEVICE |
+                                  DM_ACTIVE_UUID |
+                                  DM_ACTIVE_VERITY_HASH_DEVICE |
+                                  DM_ACTIVE_VERITY_PARAMS, &dmd);
+       if (r < 0)
+               goto out;
+
+       if (isVERITY(cd->type)) {
+               cd->verity_flags = CRYPT_VERITY_NO_HEADER; //FIXME
+               //cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
+               cd->verity_hdr.data_size = params.data_size;
+               cd->verity_root_hash_size = dmd.u.verity.root_hash_size;
+               cd->verity_root_hash = NULL;
+               cd->verity_hdr.hash_name = params.hash_name;
+               cd->verity_hdr.data_device = NULL;
+               cd->verity_hdr.data_block_size = params.data_block_size;
+               cd->verity_hdr.hash_block_size = params.hash_block_size;
+               cd->verity_hdr.hash_area_offset = params.hash_area_offset;
+               cd->verity_hdr.version = params.version;
+               cd->verity_hdr.flags = params.flags;
+               cd->verity_hdr.salt_size = params.salt_size;
+               cd->verity_hdr.salt = params.salt;
+       }
+out:
+       free(CONST_CAST(void*)dmd.u.verity.hash_device);
+       free(CONST_CAST(void*)dmd.data_device);
+       free(CONST_CAST(void*)dmd.uuid);
+       return r;
+}
+
 int crypt_init_by_name_and_header(struct crypt_device **cd,
                                  const char *name,
                                  const char *header_device)
 {
        crypt_status_info ci;
        struct crypt_dm_active_device dmd;
-       char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
-       int key_nums, r;
-
+       int r;
 
        log_dbg("Allocating crypt device context by device %s.", name);
 
@@ -698,8 +804,7 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
                return -ENODEV;
        }
 
-       r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CIPHER |
-                                 DM_ACTIVE_UUID | DM_ACTIVE_KEYSIZE, &dmd);
+       r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd);
        if (r < 0)
                goto out;
 
@@ -708,17 +813,17 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
        if (header_device) {
                r = crypt_init(cd, header_device);
        } else {
-               r = crypt_init(cd, dmd.u.crypt.device);
+               r = crypt_init(cd, dmd.data_device);
 
                /* Underlying device disappeared but mapping still active */
-               if (!dmd.u.crypt.device || r == -ENOTBLK)
+               if (!dmd.data_device || r == -ENOTBLK)
                        log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"),
                                    name);
 
                /* Underlying device is not readable but crypt mapping exists */
                if (r == -ENOTBLK) {
-                       free(CONST_CAST(void*)dmd.u.crypt.device);
-                       dmd.u.crypt.device = NULL;
+                       free(CONST_CAST(void*)dmd.data_device);
+                       dmd.data_device = NULL;
                        r = crypt_init(cd, NULL);
                }
        }
@@ -733,83 +838,38 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
                        (*cd)->type = strdup(CRYPT_LOOPAES);
                else if (!strncmp(CRYPT_LUKS1, dmd.uuid, sizeof(CRYPT_LUKS1)-1))
                        (*cd)->type = strdup(CRYPT_LUKS1);
+               else if (!strncmp(CRYPT_VERITY, dmd.uuid, sizeof(CRYPT_VERITY)-1))
+                       (*cd)->type = strdup(CRYPT_VERITY);
                else
                        log_dbg("Unknown UUID set, some parameters are not set.");
        } else
                log_dbg("Active device has no UUID set, some parameters are not set.");
 
        if (header_device) {
-               r = crypt_set_data_device(*cd, dmd.u.crypt.device);
+               r = crypt_set_data_device(*cd, dmd.data_device);
                if (r < 0)
                        goto out;
        }
 
        /* Try to initialise basic parameters from active device */
 
-       if (!(*cd)->backing_file && dmd.u.crypt.device &&
-           crypt_loop_device(dmd.u.crypt.device) &&
-           !((*cd)->backing_file = crypt_loop_backing_file(dmd.u.crypt.device))) {
+       if (!(*cd)->backing_file && dmd.data_device &&
+           crypt_loop_device(dmd.data_device) &&
+           !((*cd)->backing_file = crypt_loop_backing_file(dmd.data_device))) {
                r = -ENOMEM;
                goto out;
        }
 
-       if (isPLAIN((*cd)->type)) {
-               (*cd)->plain_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
-               (*cd)->plain_hdr.hash = NULL; /* no way to get this */
-               (*cd)->plain_hdr.offset = dmd.u.crypt.offset;
-               (*cd)->plain_hdr.skip = dmd.u.crypt.iv_offset;
-               (*cd)->plain_key_size = dmd.u.crypt.vk->keylength;
-
-               r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, NULL, cipher_mode);
-               if (!r) {
-                       (*cd)->plain_cipher = strdup(cipher);
-                       (*cd)->plain_cipher_mode = strdup(cipher_mode);
-               }
-       } else if (isLOOPAES((*cd)->type)) {
-               (*cd)->loopaes_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
-               (*cd)->loopaes_hdr.offset = dmd.u.crypt.offset;
-
-               r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher,
-                                             &key_nums, cipher_mode);
-               if (!r) {
-                       (*cd)->loopaes_cipher = strdup(cipher);
-                       (*cd)->loopaes_cipher_mode = strdup(cipher_mode);
-                       /* version 3 uses last key for IV */
-                       if (dmd.u.crypt.vk->keylength % key_nums)
-                               key_nums++;
-                       (*cd)->loopaes_key_size = dmd.u.crypt.vk->keylength / key_nums;
-               }
-       } else if (isLUKS((*cd)->type)) {
-               if (mdata_device(*cd)) {
-                       r = _crypt_load_luks1(*cd, 0, 0);
-                       if (r < 0) {
-                               log_dbg("LUKS device header does not match active device.");
-                               free((*cd)->type);
-                               (*cd)->type = NULL;
-                               r = 0;
-                               goto out;
-                       }
-                       /* checks whether UUIDs match each other */
-                       r = crypt_uuid_cmp(dmd.uuid, (*cd)->hdr.uuid);
-                       if (r < 0) {
-                               log_dbg("LUKS device header uuid: %s mismatches DM returned uuid %s",
-                                       (*cd)->hdr.uuid, dmd.uuid);
-                               free((*cd)->type);
-                               (*cd)->type = NULL;
-                               r = 0;
-                               goto out;
-                       }
-               }
-       }
-
+       if (dmd.target == DM_CRYPT)
+               r = _init_by_name_crypt(*cd, name);
+       else if (dmd.target == DM_VERITY)
+               r = _init_by_name_verity(*cd, name);
 out:
        if (r < 0) {
                crypt_free(*cd);
                *cd = NULL;
        }
-       crypt_free_volume_key(dmd.u.crypt.vk);
-       free(CONST_CAST(void*)dmd.u.crypt.device);
-       free(CONST_CAST(void*)dmd.u.crypt.cipher);
+       free(CONST_CAST(void*)dmd.data_device);
        free(CONST_CAST(void*)dmd.uuid);
        return r;
 }
@@ -1171,20 +1231,20 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
 
        log_dbg("Resizing device %s to %" PRIu64 " sectors.", name, new_size);
 
-       r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CIPHER |
-                                 DM_ACTIVE_UUID | DM_ACTIVE_KEYSIZE |
-                                 DM_ACTIVE_KEY, &dmd);
+       r = dm_query_device(name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
+                                 DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
+                                 DM_ACTIVE_CRYPT_KEY, &dmd);
        if (r < 0) {
                log_err(NULL, _("Device %s is not active.\n"), name);
-               goto out;
+               return -EINVAL;
        }
 
-       if (!dmd.uuid) {
+       if (!dmd.uuid || dmd.target != DM_CRYPT) {
                r = -EINVAL;
                goto out;
        }
 
-       r = device_check_and_adjust(cd, dmd.u.crypt.device, DEV_OK, &new_size,
+       r = device_check_and_adjust(cd, dmd.data_device, DEV_OK, &new_size,
                                    &dmd.u.crypt.offset, &dmd.flags);
        if (r)
                goto out;
@@ -1195,12 +1255,14 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
                r = 0;
        } else {
                dmd.size = new_size;
-               r = dm_create_device(name, cd->type, &dmd, NULL, 1);
+               r = dm_create_device(name, cd->type, &dmd, 1);
        }
 out:
-       crypt_free_volume_key(dmd.u.crypt.vk);
-       free(CONST_CAST(void*)dmd.u.crypt.cipher);
-       free(CONST_CAST(void*)dmd.u.crypt.device);
+       if (dmd.target == DM_CRYPT) {
+               crypt_free_volume_key(dmd.u.crypt.vk);
+               free(CONST_CAST(void*)dmd.u.crypt.cipher);
+       }
+       free(CONST_CAST(void*)dmd.data_device);
        free(CONST_CAST(void*)dmd.uuid);
 
        return r;
@@ -2342,6 +2404,9 @@ int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)),
        if (r < 0)
                return r;
 
+       if (dmd.target != DM_CRYPT)
+               return -ENOTSUP;
+
        cad->offset     = dmd.u.crypt.offset;
        cad->iv_offset  = dmd.u.crypt.iv_offset;
        cad->size       = dmd.size;
index 7a8c8cc..5a0756e 100644 (file)
@@ -39,19 +39,24 @@ struct crypt_params_verity;
 uint32_t dm_flags(void);
 
 #define DM_ACTIVE_DEVICE       (1 << 0)
-#define DM_ACTIVE_CIPHER       (1 << 1)
-#define DM_ACTIVE_UUID         (1 << 2)
-#define DM_ACTIVE_KEYSIZE      (1 << 3)
-#define DM_ACTIVE_KEY          (1 << 4)
+#define DM_ACTIVE_UUID         (1 << 1)
+
+#define DM_ACTIVE_CRYPT_CIPHER (1 << 2)
+#define DM_ACTIVE_CRYPT_KEYSIZE        (1 << 3)
+#define DM_ACTIVE_CRYPT_KEY    (1 << 4)
+
+#define DM_ACTIVE_VERITY_ROOT_HASH     (1 << 5)
+#define DM_ACTIVE_VERITY_HASH_DEVICE   (1 << 6)
+#define DM_ACTIVE_VERITY_PARAMS                (1 << 7)
 
 struct crypt_dm_active_device {
        enum { DM_CRYPT = 0, DM_VERITY } target;
        uint64_t size;          /* active device size */
        uint32_t flags;         /* activation flags */
        const char *uuid;
+       const char *data_device;
        union {
        struct {
-               const char *device;
                const char *cipher;
 
                /* Active key for device */
@@ -62,13 +67,13 @@ struct crypt_dm_active_device {
                uint64_t iv_offset;     /* IV initilisation sector */
        } crypt;
        struct {
-               const char *data_device;
                const char *hash_device;
 
                const char *root_hash;
-               size_t root_hash_size;
+               uint32_t root_hash_size;
 
                uint64_t hash_offset;   /* hash offset (not header) */
+               struct crypt_params_verity *vp;
        } verity;
        } u;
 };
@@ -85,7 +90,6 @@ int dm_query_device(const char *name, uint32_t get_flags,
 int dm_create_device(const char *name,
                      const char *type,
                      struct crypt_dm_active_device *dmd,
-                     void *params,
                      int reload);
 int dm_suspend_and_wipe_key(const char *name);
 int dm_resume_and_reinstate_key(const char *name,
index 81d6349..b53edba 100644 (file)
@@ -190,7 +190,7 @@ int VERITY_activate(struct crypt_device *cd,
                return 0;
 
        dmd.target = DM_VERITY;
-       dmd.u.verity.data_device = crypt_get_device_name(cd);
+       dmd.data_device = crypt_get_device_name(cd);
        dmd.u.verity.hash_device = hash_device;
        dmd.u.verity.root_hash = root_hash;
        dmd.u.verity.root_hash_size = root_hash_size;
@@ -198,13 +198,14 @@ int VERITY_activate(struct crypt_device *cd,
        dmd.flags = CRYPT_ACTIVATE_READONLY;
        dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
        dmd.uuid = NULL;
+       dmd.u.verity.vp = verity_hdr;
 
-       r = device_check_and_adjust(cd, dmd.u.verity.data_device, DEV_EXCL,
+       r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
                                    &dmd.size, &offset, &dmd.flags);
        if (r)
                return r;
 
-       r = dm_create_device(name, CRYPT_VERITY, &dmd, verity_hdr, 0);
+       r = dm_create_device(name, CRYPT_VERITY, &dmd, 0);
        if (!r && !(dm_flags() & DM_VERITY_SUPPORTED)) {
                log_err(cd, _("Kernel doesn't support dm-verity mapping.\n"));
                return -ENOTSUP;
index dde6aec..8b3228b 100644 (file)
@@ -489,6 +489,8 @@ static int action_status(int arg __attribute__((unused)))
        }
 out:
        crypt_free(cd);
+       if (r == -ENOTSUP)
+               r = 0;
        return r;
 }
 
index e6a08e4..87b2ab6 100644 (file)
  */
 
 /* TODO:
- * - init_by_name()
  * - support device without superblock
  * - audit alloc errors / error path
  * - change command names (cryptsetup style)
  * - extend superblock (UUID)
+ * - add api tests
  */
 
 #include <stdio.h>
@@ -40,6 +40,7 @@
 #define MODE_CREATE    1
 #define MODE_ACTIVATE  2
 #define MODE_DUMP      3
+#define MODE_STATUS    4
 
 static int mode = -1;
 static int use_superblock = 1; /* FIXME: no superblock not supported */
@@ -145,6 +146,18 @@ static int action_dump(void)
        return r;
 }
 
+static int action_status(void)
+{
+       struct crypt_device *cd = NULL;
+       int r;
+
+       r = crypt_init_by_name_and_header(&cd, dm_device, NULL);
+       if (!r)
+               r = crypt_dump(cd);
+       crypt_free(cd);
+       return r;
+}
+
 static int action_activate(int verify)
 {
        struct crypt_device *cd = NULL;
@@ -292,6 +305,7 @@ int main(int argc, const char **argv)
                { "verify",             'v',    POPT_ARG_VAL, &mode, MODE_VERIFY, "Verify integrity", NULL },
                { "activate",           'a',    POPT_ARG_VAL, &mode, MODE_ACTIVATE, "Activate the device", NULL },
                { "dump",               'd',    POPT_ARG_VAL, &mode, MODE_DUMP, "Dump the device", NULL },
+               { "status",             's',    POPT_ARG_VAL, &mode, MODE_STATUS, "Status active device", NULL },
                { "no-superblock",      0,      POPT_ARG_VAL, &use_superblock, 0, "Do not create/use superblock" },
                { "format",             0,      POPT_ARG_INT, &version, 0, "Format version (1 - normal format, 0 - original Chromium OS format)", "number" },
                { "data-block-size",    0,      POPT_ARG_INT, &data_block_size, 0, "Block size on the data device", "bytes" },
@@ -335,7 +349,7 @@ int main(int argc, const char **argv)
                usage(popt_context, EXIT_FAILURE, _("Unknown action."),
                      poptGetInvocationName(popt_context));
 
-       if (mode == MODE_ACTIVATE) {
+       if (mode == MODE_ACTIVATE || mode == MODE_STATUS) {
                dm_device = poptGetArg(popt_context);
                if (!dm_device || !*dm_device)
                        usage(popt_context, EXIT_FAILURE,
@@ -343,6 +357,9 @@ int main(int argc, const char **argv)
                              poptGetInvocationName(popt_context));
        }
 
+       if (mode == MODE_STATUS)
+               goto run; //FIXME
+
        data_device = poptGetArg(popt_context);
        if (!data_device)
                usage(popt_context, EXIT_FAILURE, _("Missing data device name."),
@@ -383,7 +400,7 @@ int main(int argc, const char **argv)
                        salt_string = "";
                salt_size = strlen(salt_string) / 2;
        }
-
+run:
        if (opt_debug) {
                opt_verbose = 1;
                crypt_set_debug_level(-1);
@@ -403,6 +420,9 @@ int main(int argc, const char **argv)
                case MODE_DUMP:
                        r = action_dump();
                        break;
+               case MODE_STATUS:
+                       r = action_status();
+                       break;
        }
 
        poptFreeContext(popt_context);