[libvirt] [PATCH] Support 'block_passwd' command for QEMU disk encryption
Daniel Veillard
veillard at redhat.com
Thu Feb 11 15:28:12 UTC 2010
On Thu, Feb 11, 2010 at 02:31:37PM +0000, Daniel P. Berrange wrote:
> The old text mode monitor prompts for a password when disks are
> encrypted. This interactive approach doesn't work for JSON mode
> monitor. Thus there is a new 'block_passwd' command that can be
> used.
>
> * src/qemu/qemu_driver.c: Split out code for looking up a disk
> secret from findVolumeQcowPassphrase, into a new method
> getVolumeQcowPassphrase. Enhance qemuInitPasswords() to also
> set the disk encryption password via the monitor
> * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
> src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h,
> src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Add
> support for the 'block_passwd' monitor command.
> ---
> src/qemu/qemu_driver.c | 117 +++++++++++++++++++++++++++++-------------
> src/qemu/qemu_monitor.c | 15 +++++
> src/qemu/qemu_monitor.h | 4 ++
> src/qemu/qemu_monitor_json.c | 33 ++++++++++++
> src/qemu/qemu_monitor_json.h | 4 ++
> src/qemu/qemu_monitor_text.c | 47 +++++++++++++++++
> src/qemu/qemu_monitor_text.h | 4 ++
> 7 files changed, 188 insertions(+), 36 deletions(-)
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 0d77d57..03d0f5f 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -694,51 +694,46 @@ qemuHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> }
>
>
> -static virStorageEncryptionPtr
> -findDomainDiskEncryption(virDomainObjPtr vm,
> - const char *path)
> +static virDomainDiskDefPtr
> +findDomainDiskByPath(virDomainObjPtr vm,
> + const char *path)
> {
> - bool seen_volume;
> int i;
>
> - seen_volume = false;
> for (i = 0; i < vm->def->ndisks; i++) {
> virDomainDiskDefPtr disk;
>
> disk = vm->def->disks[i];
> - if (disk->src != NULL && STREQ(disk->src, path)) {
> - seen_volume = true;
> - if (disk->encryption != NULL)
> - return disk->encryption;
> - }
> + if (disk->src != NULL && STREQ(disk->src, path))
> + return disk;
> }
> - if (seen_volume)
> - qemuReportError(VIR_ERR_INVALID_DOMAIN,
> - _("missing <encryption> for volume %s"), path);
> - else
> - qemuReportError(VIR_ERR_INTERNAL_ERROR,
> - _("unexpected passphrase request for volume %s"),
> - path);
> +
> + qemuReportError(VIR_ERR_INTERNAL_ERROR,
> + _("no disk found with path %s"),
> + path);
> return NULL;
> }
>
> -
> static int
> -findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> - virConnectPtr conn,
> - virDomainObjPtr vm,
> - const char *path,
> - char **secretRet,
> - size_t *secretLen)
> +getVolumeQcowPassphrase(virConnectPtr conn,
> + virDomainDiskDefPtr disk,
> + char **secretRet,
> + size_t *secretLen)
> {
> - virStorageEncryptionPtr enc;
> virSecretPtr secret;
> char *passphrase;
> unsigned char *data;
> size_t size;
> int ret = -1;
> + virStorageEncryptionPtr enc;
>
> - virDomainObjLock(vm);
> + if (!disk->encryption) {
> + qemuReportError(VIR_ERR_INTERNAL_ERROR,
> + _("disk %s does not have any encryption information"),
> + disk->src);
> + return -1;
> + }
> + enc = disk->encryption;
>
> if (!conn) {
> qemuReportError(VIR_ERR_NO_SUPPORT,
> @@ -754,16 +749,12 @@ findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> goto cleanup;
> }
>
> - enc = findDomainDiskEncryption(vm, path);
> - if (enc == NULL)
> - return -1;
> -
> if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
> enc->nsecrets != 1 ||
> enc->secrets[0]->type !=
> VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) {
> qemuReportError(VIR_ERR_INVALID_DOMAIN,
> - _("invalid <encryption> for volume %s"), path);
> + _("invalid <encryption> for volume %s"), disk->src);
> goto cleanup;
> }
>
> @@ -782,7 +773,7 @@ findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> VIR_FREE(data);
> qemuReportError(VIR_ERR_INVALID_SECRET,
> _("format='qcow' passphrase for %s must not contain a "
> - "'\\0'"), path);
> + "'\\0'"), disk->src);
> goto cleanup;
> }
>
> @@ -804,8 +795,30 @@ findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> ret = 0;
>
> cleanup:
> - virDomainObjUnlock(vm);
> + return ret;
> +}
>
> +static int
> +findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> + virConnectPtr conn,
> + virDomainObjPtr vm,
> + const char *path,
> + char **secretRet,
> + size_t *secretLen)
> +{
> + virDomainDiskDefPtr disk;
> + int ret = -1;
> +
> + virDomainObjLock(vm);
> + disk = findDomainDiskByPath(vm, path);
> +
> + if (!disk)
> + goto cleanup;
> +
> + ret = getVolumeQcowPassphrase(conn, disk, secretRet, secretLen);
> +
> +cleanup:
> + virDomainObjUnlock(vm);
> return ret;
> }
>
> @@ -1681,8 +1694,10 @@ qemudInitCpuAffinity(virDomainObjPtr vm)
>
>
> static int
> -qemuInitPasswords(struct qemud_driver *driver,
> - virDomainObjPtr vm) {
> +qemuInitPasswords(virConnectPtr conn,
> + struct qemud_driver *driver,
> + virDomainObjPtr vm,
> + unsigned long long qemuCmdFlags) {
> int ret = 0;
> qemuDomainObjPrivatePtr priv = vm->privateData;
>
> @@ -1698,6 +1713,36 @@ qemuInitPasswords(struct qemud_driver *driver,
> qemuDomainObjExitMonitorWithDriver(driver, vm);
> }
>
> + if (ret < 0)
> + goto cleanup;
> +
> + if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
> + int i;
> +
> + for (i = 0 ; i < vm->def->ndisks ; i++) {
> + char *secret;
> + size_t secretLen;
> +
> + if (!vm->def->disks[i]->encryption ||
> + !vm->def->disks[i]->src)
> + continue;
> +
> + if (getVolumeQcowPassphrase(conn,
> + vm->def->disks[i],
> + &secret, &secretLen) < 0)
> + goto cleanup;
> +
> + qemuDomainObjEnterMonitorWithDriver(driver, vm);
> + ret = qemuMonitorSetDrivePassphrase(priv->mon,
> + vm->def->disks[i]->info.alias,
> + secret);
> + qemuDomainObjExitMonitorWithDriver(driver, vm);
> + if (ret < 0)
> + goto cleanup;
> + }
> + }
> +
> +cleanup:
> return ret;
> }
>
> @@ -2721,7 +2766,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
> if (qemudInitCpuAffinity(vm) < 0)
> goto abort;
>
> - if (qemuInitPasswords(driver, vm) < 0)
> + if (qemuInitPasswords(conn, driver, vm, qemuCmdFlags) < 0)
> goto abort;
>
> /* If we have -device, then addresses are assigned explicitly.
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 64c6cba..c1d369b 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -1331,3 +1331,18 @@ int qemuMonitorAddDrive(qemuMonitorPtr mon,
> ret = qemuMonitorTextAddDrive(mon, drivestr);
> return ret;
> }
> +
> +
> +int qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase)
> +{
> + DEBUG("mon=%p, fd=%d alias=%s passphrase=%p(value hidden)", mon, mon->fd, alias, passphrase);
> + int ret;
> +
> + if (mon->json)
> + ret = qemuMonitorJSONSetDrivePassphrase(mon, alias, passphrase);
> + else
> + ret = qemuMonitorTextSetDrivePassphrase(mon, alias, passphrase);
> + return ret;
> +}
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index a330eff..786ad7a 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -291,4 +291,8 @@ int qemuMonitorAddDevice(qemuMonitorPtr mon,
> int qemuMonitorAddDrive(qemuMonitorPtr mon,
> const char *drivestr);
>
> +int qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase);
> +
> #endif /* QEMU_MONITOR_H */
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 032afef..c9b8d60 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -1841,3 +1841,36 @@ int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
> virJSONValueFree(reply);
> return ret;
> }
> +
> +
> +int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase)
> +{
> + int ret;
> + virJSONValuePtr cmd;
> + virJSONValuePtr reply = NULL;
> + char *drive;
> +
> + if (virAsprintf(&drive, "%s%s", QEMU_DRIVE_HOST_PREFIX, alias) < 0) {
> + virReportOOMError();
> + return -1;
> + }
> +
> + cmd = qemuMonitorJSONMakeCommand("block_passwd",
> + "s:device", drive,
> + "s:password", passphrase,
> + NULL);
> + VIR_FREE(drive);
> + if (!cmd)
> + return -1;
> +
> + ret = qemuMonitorJSONCommand(mon, cmd, &reply);
> +
> + if (ret == 0)
> + ret = qemuMonitorJSONCheckError(cmd, reply);
> +
> + virJSONValueFree(cmd);
> + virJSONValueFree(reply);
> + return ret;
> +}
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index ac6458c..65a70e3 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -162,4 +162,8 @@ int qemuMonitorJSONAddDevice(qemuMonitorPtr mon,
> int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
> const char *drivestr);
>
> +int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase);
> +
> #endif /* QEMU_MONITOR_JSON_H */
> diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
> index a6a4598..e993699 100644
> --- a/src/qemu/qemu_monitor_text.c
> +++ b/src/qemu/qemu_monitor_text.c
> @@ -2127,3 +2127,50 @@ cleanup:
> VIR_FREE(safe_str);
> return ret;
> }
> +
> +
> +int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase)
> +{
> + char *cmd = NULL;
> + char *reply = NULL;
> + int ret = -1;
> + char *safe_str;
> +
> + safe_str = qemuMonitorEscapeArg(passphrase);
> + if (!safe_str) {
> + virReportOOMError();
> + return -1;
> + }
> +
> + ret = virAsprintf(&cmd, "block_passwd %s%s \"%s\"", QEMU_DRIVE_HOST_PREFIX, alias, safe_str);
> + if (ret == -1) {
> + virReportOOMError();
> + goto cleanup;
> + }
> +
> + if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
> + qemuReportError(VIR_ERR_OPERATION_FAILED,
> + _("failed to close fd in qemu with '%s'"), cmd);
> + goto cleanup;
> + }
> +
> + if (strstr(reply, "\nunknown command:")) {
> + qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
> + _("setting disk password is not supported"));
> + goto cleanup;
> + } else if (strstr(reply, "The entered password is invalid")) {
> + qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
> + _("the disk password is incorrect"));
> + goto cleanup;
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + VIR_FREE(cmd);
> + VIR_FREE(reply);
> + VIR_FREE(safe_str);
> + return ret;
> +}
> diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
> index 12d75f5..1937e99 100644
> --- a/src/qemu/qemu_monitor_text.h
> +++ b/src/qemu/qemu_monitor_text.h
> @@ -166,4 +166,8 @@ int qemuMonitorTextAddDevice(qemuMonitorPtr mon,
> int qemuMonitorTextAddDrive(qemuMonitorPtr mon,
> const char *drivestr);
>
> +int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
> + const char *alias,
> + const char *passphrase);
> +
> #endif /* QEMU_MONITOR_TEXT_H */
Looks fine, ACK,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list