diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 97939df48d24c690c094a96e6edd9d840f68219a..1e0bde6aacbe600f610fed8c669770b951810588 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -349,6 +349,113 @@ qemuHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED, } +static virStorageEncryptionPtr +findDomainDiskEncryption(virConnectPtr conn, 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 (seen_volume) + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("missing for volume %s"), path); + else + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unexpected passphrase request for volume %s"), + path); + return NULL; +} + + +static int +findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virConnectPtr conn, + virDomainObjPtr vm, + const char *path, + char **secretRet, + size_t *secretLen) +{ + virStorageEncryptionPtr enc; + virSecretPtr secret; + char *passphrase; + unsigned char *data; + size_t size; + + if (!conn) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, + "%s", _("cannot find secrets without a connection")); + return -1; + } + + if (conn->secretDriver == NULL || + conn->secretDriver->lookupByUUID == NULL || + conn->secretDriver->getValue == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", + _("secret storage not supported")); + return -1; + } + + enc = findDomainDiskEncryption(conn, 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) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _("invalid for volume %s"), path); + return -1; + } + + secret = conn->secretDriver->lookupByUUID(conn, + enc->secrets[0]->uuid); + if (secret == NULL) + return -1; + data = conn->secretDriver->getValue(secret, &size, + VIR_SECRET_GET_VALUE_INTERNAL_CALL); + virUnrefSecret(secret); + if (data == NULL) + return -1; + + if (memchr(data, '\0', size) != NULL) { + memset(data, 0, size); + VIR_FREE(data); + qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET, + _("format='qcow' passphrase for %s must not contain a " + "'\\0'"), path); + return -1; + } + + if (VIR_ALLOC_N(passphrase, size + 1) < 0) { + memset(data, 0, size); + VIR_FREE(data); + virReportOOMError(conn); + return -1; + } + memcpy(passphrase, data, size); + passphrase[size] = '\0'; + + memset(data, 0, size); + VIR_FREE(data); + + *secretRet = passphrase; + *secretLen = size; + + return 0; +} + static int qemuConnectMonitor(virDomainObjPtr vm, int reconnect) { @@ -359,6 +466,9 @@ qemuConnectMonitor(virDomainObjPtr vm, int reconnect) return -1; } + qemuMonitorRegisterDiskSecretLookup(priv->mon, + findVolumeQcowPassphrase); + return 0; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 5f7e20cb3042a79cf9b0e07d3dcd7934f1878048..352328db3a0ee7493665e296059338847828ca53 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -45,6 +45,7 @@ struct _qemuMonitor { virDomainObjPtr vm; qemuMonitorEOFNotify eofCB; + qemuMonitorDiskSecretLookup secretCB; }; /* Return -1 for error, 1 to continue reading and 0 for success */ @@ -322,6 +323,7 @@ qemuMonitorOpen(virDomainObjPtr vm, goto cleanup; } + return mon; cleanup: @@ -344,6 +346,13 @@ void qemuMonitorClose(qemuMonitorPtr mon) } +void qemuMonitorRegisterDiskSecretLookup(qemuMonitorPtr mon, + qemuMonitorDiskSecretLookup secretCB) +{ + mon->secretCB = secretCB; +} + + int qemuMonitorWrite(qemuMonitorPtr mon, const char *data, size_t len) @@ -410,3 +419,16 @@ retry: } return 0; } + + +int qemuMonitorGetDiskSecret(qemuMonitorPtr mon, + virConnectPtr conn, + const char *path, + char **secret, + size_t *secretLen) +{ + *secret = NULL; + *secretLen = 0; + + return mon->secretCB(mon, conn, mon->vm, path, secret, secretLen); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index e863e20811e51756d6830dbcd2a46ad8252943c8..6fb99a927fd2a62a2679e2e3769753c888b77b73 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -36,12 +36,27 @@ typedef void (*qemuMonitorEOFNotify)(qemuMonitorPtr mon, virDomainObjPtr vm, int withError); +/* XXX we'd really like to avoid virCOnnectPtr here + * It is required so the callback can find the active + * secret driver. Need to change this to work like the + * security drivers do, to avoid this + */ +typedef int (*qemuMonitorDiskSecretLookup)(qemuMonitorPtr mon, + virConnectPtr conn, + virDomainObjPtr vm, + const char *path, + char **secret, + size_t *secretLen); + qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm, int reconnect, qemuMonitorEOFNotify eofCB); void qemuMonitorClose(qemuMonitorPtr mon); +void qemuMonitorRegisterDiskSecretLookup(qemuMonitorPtr mon, + qemuMonitorDiskSecretLookup secretCB); + int qemuMonitorWrite(qemuMonitorPtr mon, const char *data, size_t len); @@ -57,5 +72,10 @@ int qemuMonitorRead(qemuMonitorPtr mon, int qemuMonitorWaitForInput(qemuMonitorPtr mon); +int qemuMonitorGetDiskSecret(qemuMonitorPtr mon, + virConnectPtr conn, + const char *path, + char **secret, + size_t *secretLen); #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 615da1966113d92626812126e13ba9839a8db785..86bdab1d217f1e3d1bcc7963d020b4da5d752eb3 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -336,101 +336,6 @@ qemuMonitorCommand(const virDomainObjPtr vm, } - -static virStorageEncryptionPtr -findDomainDiskEncryption(virConnectPtr conn, 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 (seen_volume) - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, - _("missing for volume %s"), path); - else - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unexpected passphrase request for volume %s"), - path); - return NULL; -} - -static char * -findVolumeQcowPassphrase(virConnectPtr conn, virDomainObjPtr vm, - const char *path, size_t *passphrase_len) -{ - virStorageEncryptionPtr enc; - virSecretPtr secret; - char *passphrase; - unsigned char *data; - size_t size; - - if (conn->secretDriver == NULL || - conn->secretDriver->lookupByUUID == NULL || - conn->secretDriver->getValue == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s", - _("secret storage not supported")); - return NULL; - } - - enc = findDomainDiskEncryption(conn, vm, path); - if (enc == NULL) - return NULL; - - if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW || - enc->nsecrets != 1 || - enc->secrets[0]->type != - VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, - _("invalid for volume %s"), path); - return NULL; - } - - secret = conn->secretDriver->lookupByUUID(conn, - enc->secrets[0]->uuid); - if (secret == NULL) - return NULL; - data = conn->secretDriver->getValue(secret, &size, - VIR_SECRET_GET_VALUE_INTERNAL_CALL); - virUnrefSecret(secret); - if (data == NULL) - return NULL; - - if (memchr(data, '\0', size) != NULL) { - memset(data, 0, size); - VIR_FREE(data); - qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET, - _("format='qcow' passphrase for %s must not contain a " - "'\\0'"), path); - return NULL; - } - - if (VIR_ALLOC_N(passphrase, size + 1) < 0) { - memset(data, 0, size); - VIR_FREE(data); - virReportOOMError(conn); - return NULL; - } - memcpy(passphrase, data, size); - passphrase[size] = '\0'; - - memset(data, 0, size); - VIR_FREE(data); - - *passphrase_len = size; - return passphrase; -} - static int qemuMonitorSendVolumePassphrase(const virDomainObjPtr vm, const char *buf, @@ -438,7 +343,8 @@ qemuMonitorSendVolumePassphrase(const virDomainObjPtr vm, void *data) { virConnectPtr conn = data; - char *passphrase, *path; + qemuDomainObjPrivatePtr priv = vm->privateData; + char *passphrase = NULL, *path; const char *prompt_path; size_t path_len, passphrase_len = 0; int res; @@ -458,9 +364,10 @@ qemuMonitorSendVolumePassphrase(const virDomainObjPtr vm, memcpy(path, prompt_path, path_len); path[path_len] = '\0'; - passphrase = findVolumeQcowPassphrase(conn, vm, path, &passphrase_len); + res = qemuMonitorGetDiskSecret(priv->mon, conn, path, + &passphrase, &passphrase_len); VIR_FREE(path); - if (passphrase == NULL) + if (res < 0) return -1; res = qemuMonitorSend(vm, passphrase, -1);