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 */ -- 1.6.5.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list