dnode_end_t mdn;
grub_uint64_t obj;
grub_uint64_t case_insensitive;
- grub_crypto_cipher_handle_t cipher;
+ grub_size_t nkeys;
+ struct
+ {
+ grub_crypto_cipher_handle_t cipher;
+ grub_uint64_t txg;
+ } *keyring;
};
struct grub_zfs_data
if (!grub_zfs_decrypt)
err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded");
else
- err = grub_zfs_decrypt (data->subvol.cipher, &(bp)->blk_dva[encrypted],
- compbuf, psize, ((grub_uint32_t *) &zc + 5),
- endian);
+ {
+ unsigned i, besti = 0;
+ grub_uint64_t bestval = 0;
+ for (i = 0; i < data->subvol.nkeys; i++)
+ if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth,
+ endian)
+ && data->subvol.keyring[i].txg > bestval)
+ {
+ besti = i;
+ bestval = data->subvol.keyring[i].txg;
+ }
+ if (bestval == 0)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
+ grub_zfs_to_cpu64 (bp->blk_birth,
+ endian));
+ return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
+ }
+ grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
+ ", %p) for txg %" PRIxGRUB_UINT64_T "\n",
+ besti, data->subvol.keyring[besti].txg,
+ data->subvol.keyring[besti].cipher,
+ grub_zfs_to_cpu64 (bp->blk_birth,
+ endian));
+ err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
+ &(bp)->blk_dva[encrypted],
+ compbuf, psize, ((grub_uint32_t *) &zc + 5),
+ endian);
+ }
if (err)
{
grub_free (compbuf);
/* XXX */
static int
fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap,
- int NESTED_FUNC_ATTR (*hook) (const char *name,
+ grub_size_t name_elem_length,
+ int NESTED_FUNC_ATTR (*hook) (const void *name,
+ grub_size_t name_length,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize),
if (le->le_type != ZAP_CHUNK_ENTRY)
continue;
- buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
- + 1);
+ buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian)
+ * name_elem_length + 1);
if (zap_leaf_array_get (l, endian, blksft,
grub_zfs_to_cpu16 (le->le_name_chunk,
endian),
grub_zfs_to_cpu16 (le->le_name_length,
- endian), buf))
+ endian)
+ * name_elem_length, buf))
{
grub_free (buf);
continue;
}
- buf[le->le_name_length] = 0;
+ buf[le->le_name_length * name_elem_length] = 0;
val_length = ((int) le->le_value_length
* (int) le->le_int_size);
continue;
}
- if (hook (buf, val, le->le_value_length, le->le_int_size))
+ if (hook (buf, le->le_name_length,
+ val, le->le_value_length, le->le_int_size))
return 1;
grub_free (buf);
grub_free (val);
int ret;
grub_zfs_endian_t endian;
- auto int NESTED_FUNC_ATTR transform (const char *name,
+ auto int NESTED_FUNC_ATTR transform (const void *name,
+ grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize);
- int NESTED_FUNC_ATTR transform (const char *name,
+ int NESTED_FUNC_ATTR transform (const void *name,
+ grub_size_t namelen __attribute__ ((unused)),
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize)
{
grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */
- ret = fzap_iterate (zap_dnode, zapbuf, transform, data);
+ ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data);
grub_free (zapbuf);
return ret;
}
static int
zap_iterate (dnode_end_t * zap_dnode,
- int NESTED_FUNC_ATTR (*hook) (const char *name,
+ grub_size_t nameelemlen,
+ int NESTED_FUNC_ATTR (*hook) (const void *name,
+ grub_size_t namelen,
const void *val_in,
grub_size_t nelem,
grub_size_t elemsize),
{
grub_dprintf ("zfs", "fat zap\n");
/* this is a fat zap */
- ret = fzap_iterate (zap_dnode, zapbuf, hook, data);
+ ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data);
grub_free (zapbuf);
return ret;
}
grub_uint64_t keychainobj;
grub_uint64_t salt;
grub_err_t err;
+ int keyn = 0;
+
+ auto int NESTED_FUNC_ATTR count_zap_keys (const void *name,
+ grub_size_t namelen,
+ const void *val_in,
+ grub_size_t nelem,
+ grub_size_t elemsize);
+ int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)),
+ grub_size_t namelen __attribute__ ((unused)),
+ const void *val_in __attribute__ ((unused)),
+ grub_size_t nelem __attribute__ ((unused)),
+ grub_size_t elemsize __attribute__ ((unused)))
+ {
+ subvol->nkeys++;
+ return 0;
+ }
-
- auto int NESTED_FUNC_ATTR iterate_zap_key (const char *name,
- const void *val_in,
- grub_size_t nelem,
- grub_size_t elemsize);
- int NESTED_FUNC_ATTR iterate_zap_key (const char *name __attribute__ ((unused)),
- const void *val_in,
- grub_size_t nelem,
- grub_size_t elemsize)
+ auto int NESTED_FUNC_ATTR load_zap_key (const void *name,
+ grub_size_t namelen,
+ const void *val_in,
+ grub_size_t nelem,
+ grub_size_t elemsize);
+ int NESTED_FUNC_ATTR load_zap_key (const void *name,
+ grub_size_t namelen,
+ const void *val_in,
+ grub_size_t nelem,
+ grub_size_t elemsize)
{
+ if (namelen != 1)
+ {
+ grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n",
+ namelen);
+ return 0;
+ }
+
if (elemsize != 1)
{
grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n",
return 0;
}
- subvol->cipher = grub_zfs_load_key (val_in, nelem, salt);
+ subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name);
+ subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt);
+ keyn++;
return 0;
}
grub_free (snapname);
return err;
}
- zap_iterate (&keychain_dn, iterate_zap_key, data);
+ subvol->nkeys = 0;
+ zap_iterate (&keychain_dn, 8, count_zap_keys, data);
+ subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0]));
+ if (!subvol->keyring)
+ {
+ grub_free (fsname);
+ grub_free (snapname);
+ return err;
+ }
+ zap_iterate (&keychain_dn, 8, load_zap_key, data);
}
if (snapname)
grub_free (data->dnode_buf);
grub_free (data->dnode_mdn);
grub_free (data->file_buf);
- grub_crypto_cipher_close (data->subvol.cipher);
+ for (i = 0; i < data->subvol.nkeys; i++)
+ grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
+ grub_free (data->subvol.keyring);
grub_free (data);
}