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(a)veillard.com | Rpmfind RPM search engine
http://rpmfind.net/
http://veillard.com/ | virtualization library
http://libvirt.org/