diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a2be1a300e..d596109cdb 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 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 for volume %s"), path); + _("invalid 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 64c6cbacf7..c1d369b218 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 a330eff084..786ad7abe1 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 032afef1b6..c9b8d6049f 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 ac6458c548..65a70e3194 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 a6a4598e3a..e993699f4b 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 12d75f512f..1937e99957 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 */