Re: [libvirt] [PATCH] Small fixes for qemu save compression.
Daniel Veillard wrote: On Mon, Aug 17, 2009 at 12:37:31PM +0200, Chris Lalancette wrote: Fix up a small memory leak pointed out by DanB; I was forgetting to release memory allocated to driver-saveImageFormat. Also add the save_image_format and security entries to the augeas lens. ACK ! Thanks, committed. -- Chris Lalancette -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] libvirt with libssh2?
Hi, I'm the package maintainer of libvirt for the Pardus distribution. While trying to update the package to the latest 0.7.0, I recognized that configure script does not find libssh. I checked our system and found out that we are using libssh2 instead of libssh. From this website (http://www.libssh2.org/libssh2-vs-libssh.html), libssh2 developers summarize their differences. My questions: 1) Is there a specific reason why we are using libssh? Is there a patch to make libvirt use libssh2 instead? 2) What functionality do we loose if we don't have libssh in the system? (depending on this, I'll also package libssh or not) Thanks a lot for any comments, Best regards, Emre Erenoglu -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] libvirt with libssh2?
On Thu, Aug 20, 2009 at 10:50:37AM +0200, Emre Erenoglu wrote: Hi, I'm the package maintainer of libvirt for the Pardus distribution. While trying to update the package to the latest 0.7.0, I recognized that configure script does not find libssh. I checked our system and found out that we are using libssh2 instead of libssh. From this website (http://www.libssh2.org/libssh2-vs-libssh.html), libssh2 developers summarize their differences. My questions: 1) Is there a specific reason why we are using libssh? Is there a patch to make libvirt use libssh2 instead? 2) What functionality do we loose if we don't have libssh in the system? (depending on this, I'll also package libssh or not) I guess you activated --with-phyp which currently requires libssh, but this will be fixed in the future, the result is just that that driver gets desactivated for now if you don't have libssh see http://www.mail-archive.com/libvir-list@redhat.com/msg15086.html Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ dan...@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] Power Hypervisor: Fix potential segfault and memleak in phypOpen
Matthias Bolte wrote: Hi, I came across this line in the phypOpen function: char string[strlen(conn-uri-path)]; Here the path part of the given URI is used without checking it for NULL, this can cause a segfault as strlen expects a string != NULL. Beside that uuid_db and connection_data leak in case of an error. In this line conn-uri-path = string; the original path of the URI leaks. The patch adds a VIR_FREE call before setting the new path. The attached patch is compile-tested but I don't have a Power Hypervisor installation at hand to test it for real. I've now committed this patch (with some slight munging to get it to apply to recent libvirt.git). Thanks, -- Chris Lalancette -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] Power Hypervisor: Fix potential segfault and memleak in phypOpen
2009/8/20 Chris Lalancette clala...@redhat.com: Matthias Bolte wrote: Hi, I came across this line in the phypOpen function: char string[strlen(conn-uri-path)]; Here the path part of the given URI is used without checking it for NULL, this can cause a segfault as strlen expects a string != NULL. Beside that uuid_db and connection_data leak in case of an error. In this line conn-uri-path = string; the original path of the URI leaks. The patch adds a VIR_FREE call before setting the new path. The attached patch is compile-tested but I don't have a Power Hypervisor installation at hand to test it for real. I've now committed this patch (with some slight munging to get it to apply to recent libvirt.git). Thanks, -- Chris Lalancette Well, you should have applied version 2 of this patch, because version 1 was invalidated by changes to escape_specialcharacters(). It now takes a length argument, but string isn't an array anymore (but a char pointer), so sizeof(string) does no longer the right thing: escape_specialcharacters(conn-uri-path, string, sizeof(string)) I attached patch version 2 again. Matthias diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index f457cf4..9b46696 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -63,25 +63,18 @@ static virDrvOpenStatus phypOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) { -SSH_SESSION *session; -ConnectionData *connection_data; -char string[strlen(conn-uri-path)]; - +SSH_SESSION *session = NULL; +ConnectionData *connection_data = NULL; +char *string = NULL; +size_t len = 0; uuid_dbPtr uuid_db = NULL; -if (VIR_ALLOC(uuid_db) 0) -virReportOOMError(conn); - -if (VIR_ALLOC(connection_data) 0) -virReportOOMError(conn); - if (!conn || !conn-uri) return VIR_DRV_OPEN_DECLINED; if (conn-uri-scheme == NULL || STRNEQ(conn-uri-scheme, phyp)) return VIR_DRV_OPEN_DECLINED; - if (conn-uri-server == NULL) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, %s, @@ -96,20 +89,38 @@ phypOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } -if (escape_specialcharacters(conn-uri-path, string, sizeof(string)) == -1) { +if (VIR_ALLOC(uuid_db) 0) { +virReportOOMError(conn); +goto failure; +} + +if (VIR_ALLOC(connection_data) 0) { +virReportOOMError(conn); +goto failure; +} + +len = strlen(conn-uri-path) + 1; + +if (VIR_ALLOC_N(string, len) 0) { +virReportOOMError(conn); +goto failure; +} + +if (escape_specialcharacters(conn-uri-path, string, len) == -1) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, %s, _(Error parsing 'path'. Invalid characters.)); -return VIR_DRV_OPEN_ERROR; +goto failure; } if ((session = openSSHSession(conn, auth)) == NULL) { virRaiseError(conn, NULL, NULL, 0, VIR_FROM_PHYP, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, %s, _(Error while opening SSH session.)); -return VIR_DRV_OPEN_ERROR; +goto failure; } +VIR_FREE(conn-uri-path); conn-uri-path = string; connection_data-session = session; connection_data-auth = auth; @@ -122,6 +133,13 @@ phypOpen(virConnectPtr conn, init_uuid_db(conn); return VIR_DRV_OPEN_SUCCESS; + + failure: +VIR_FREE(uuid_db); +VIR_FREE(connection_data); +VIR_FREE(string); + +return VIR_DRV_OPEN_ERROR; } static int -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Introduce virStrcpy.
Daniel P. Berrange wrote: On Fri, Aug 07, 2009 at 11:06:29AM +0200, Chris Lalancette wrote: diff --git a/proxy/libvirt_proxy.c b/proxy/libvirt_proxy.c index e008a7f..42084c7 100644 --- a/proxy/libvirt_proxy.c +++ b/proxy/libvirt_proxy.c @@ -167,10 +167,13 @@ proxyListenUnixSocket(const char *path) { * Abstract socket do not hit the filesystem, way more secure and * guaranteed to be atomic */ -memset(addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; addr.sun_path[0] = '\0'; -strncpy(addr.sun_path[1], path, (sizeof(addr) - 4) - 2); +if (virStrcpy(addr.sun_path[1], path, sizeof(addr.sun_path) - 1) == NULL) { +fprintf(stderr, Path %s too long to fit into destination\n, path); +close(fd); +return -1; +} Removing the memset is not safe - the abstract namesapce defines the name to be the *entire* addr.sun_path array. So it must be null filled, otherwise the name will be the string copied + whatever trailing garbage exists Ug, OK, thanks, I've fixed all instances of this. diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 37fdec2..bcacd41 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -5802,8 +5806,11 @@ static int qemuGetSchedulerParameters(virDomainPtr dom, goto cleanup; } params[0].value.ul = val; -strncpy(params[0].field, cpu_shares, sizeof(params[0].field)); -params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG; +if (virStrcpy(params[0].field, cpu_shares, sizeof(params[0].field)) == NULL) { +qemudReportError(dom-conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, + %s, _(Field cpu_shares too long for destination)); +goto cleanup; +} Why remove the assginemnt to 'type' here ? Oversight on my part, thanks for pointing it out. Fixed now. @@ -1573,6 +1572,28 @@ virAsprintf(char **strp, const char *fmt, ...) return ret; } +/** + * virStrcpy + * + * A safe version of strcpy. The last parameter is the number of bytes + * available in the destination string, *not* the number of bytes you want + * to copy. If the destination is not large enough to hold all of the + * src string, NULL is returned and no data is copied. If the destination + * is large enough to hold all of the src, then the string is copied and + * a pointer to the destination string is returned. + */ +char * +virStrcpy(char *dest, const char *src, size_t destbytes) +{ +int len; + +len = strlen(src) + 1; +if (len destbytes) +return NULL; + +return memcpy(dest, src, len); +} Why not just use strncpy() and ensure the trailing null. Seems like it would be more efficient than requiring 2 passes over the string. Hm, I'm not entirely sure I understand you. Do you mean something like: char * virStrcpy(char *dest, const char *src, size_t destbytes) { char *ret; ret = strncpy(dest, src, destbytes); if (ret) ret[destbytes - 1] = '\0'; return ret; } But in this case, there is nowhere that I can return NULL if the destination is too short. Any solution I can think of in the current form requires me to run strlen over the source to check that it isn't too big for the dest. Hm, here's another thought. Maybe I should make the signature: char * virStrcpy(char *dest, const char *src, size_t srclen, size_t destbytes); Then, the first three parameters would actually be exactly the same as for strncpy() (meaning that you could tell it to stop copying short of the \0 in src). The additional destbytes parameter is the safety parameter to make sure the dest is big enough. Of course, this sort of just punts the two-pass strlen() problem off to the callers, but for callers that already know the length they can just pass it in here without an additional penalty. Or did you have another idea? index b3e628a..ffbf2b3 100644 --- a/src/util.h +++ b/src/util.h @@ -164,6 +164,7 @@ void virSkipSpaces(const char **str); int virParseNumber(const char **str); int virAsprintf(char **strp, const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(2, 3); +char *virStrcpy(char *dest, const char *src, size_t destbytes); THis is probably a candidate for ATTRIBUTE_RETURN_CHECK to guarentee that all callers are dealing with the failure case at compile time Done. @@ -1026,42 +1043,46 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { data++; if (STRPREFIX(key, mac=)) { -int len = nextkey ? (nextkey - data) : 17; -if (len 17) -len = 17; -strncpy(mac, data, len); -mac[len] = '\0'; +if (virStrcpy(mac, data, sizeof(mac)) == NULL) { +xenXMError(conn, VIR_ERR_INTERNAL_ERROR, + _(MAC address %s too big for destination), +
Re: [libvirt] Power Hypervisor: Fix potential segfault and memleak in phypOpen
Matthias Bolte wrote: 2009/8/20 Chris Lalancette clala...@redhat.com: Matthias Bolte wrote: Hi, I came across this line in the phypOpen function: char string[strlen(conn-uri-path)]; Here the path part of the given URI is used without checking it for NULL, this can cause a segfault as strlen expects a string != NULL. Beside that uuid_db and connection_data leak in case of an error. In this line conn-uri-path = string; the original path of the URI leaks. The patch adds a VIR_FREE call before setting the new path. The attached patch is compile-tested but I don't have a Power Hypervisor installation at hand to test it for real. I've now committed this patch (with some slight munging to get it to apply to recent libvirt.git). Thanks, -- Chris Lalancette Well, you should have applied version 2 of this patch, because version 1 was invalidated by changes to escape_specialcharacters(). It now takes a length argument, but string isn't an array anymore (but a char pointer), so sizeof(string) does no longer the right thing: escape_specialcharacters(conn-uri-path, string, sizeof(string)) I attached patch version 2 again. Gah, sorry, I totally missed (or forgot about) that. I'll apply the incremental diff, thanks. -- Chris Lalancette -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] libvirt with libssh2?
-- Forwarded message -- From: Daniel Veillard veill...@redhat.com To: Emre Erenoglu ereno...@gmail.com Date: Thu, 20 Aug 2009 11:14:53 +0200 Subject: Re: [libvirt] libvirt with libssh2? On Thu, Aug 20, 2009 at 10:50:37AM +0200, Emre Erenoglu wrote: Hi, I'm the package maintainer of libvirt for the Pardus distribution. While trying to update the package to the latest 0.7.0, I recognized that configure script does not find libssh. I checked our system and found out that we are using libssh2 instead of libssh. From this website (http://www.libssh2.org/libssh2-vs-libssh.html), libssh2 developers summarize their differences. My questions: 1) Is there a specific reason why we are using libssh? Is there a patch to make libvirt use libssh2 instead? 2) What functionality do we loose if we don't have libssh in the system? (depending on this, I'll also package libssh or not) I guess you activated --with-phyp which currently requires libssh, but this will be fixed in the future, the result is just that that driver gets desactivated for now if you don't have libssh see http://www.mail-archive.com/libvir-list@redhat.com/msg15086.html Thanks Daniel. I'm a bit foreign to this Power Hypervisor thing, but if I'm not wrong from the information that I got from this site: http://publib.boulder.ibm.com/infocenter/systems/scope/hw/index.jsp?topic=/iphb2/iphb2hypervisor.htm than it's nothing that we support in Pardus at the moment. In fact, we only support KVM in our libvirt at the moment, possibly virtualbox in the future. In this case, I'm disabling this pyhp as well as the libssh dependency. Thanks a lot for the info and let me know if my understanding is wrong :) -- Emre -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] Migration fail
hi, i am trying to migrate a VM from my local system pc38 to a remote on pc36: virsh # list --all Id Name State -- - scalaris1shut off virsh # migrate scalaris1 qemu+ssh://csr-u...@pc36/system error: monitor socket did not show up.: No such file or directory What is the monitor socket? Both system are ubuntu server 9.04 : christ...@pc38:~$ virsh --version Connecting to uri: qemu:///system 0.6.1 christ...@pc38:~$ Thx for help! Christian -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] Migration fail
Christian Hennig wrote: hi, i am trying to migrate a VM from my local system pc38 to a remote on pc36: virsh # list --all Id Name State -- - scalaris1shut off virsh # migrate scalaris1 qemu+ssh://csr-u...@pc36/system error: monitor socket did not show up.: No such file or directory What is the monitor socket? The monitor socket is how libvirt talks to the qemu monitor to issue commands. Things like virsh suspend are implemented by issuing a stop command to the qemu monitor, and it's fundamental to libvirt operation. The monitor socket did not show up error occurs if libvirt could not connect to the monitor after trying for 3 seconds; it usually means that qemu forked successfully, but failed to really start. You should be able to get a bit more information by looking at /var/log/libvirt/qemu/guestname on the destination of your migration. That being said, I think 0.6.1 had a number of race conditions, so it's probably worthwhile to try and get a newer version of libvirt; 0.6.4 or later should be pretty good. -- Chris Lalancette -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] Add support for (qcow*) volume encryption (v4)
Hello, the following patches add full support for qcow/qcow2 volume encryption, assuming a client that supports it. (Main changes since the previous version: * Add flags argument to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretSetValue(), virSecretGetValue() * Various clean-ups and bug fixes in the local secret storage driver * Make the Python API more consistent with other objects See the specific patch change logs for more details; patches without change logs are unchanged.) New XML tags are defined to represent encryption parameters (currently format and passphrase, more can be added in the future), e.g. encryption format='qcow' secret type='passphrase' uuid='724d95f2-0ed2-6ff9-84d0-0f3d1618428d'/ /encryption The encryption tag can be added to a volume node passed to virStorageVolCreateXML() to create an encrypted volume, or to a disk node inside a domain to specify what encryption parameters to use for a domain. uuid above refers to a separately-managed secret, which was created using virSecretDefineXML() and set using virSecretSetValue(). Other properties of the secret can be managed using an XML representation. Detailed documentation of the formats and features is inside the patches. -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 01/20] Secret manipulation step 1: Public API
This patch adds a secret as a separately managed object, using a special-purpose API to transfer the secret values between nodes and libvirt users. Rather than add explicit accessors for attributes of secrets, and hard-code the secrets are related to storage volumes association in the API, the API uses XML to manipulate the association as well as other attributes, similarly to other areas of libvirt. The user can set attributes of the secret using XML, e.g. secret ephemeral='no' private='yes' uuidb8eecf55-798e-4db7-b2dd-025b0cf08a36/uuid volume/var/lib/libvirt/images/mail.img/volume descriptionLUKS passphrase for our mail server/description /secret If uuid/ is not specified, it is chosen automatically. The secret value can be either generated and stored by libvirt during volume creation, or supplied by the user using virSecretSetValue(). A simple API is provided for enumeration of all secrets. Very large deployments will manage secret IDs automatically, so it is probably not necessary to provide a specialized lookup function (allowing the volume key - secret ID lookup in less than O(number of secrets)). These functions can eventually be added later. Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- docs/format.html |4 + docs/formatcaps.html |4 + docs/formatdomain.html |4 + docs/formatnetwork.html |4 + docs/formatnode.html |4 + docs/formatsecret.html | 170 ++ docs/formatsecret.html.in| 52 + docs/formatstorage.html |4 + docs/schemas/Makefile.am |1 + docs/schemas/secret.rng | 44 +++ docs/sitemap.html|3 + docs/sitemap.html.in |4 + include/libvirt/libvirt.h| 38 + include/libvirt/libvirt.h.in | 38 + src/libvirt_public.syms | 16 15 files changed, 390 insertions(+), 0 deletions(-) create mode 100644 docs/formatsecret.html create mode 100644 docs/formatsecret.html.in create mode 100644 docs/schemas/secret.rng diff --git a/docs/format.html b/docs/format.html index e97d0e7..3c20b5f 100644 --- a/docs/format.html +++ b/docs/format.html @@ -70,6 +70,10 @@ div a title=The host device XML format class=inactive href=formatnode.htmlNode Devices/a /div + /lili +div + a title=The secret XML format class=inactive href=formatsecret.htmlSecrets/a +/div /li/ul /div /lili diff --git a/docs/formatcaps.html b/docs/formatcaps.html index 5b20aac..5f2bc72 100644 --- a/docs/formatcaps.html +++ b/docs/formatcaps.html @@ -70,6 +70,10 @@ div a title=The host device XML format class=inactive href=formatnode.htmlNode Devices/a /div + /lili +div + a title=The secret XML format class=inactive href=formatsecret.htmlSecrets/a +/div /li/ul /div /lili diff --git a/docs/formatdomain.html b/docs/formatdomain.html index 5415200..6b655ad 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -70,6 +70,10 @@ div a title=The host device XML format class=inactive href=formatnode.htmlNode Devices/a /div + /lili +div + a title=The secret XML format class=inactive href=formatsecret.htmlSecrets/a +/div /li/ul /div /lili diff --git a/docs/formatnetwork.html b/docs/formatnetwork.html index 0b25a0b..72a3cda 100644 --- a/docs/formatnetwork.html +++ b/docs/formatnetwork.html @@ -70,6 +70,10 @@ div a title=The host device XML format class=inactive href=formatnode.htmlNode Devices/a /div + /lili +div + a title=The secret XML format class=inactive href=formatsecret.htmlSecrets/a +/div /li/ul /div /lili diff --git a/docs/formatnode.html b/docs/formatnode.html index 4d30b0c..516c27b 100644 --- a/docs/formatnode.html +++ b/docs/formatnode.html @@ -70,6 +70,10 @@ div span class=activeNode Devices/span /div + /lili +div +
[libvirt] [PATCH 02/20] Secret manipulation step 2: Internal API
Adds a new driver type. Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Fix a copypasted comment --- include/libvirt/virterror.h |1 + src/datatypes.c | 155 +++ src/datatypes.h | 28 src/driver.h| 61 + src/libvirt.c | 53 +++ src/libvirt_private.syms|2 + src/virterror.c |6 ++ 7 files changed, 306 insertions(+), 0 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index e4d013f..5cbb120 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -166,6 +166,7 @@ typedef enum { VIR_ERR_NO_INTERFACE, /* interface driver not running */ VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ +VIR_WAR_NO_SECRET, /* failed to start secret storage */ } virErrorNumber; /** diff --git a/src/datatypes.c b/src/datatypes.c index d03a679..2e85196 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -109,6 +109,23 @@ virStorageVolFreeName(virStorageVolPtr vol, const char *name ATTRIBUTE_UNUSED) } /** + * virSecretFreeName: + * @secret_: a secret object + * + * Destroy the secret object, this is just used by the secret hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static void +virSecretFreeName(void *secret_, const char *name ATTRIBUTE_UNUSED) +{ +virSecretPtr secret; + +secret = secret_; +virUnrefSecret(secret); +} + +/** * virGetConnect: * * Allocates a new hypervisor connection structure @@ -152,6 +169,9 @@ virGetConnect(void) { ret-nodeDevices = virHashCreate(256); if (ret-nodeDevices == NULL) goto failed; +ret-secrets = virHashCreate(20); +if (ret-secrets == NULL) +goto failed; ret-refs = 1; return(ret); @@ -170,6 +190,8 @@ failed: virHashFree(ret-storageVols, (virHashDeallocator) virStorageVolFreeName); if (ret-nodeDevices != NULL) virHashFree(ret-nodeDevices, (virHashDeallocator) virNodeDeviceFree); +if (ret-secrets != NULL) +virHashFree(ret-secrets, virSecretFreeName); virMutexDestroy(ret-lock); VIR_FREE(ret); @@ -201,6 +223,8 @@ virReleaseConnect(virConnectPtr conn) { virHashFree(conn-storageVols, (virHashDeallocator) virStorageVolFreeName); if (conn-nodeDevices != NULL) virHashFree(conn-nodeDevices, (virHashDeallocator) virNodeDeviceFree); +if (conn-secrets != NULL) +virHashFree(conn-secrets, virSecretFreeName); virResetError(conn-err); @@ -246,6 +270,8 @@ virUnrefConnect(virConnectPtr conn) { conn-storageDriver-close (conn); if (conn-deviceMonitor) conn-deviceMonitor-close (conn); +if (conn-secretDriver) +conn-secretDriver-close (conn); if (conn-driver) conn-driver-close (conn); @@ -1129,3 +1155,132 @@ virUnrefNodeDevice(virNodeDevicePtr dev) { virMutexUnlock(dev-conn-lock); return (refs); } + +/** + * virGetSecret: + * @conn: the hypervisor connection + * @uuid: secret UUID + * + * Lookup if the secret is already registered for that connection, if so return + * a pointer to it, otherwise allocate a new structure, and register it in the + * table. In any case a corresponding call to virFreeSecret() is needed to not + * leak data. + * + * Returns a pointer to the secret, or NULL in case of failure + */ +virSecretPtr +virGetSecret(virConnectPtr conn, const char *uuid) +{ +virSecretPtr ret = NULL; + +if (!VIR_IS_CONNECT(conn) || uuid == NULL) { +virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); +return NULL; +} +virMutexLock(conn-lock); + +ret = virHashLookup(conn-secrets, uuid); +if (ret == NULL) { +if (VIR_ALLOC(ret) 0) { +virMutexUnlock(conn-lock); +virReportOOMError(conn); +goto error; +} +ret-magic = VIR_SECRET_MAGIC; +ret-conn = conn; +ret-uuid = strdup(uuid); +if (ret-uuid == NULL) { +virMutexUnlock(conn-lock); +virReportOOMError(conn); +goto error; +} + +if (virHashAddEntry(conn-secrets, uuid, ret) 0) { +virMutexUnlock(conn-lock); +virLibConnError(conn, VIR_ERR_INTERNAL_ERROR, +%s, _(failed to add secret to conn hash table)); +goto error; +} +conn-refs++; +} +ret-refs++; +virMutexUnlock(conn-lock); +return ret; + +error: +if (ret != NULL) { +VIR_FREE(ret-uuid); +VIR_FREE(ret); +} +return NULL; +} + +/** + * virReleaseSecret: + * @secret:
[libvirt] [PATCH 03/20] Secret manipulation step 3: Public API implementation
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- include/libvirt/virterror.h |2 + src/libvirt.c | 504 +++ src/virterror.c |9 + 3 files changed, 515 insertions(+), 0 deletions(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 5cbb120..62cad88 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -67,6 +67,7 @@ typedef enum { VIR_FROM_ONE, /* Error from OpenNebula driver */ VIR_FROM_ESX, /* Error from ESX driver */ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ +VIR_FROM_SECRET,/* Error from secret storage */ } virErrorDomain; @@ -167,6 +168,7 @@ typedef enum { VIR_ERR_INVALID_INTERFACE, /* invalid interface object */ VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ VIR_WAR_NO_SECRET, /* failed to start secret storage */ +VIR_ERR_INVALID_SECRET, /* invalid secret */ } virErrorNumber; /** diff --git a/src/libvirt.c b/src/libvirt.c index bea60f4..c544297 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -562,6 +562,31 @@ virLibNodeDeviceError(virNodeDevicePtr dev, virErrorNumber error, } /** + * virLibSecretError: + * @secret: the secret if available + * @error: the error number + * @info: extra information string + * + * Handle an error at the secret level + */ +static void +virLibSecretError(virSecretPtr secret, virErrorNumber error, const char *info) +{ +virConnectPtr conn = NULL; +const char *errmsg; + +if (error == VIR_ERR_OK) +return; + +errmsg = virErrorMsg(error, info); +if (error != VIR_ERR_INVALID_SECRET) +conn = secret-conn; + +virRaiseError(conn, NULL, NULL, VIR_FROM_SECRET, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** * virRegisterNetworkDriver: * @driver: pointer to a network driver block * @@ -8679,3 +8704,482 @@ error: virSetConnError(conn); return -1; } + +/** + * virSecretGetConnect: + * @secret: A virSecret secret + * + * Provides the connection pointer associated with a secret. The reference + * counter on the connection is not increased by this call. + * + * WARNING: When writing libvirt bindings in other languages, do not use this + * function. Instead, store the connection and the secret object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virSecretGetConnect (virSecretPtr secret) +{ +DEBUG(secret=%p, secret); + +virResetLastError(); + +if (!VIR_IS_CONNECTED_SECRET (secret)) { +virLibSecretError (NULL, VIR_ERR_INVALID_SECRET, __FUNCTION__); +return NULL; +} +return secret-conn; +} + +/** + * virConnectNumOfSecrets: + * @conn: virConnect connection + * + * Fetch number of currently defined secrets. + * + * Returns the number currently defined secrets. + */ +int +virConnectNumOfSecrets(virConnectPtr conn) +{ +VIR_DEBUG(conn=%p, conn); + +virResetLastError(); + +if (!VIR_IS_CONNECT(conn)) { +virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); +return -1; +} + +if (conn-secretDriver != NULL +conn-secretDriver-numOfSecrets != NULL) { +int ret; + +ret = conn-secretDriver-numOfSecrets(conn); +if (ret 0) +goto error; +return ret; +} + +virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: +/* Copy to connection error object for back compatability */ +virSetConnError(conn); +return -1; +} + +/** + * virConnectListSecrets: + * @conn: virConnect connection + * @uuids: Pointer to an array to store the UUIDs + * @maxuuids: size of the array. + * + * List UUIDs of defined secrets, store pointers to names in uuids. + * + * Returns the number of UUIDs provided in the array, or -1 on failure. + */ +int +virConnectListSecrets(virConnectPtr conn, char **uuids, int maxuuids) +{ +VIR_DEBUG(conn=%p, uuids=%p, maxuuids=%d, conn, uuids, maxuuids); + +virResetLastError(); + +if (!VIR_IS_CONNECT(conn)) { +virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); +return -1; +} +if (uuids == NULL || maxuuids 0) { +virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); +goto error; +} + +if (conn-secretDriver != NULL conn-secretDriver-listSecrets != NULL) { +int ret; + +ret = conn-secretDriver-listSecrets(conn, uuids, maxuuids); +if (ret 0) +goto error; +return ret; +} + +virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: +/* Copy to connection error object for back compatability */ +virSetConnError(conn); +return -1; +} + +/** + * virSecretLookupByUUIDString: + * @conn: virConnect
[libvirt] [PATCH 04/20] Secret manipulation step 4: Wire protocol
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- qemud/remote_dispatch_args.h |7 ++ qemud/remote_dispatch_prototypes.h | 56 ++ qemud/remote_dispatch_ret.h|6 ++ qemud/remote_dispatch_table.h | 40 ++ qemud/remote_protocol.c| 140 qemud/remote_protocol.h| 122 +++ qemud/remote_protocol.x| 83 +- 7 files changed, 453 insertions(+), 1 deletions(-) diff --git a/qemud/remote_dispatch_args.h b/qemud/remote_dispatch_args.h index 9dacfb8..dcf7ddf 100644 --- a/qemud/remote_dispatch_args.h +++ b/qemud/remote_dispatch_args.h @@ -117,3 +117,10 @@ remote_domain_xml_from_native_args val_remote_domain_xml_from_native_args; remote_domain_xml_to_native_args val_remote_domain_xml_to_native_args; remote_list_defined_interfaces_args val_remote_list_defined_interfaces_args; +remote_list_secrets_args val_remote_list_secrets_args; +remote_secret_lookup_by_uuid_string_args val_remote_secret_lookup_by_uuid_string_args; +remote_secret_define_xml_args val_remote_secret_define_xml_args; +remote_secret_get_xml_desc_args val_remote_secret_get_xml_desc_args; +remote_secret_set_value_args val_remote_secret_set_value_args; +remote_secret_get_value_args val_remote_secret_get_value_args; +remote_secret_undefine_args val_remote_secret_undefine_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index d9f6aad..647f5bb 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -513,6 +513,13 @@ static int remoteDispatchListNetworks( remote_error *err, remote_list_networks_args *args, remote_list_networks_ret *ret); +static int remoteDispatchListSecrets( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_list_secrets_args *args, +remote_list_secrets_ret *ret); static int remoteDispatchListStoragePools( struct qemud_server *server, struct qemud_client *client, @@ -758,6 +765,13 @@ static int remoteDispatchNumOfNetworks( remote_error *err, void *args, remote_num_of_networks_ret *ret); +static int remoteDispatchNumOfSecrets( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +void *args, +remote_num_of_secrets_ret *ret); static int remoteDispatchNumOfStoragePools( struct qemud_server *server, struct qemud_client *client, @@ -772,6 +786,48 @@ static int remoteDispatchOpen( remote_error *err, remote_open_args *args, void *ret); +static int remoteDispatchSecretDefineXml( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_define_xml_args *args, +remote_secret_define_xml_ret *ret); +static int remoteDispatchSecretGetValue( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_get_value_args *args, +remote_secret_get_value_ret *ret); +static int remoteDispatchSecretGetXmlDesc( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_get_xml_desc_args *args, +remote_secret_get_xml_desc_ret *ret); +static int remoteDispatchSecretLookupByUuidString( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_lookup_by_uuid_string_args *args, +remote_secret_lookup_by_uuid_string_ret *ret); +static int remoteDispatchSecretSetValue( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_set_value_args *args, +void *ret); +static int remoteDispatchSecretUndefine( +struct qemud_server *server, +struct qemud_client *client, +virConnectPtr conn, +remote_error *err, +remote_secret_undefine_args *args, +void *ret); static int remoteDispatchStoragePoolBuild( struct qemud_server *server, struct qemud_client *client, diff --git a/qemud/remote_dispatch_ret.h b/qemud/remote_dispatch_ret.h index 5376960..9d74a27 100644 --- a/qemud/remote_dispatch_ret.h +++ b/qemud/remote_dispatch_ret.h @@ -99,3 +99,9 @@ remote_domain_xml_to_native_ret val_remote_domain_xml_to_native_ret; remote_num_of_defined_interfaces_ret val_remote_num_of_defined_interfaces_ret; remote_list_defined_interfaces_ret val_remote_list_defined_interfaces_ret; +remote_num_of_secrets_ret val_remote_num_of_secrets_ret; +remote_list_secrets_ret val_remote_list_secrets_ret; +
[libvirt] [PATCH 06/20] Secret manipulation step 6: RPC dispatcher
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- qemud/remote.c | 203 1 files changed, 203 insertions(+), 0 deletions(-) diff --git a/qemud/remote.c b/qemud/remote.c index d32d513..2258dec 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -64,12 +64,14 @@ static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_net static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface iface); static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol); +static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret); static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src); static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src); static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); static void make_nonnull_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src); +static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src); #include remote_dispatch_prototypes.h @@ -4515,6 +4517,195 @@ error: VIR_FREE(msg); } +static int +remoteDispatchNumOfSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, +struct qemud_client *client ATTRIBUTE_UNUSED, +virConnectPtr conn, remote_error *err, +void *args ATTRIBUTE_UNUSED, +remote_num_of_secrets_ret *ret) +{ +ret-num = virConnectNumOfSecrets (conn); +if (ret-num == -1) { +remoteDispatchConnError (err, conn); +return -1; +} + +return 0; +} + +static int +remoteDispatchListSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_list_secrets_args *args, + remote_list_secrets_ret *ret) +{ +if (args-maxuuids REMOTE_SECRET_UUID_LIST_MAX) { +remoteDispatchFormatError (err, %s, + _(maxuuids REMOTE_SECRET_UUID_LIST_MAX)); +return -1; +} + +if (VIR_ALLOC_N (ret-uuids.uuids_val, args-maxuuids) 0) { +remoteDispatchOOMError (err); +return -1; +} + +ret-uuids.uuids_len = virConnectListSecrets (conn, ret-uuids.uuids_val, + args-maxuuids); +if (ret-uuids.uuids_len == -1) { +VIR_FREE (ret-uuids.uuids_val); +remoteDispatchConnError (err, conn); +return -1; +} + +return 0; +} + +static int +remoteDispatchSecretDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_define_xml_args *args, + remote_secret_define_xml_ret *ret) +{ +virSecretPtr secret; + +secret = virSecretDefineXML (conn, args-xml, args-flags); +if (secret == NULL) { +remoteDispatchConnError (err, conn); +return -1; +} + +make_nonnull_secret (ret-secret, secret); +virSecretFree (secret); +return 0; +} + +static int +remoteDispatchSecretGetValue (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, remote_error *err, + remote_secret_get_value_args *args, + remote_secret_get_value_ret *ret) +{ +virSecretPtr secret; +size_t value_size; +unsigned char *value; + +secret = get_nonnull_secret (conn, args-secret); +if (secret == NULL) { +remoteDispatchConnError (err, conn); +return -1; +} + +value = virSecretGetValue (secret, value_size, args-flags); +if (value == NULL) { +remoteDispatchConnError (err, conn); +virSecretFree(secret); +return -1; +} + +ret-value.value_len = value_size; +ret-value.value_val = (char *)value; +virSecretFree(secret); +return 0; +} + +static int +remoteDispatchSecretGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, +
[libvirt] [PATCH 05/20] Secret manipulation step 5: RPC client
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/datatypes.h |1 + src/remote_internal.c | 328 + 2 files changed, 329 insertions(+), 0 deletions(-) diff --git a/src/datatypes.h b/src/datatypes.h index 56c3777..aa60b63 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -140,6 +140,7 @@ struct _virConnect { void *interfacePrivateData; void *storagePrivateData; void *devMonPrivateData; +void *secretPrivateData; /* * The lock mutex must be acquired before accessing/changing diff --git a/src/remote_internal.c b/src/remote_internal.c index de3c288..682a904 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -221,11 +221,13 @@ static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool); static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol); static virNodeDevicePtr get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev); +static virSecretPtr get_nonnull_secret (virConnectPtr conn, remote_nonnull_secret secret); static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src); static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src); static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src); static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src); static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); +static void make_nonnull_secret (remote_nonnull_secret *secret_dst, virSecretPtr secret_src); void remoteDomainEventFired(int watch, int fd, int event, void *data); static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr); void remoteDomainEventQueueFlush(int timer, void *opaque); @@ -6319,6 +6321,305 @@ done: return rv; } +static virDrvOpenStatus +remoteSecretOpen (virConnectPtr conn, + virConnectAuthPtr auth, + int flags) +{ +if (inside_daemon) +return VIR_DRV_OPEN_DECLINED; + +if (conn +conn-driver +STREQ (conn-driver-name, remote)) { +struct private_data *priv; + +/* If we're here, the remote driver is already + * in use due to a) a QEMU uri, or b) a remote + * URI. So we can re-use existing connection + */ +priv = conn-privateData; +remoteDriverLock(priv); +priv-localUses++; +conn-secretPrivateData = priv; +remoteDriverUnlock(priv); +return VIR_DRV_OPEN_SUCCESS; +} else if (conn-networkDriver + STREQ (conn-networkDriver-name, remote)) { +struct private_data *priv = conn-networkPrivateData; +remoteDriverLock(priv); +conn-secretPrivateData = priv; +priv-localUses++; +remoteDriverUnlock(priv); +return VIR_DRV_OPEN_SUCCESS; +} else { +/* Using a non-remote driver, so we need to open a + * new connection for secret APIs, forcing it to + * use the UNIX transport. + */ +struct private_data *priv; +int ret; +ret = remoteOpenSecondaryDriver(conn, +auth, +flags, +priv); +if (ret == VIR_DRV_OPEN_SUCCESS) +conn-secretPrivateData = priv; +return ret; +} +} + +static int +remoteSecretClose (virConnectPtr conn) +{ +int rv = 0; +struct private_data *priv = conn-secretPrivateData; + +conn-secretPrivateData = NULL; +remoteDriverLock(priv); +priv-localUses--; +if (!priv-localUses) { +rv = doRemoteClose(conn, priv); +remoteDriverUnlock(priv); +virMutexDestroy(priv-lock); +VIR_FREE(priv); +} +if (priv) +remoteDriverUnlock(priv); +return rv; +} + +static int +remoteSecretNumOfSecrets (virConnectPtr conn) +{ +int rv = -1; +remote_num_of_secrets_ret ret; +struct private_data *priv = conn-secretPrivateData; + +remoteDriverLock (priv); + +memset (ret, 0, sizeof (ret)); +if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_SECRETS, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_num_of_secrets_ret, (char *) ret) == -1) +goto done; + +rv = ret.num; + +done: +remoteDriverUnlock (priv); +return rv; +} + +static int +remoteSecretListSecrets (virConnectPtr conn, char **uuids, int maxuuids) +{ +int rv = -1; +int i; +remote_list_secrets_args
[libvirt] [PATCH 07/20] Secret manipulation step 7: Local driver
This implementation stores the secrets in an unencrypted text file, for simplicity in implementation and debugging. (Symmetric encryption, e.g. using gpgme, will not be difficult to add. Because the TLS private key used by libvirtd is stored unencrypted, encrypting the secrets file does not currently provide much additional security.) Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Add the base64 gnulib module here, not in a later patch - Don't use fprintf(stderr) for logging - Move an assignment out of loop termination test - fchmod() a newly created temporary file before writing secrets to it - Reject invalid XML attribute values - Use more verbose errors in parseKeyValue() - Use open()+fstat() instead of stat()+open() - Fix structure declaration formatting - Fix error message formatting - Remove a comment suggesting use of abort() --- bootstrap |1 + include/libvirt/virterror.h |1 + po/POTFILES.in |1 + qemud/qemud.c |3 + src/Makefile.am | 14 + src/libvirt_private.syms|2 + src/secret_driver.c | 1152 +++ src/secret_driver.h | 28 + src/test.c | 21 + src/virterror.c |5 + 10 files changed, 1228 insertions(+), 0 deletions(-) create mode 100644 src/secret_driver.c create mode 100644 src/secret_driver.h diff --git a/bootstrap b/bootstrap index 8b81e0e..885b299 100755 --- a/bootstrap +++ b/bootstrap @@ -65,6 +65,7 @@ gnulib_tool=$GNULIB_SRCDIR/gnulib-tool $gnulib_tool || exit modules=' +base64 c-ctype close connect diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 62cad88..fa5cac4 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -169,6 +169,7 @@ typedef enum { VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */ VIR_WAR_NO_SECRET, /* failed to start secret storage */ VIR_ERR_INVALID_SECRET, /* invalid secret */ +VIR_ERR_NO_SECRET, /* secret not found */ } virErrorNumber; /** diff --git a/po/POTFILES.in b/po/POTFILES.in index 66d3ebd..e9d388a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,6 +30,7 @@ src/proxy_internal.c src/qemu_conf.c src/qemu_driver.c src/remote_internal.c +src/secret_driver.c src/security.c src/security_selinux.c src/storage_backend.c diff --git a/qemud/qemud.c b/qemud/qemud.c index e657cf2..ec7c021 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -92,6 +92,7 @@ #ifdef WITH_NODE_DEVICES #include node_device.h #endif +#include secret_driver.h #endif @@ -814,6 +815,7 @@ static struct qemud_server *qemudInitialize(int sigread) { virDriverLoadModule(network); virDriverLoadModule(storage); virDriverLoadModule(nodedev); +virDriverLoadModule(secret); virDriverLoadModule(qemu); virDriverLoadModule(lxc); virDriverLoadModule(uml); @@ -832,6 +834,7 @@ static struct qemud_server *qemudInitialize(int sigread) { (defined(HAVE_HAL) || defined(HAVE_DEVKIT)) nodedevRegister(); #endif +secretRegister(); #ifdef WITH_QEMU qemuRegister(); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 9567490..ce33695 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -176,6 +176,9 @@ NETWORK_DRIVER_SOURCES = \ INTERFACE_DRIVER_SOURCES = \ interface_driver.h interface_driver.c +SECRET_DRIVER_SOURCES =\ + secret_driver.h secret_driver.c + # Storage backend specific impls STORAGE_DRIVER_SOURCES = \ storage_driver.h storage_driver.c \ @@ -448,6 +451,17 @@ endif libvirt_driver_interface_la_SOURCES = $(INTERFACE_DRIVER_SOURCES) endif +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_secret.la +else +noinst_LTLIBRARIES += libvirt_driver_secret.la +libvirt_la_LIBADD += libvirt_driver_secret.la +endif +if WITH_DRIVER_MODULES +libvirt_driver_secret_la_LDFLAGS = -module -avoid-version +endif +libvirt_driver_secret_la_SOURCES = $(SECRET_DRIVER_SOURCES) + # Needed to keep automake quiet about conditionals libvirt_driver_storage_la_SOURCES = if WITH_STORAGE_DIR diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f2c0736..8b22030 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -299,6 +299,8 @@ qparam_get_query; qparam_query_parse; free_qparam_set; +# secret.h +secretRegister; # security.h virSecurityDriverVerify; diff --git a/src/secret_driver.c b/src/secret_driver.c new file mode 100644 index 000..f8180ad --- /dev/null +++ b/src/secret_driver.c @@ -0,0 +1,1152 @@ +/* + * secret_driver.c: local driver for secret manipulation API + * + *
[libvirt] [PATCH 08/20] Secret manipulation step 8: Add virsh commands
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - Add documentation to virsh.1 --- docs/virsh.pod | 43 src/virsh.c| 323 virsh.1| 34 ++- 3 files changed, 399 insertions(+), 1 deletions(-) diff --git a/docs/virsh.pod b/docs/virsh.pod index 10bb991..55ec64a 100644 --- a/docs/virsh.pod +++ b/docs/virsh.pod @@ -543,6 +543,49 @@ Convert a network name to network UUID. =back +=head1 SECRET COMMMANDS + +The following commands manipulate secrets (e.g. passwords, passphrases and +encryption keys). Libvirt can store secrets independently from their use, and +other objects (e.g. volumes or domains) can refer to the secrets for encryption +or possibly other uses. Secrets are identified using an UUID. See +Lhttp://libvirt.org/formatsecret.html for documentation of the XML format +used to represent properties of secrets. + +=over 4 + +=item Bsecret-define Ifile + +Create a secret with the properties specified in Ifile, with no associated +secret value. If Ifile does not specify a UUID, choose one automatically. +If Ifile specifies an UUID of an existing secret, replace its properties by +properties defined in Ifile, without affecting the secret value. + +=item Bsecret-dumpxml Isecret + +Output properties of Isecret (specified by its UUID) as an XML dump to stdout. + +=item Bsecret-set-value Isecret Ibase64 + +Set the value associated with Isecret (specified by its UUID) to the value +Base64-encoded value Ibase64. + +=item Bsecret-get-value Isecret + +Output the value associated with Isecret (specified by its UUID) to stdout, +encoded using Base64. + +=item Bsecret-undefine Isecret + +Delete a Isecret (specified by its UUID), including the associated value, if +any. + +=item Bsecret-list + +Output a list of UUIDs of known secrets to stdout. + +=back + =head1 ENVIRONMENT The following environment variables can be set to alter the behaviour diff --git a/src/virsh.c b/src/virsh.c index 2d0cf81..1b073ef 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -41,6 +41,7 @@ #endif #include internal.h +#include base64.h #include buf.h #include console.h #include util.h @@ -271,6 +272,9 @@ static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ VSH_BYUUID|VSH_BYNAME) +static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, +char **name); + static void vshPrintExtra(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); static void vshDebug(vshControl *ctl, int level, const char *format, ...) @@ -5249,9 +5253,291 @@ cmdVolPath(vshControl *ctl, const vshCmd *cmd) } +/* + * secret-define command + */ +static const vshCmdInfo info_secret_define[] = { +{help, gettext_noop(define or modify a secret from an XML file)}, +{desc, gettext_noop(Define or modify a secret.)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_define[] = { +{file, VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop(file containing secret attributes in XML)}, +{NULL, 0, 0, NULL} +}; + +static int +cmdSecretDefine(vshControl *ctl, const vshCmd *cmd) +{ +char *from, *buffer, *uuid; +virSecretPtr res; + +if (!vshConnectionUsability(ctl, ctl-conn, TRUE)) +return FALSE; + +from = vshCommandOptString(cmd, file, NULL); +if (!from) +return FALSE; + +if (virFileReadAll(from, VIRSH_MAX_XML_FILE, buffer) 0) +return FALSE; + +res = virSecretDefineXML(ctl-conn, buffer, 0); +free (buffer); + +if (res == NULL) { +vshError(ctl, FALSE, _(Failed to set attributes from %s), from); +return FALSE; +} +uuid = virSecretGetUUIDString(res); +if (uuid == NULL) { +vshError(ctl, FALSE, %s, + _(Failed to get UUID of created secret)); +virSecretFree(res); +return FALSE; +} +vshPrint(ctl, _(Secret %s created\n), uuid); +free(uuid); +virSecretFree(res); +return TRUE; +} + +/* + * secret-dumpxml command + */ +static const vshCmdInfo info_secret_dumpxml[] = { +{help, gettext_noop(secret attributes in XML)}, +{desc, gettext_noop(Output attributes of a secret as an XML dump to stdout.)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_dumpxml[] = { +{secret, VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop(secret UUID)}, +{NULL, 0, 0, NULL} +}; + +static int +cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd) +{ +virSecretPtr secret; +int ret = FALSE; +char *xml; + +if (!vshConnectionUsability(ctl, ctl-conn, TRUE)) +return FALSE; + +secret = vshCommandOptSecret(ctl, cmd, NULL); +if (secret == NULL) +return FALSE; + +xml =
[libvirt] [PATCH 10/20] Secret manipulation step 10: Add Python API
Sample session: import libvirt c = libvirt.open('qemu:///session') c.listSecrets() ['12247729-47d2-a783-88ce-b329d4781cd3', 'reee', 'abc'] s = c.secretDefineXML(secret ephemeral='no' private='no'\ndescriptionSomething for use/description\nvolume/foo/bar/volume\n/secret\n) s.UUIDString() '340c2dfb-811b-eda8-da9e-25ccd7bfd650' s.XMLDesc() secret ephemeral='no' private='no'\n uuid340c2dfb-811b-eda8-da9e-25ccd7bfd650/uuid\n descriptionSomething for use/description\n volume/foo/bar/volume\n/secret\n s.setValue('abc\0xx\xffx') 0 s.value() 'abc\x00xx\xffx' s.undefine() 0 Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. - remove get prefix from method names of virSecret, to be more consistent with other classes. --- python/generator.py | 31 +++-- python/libvir.c | 100 + python/libvirt-python-api.xml | 18 +++ python/libvirt_wrap.h |9 python/types.c| 13 + 5 files changed, 167 insertions(+), 4 deletions(-) diff --git a/python/generator.py b/python/generator.py index feff7a3..4dbad1c 100755 --- a/python/generator.py +++ b/python/generator.py @@ -270,6 +270,11 @@ py_types = { 'const virNodeDevicePtr': ('O', virNodeDevice, virNodeDevicePtr, virNodeDevicePtr), 'virNodeDevice *': ('O', virNodeDevice, virNodeDevicePtr, virNodeDevicePtr), 'const virNodeDevice *': ('O', virNodeDevice, virNodeDevicePtr, virNodeDevicePtr), + +'virSecretPtr': ('O', virSecret, virSecretPtr, virSecretPtr), +'const virSecretPtr': ('O', virSecret, virSecretPtr, virSecretPtr), +'virSecret *': ('O', virSecret, virSecretPtr, virSecretPtr), +'const virSecret *': ('O', virSecret, virSecretPtr, virSecretPtr), } py_return_types = { @@ -296,6 +301,7 @@ skip_impl = ( 'virConnectListDefinedNetworks', 'virConnectListInterfaces', 'virConnectListDefinedInterfaces', +'virConnectListSecrets', 'virConnectListStoragePools', 'virConnectListDefinedStoragePools', 'virConnectListStorageVols', @@ -320,6 +326,8 @@ skip_impl = ( 'virDomainSetSchedulerParameters', 'virDomainGetVcpus', 'virDomainPinVcpu', +'virSecretGetValue', +'virSecretSetValue', 'virStoragePoolGetUUID', 'virStoragePoolGetUUIDString', 'virStoragePoolLookupByUUID', @@ -623,6 +631,8 @@ classes_type = { virStorageVol *: (._o, virStorageVol(self, _obj=%s), virStorageVol), virNodeDevicePtr: (._o, virNodeDevice(self, _obj=%s), virNodeDevice), virNodeDevice *: (._o, virNodeDevice(self, _obj=%s), virNodeDevice), +virSecretPtr: (._o, virSecret(self, _obj=%s), virSecret), +virSecret *: (._o, virSecret(self, _obj=%s), virSecret), virConnectPtr: (._o, virConnect(_obj=%s), virConnect), virConnect *: (._o, virConnect(_obj=%s), virConnect), } @@ -632,7 +642,7 @@ converter_type = { primary_classes = [virDomain, virNetwork, virInterface, virStoragePool, virStorageVol, - virConnect, virNodeDevice ] + virConnect, virNodeDevice, virSecret ] classes_ancestor = { } @@ -642,7 +652,8 @@ classes_destructors = { virInterface: virInterfaceFree, virStoragePool: virStoragePoolFree, virStorageVol: virStorageVolFree, -virNodeDevice : virNodeDeviceFree +virNodeDevice : virNodeDeviceFree, +virSecret: virSecretFree } functions_noexcept = { @@ -714,6 +725,12 @@ def nameFixup(name, classe, type, file): elif name[0:18] == virInterfaceLookup: func = name[3:] func = string.lower(func[0:1]) + func[1:] +elif name[0:15] == virSecretDefine: +func = name[3:] +func = string.lower(func[0:1]) + func[1:] +elif name[0:15] == virSecretLookup: +func = name[3:] +func = string.lower(func[0:1]) + func[1:] elif name[0:20] == virStoragePoolDefine: func = name[3:] func = string.lower(func[0:1]) + func[1:] @@ -747,6 +764,12 @@ def nameFixup(name, classe, type, file): elif name[0:12] == virInterface: func = name[10:] func = string.lower(func[0:1]) + func[1:] +elif name[0:12] == 'virSecretGet': +func = name[12:] +func = string.lower(func[0:1]) + func[1:] +elif name[0:9] == 'virSecret': +func = name[9:] +func = string.lower(func[0:1]) + func[1:] elif name[0:17] == virStoragePoolGet: func = name[17:] func = string.lower(func[0:1]) + func[1:] @@ -1018,7 +1041,7 @@ def buildWrappers(): else: txt.write(Class %s()\n % (classname)) classes.write(class %s:\n % (classname)) -if classname in [ virDomain, virNetwork, virInterface, virStoragePool, virStorageVol, virNodeDevice ]: +if classname in [ virDomain,
[libvirt] [PATCH 11/20] Add volume encryption information handling.
Define an encryption tag specifying volume encryption format and format-depenedent parameters (e.g. passphrase, cipher name, key length, key). Currently the only defined parameter is a reference to a secret (passphrase/key) managed using the virSecret* API. Only the qcow/qcow2 encryption format, and a default format used to let libvirt choose the format during volume creation, is currently supported. This patch does not add any users; the encryption tag is added in the following patches to both volumes (to support encrypted volume creation) and domains. Changes since the third submission: - Move base64 gnulib module inclusion to an earlier patch --- docs/format.html |4 + docs/formatcaps.html |4 + docs/formatdomain.html |4 + docs/formatnetwork.html |4 + docs/formatnode.html |4 + docs/formatsecret.html |4 + docs/formatstorage.html |4 + docs/formatstorageencryption.html| 209 + docs/formatstorageencryption.html.in | 65 + docs/schemas/Makefile.am |1 + docs/schemas/storageencryption.rng | 34 + docs/sitemap.html|3 + docs/sitemap.html.in |4 + po/POTFILES.in |1 + src/Makefile.am |1 + src/libvirt_private.syms |5 + src/storage_encryption.c | 241 ++ src/storage_encryption.h | 72 ++ 18 files changed, 664 insertions(+), 0 deletions(-) create mode 100644 docs/formatstorageencryption.html create mode 100644 docs/formatstorageencryption.html.in create mode 100644 docs/schemas/storageencryption.rng create mode 100644 src/storage_encryption.c create mode 100644 src/storage_encryption.h diff --git a/docs/format.html b/docs/format.html index 3c20b5f..e8b1498 100644 --- a/docs/format.html +++ b/docs/format.html @@ -64,6 +64,10 @@ /div /lili div + a title=Storage volume encryption XML format class=inactive href=formatstorageencryption.htmlStorage Encryption/a +/div + /lili +div a title=The driver capabilities XML format class=inactive href=formatcaps.htmlCapabilities/a /div /lili diff --git a/docs/formatcaps.html b/docs/formatcaps.html index 5f2bc72..3240101 100644 --- a/docs/formatcaps.html +++ b/docs/formatcaps.html @@ -64,6 +64,10 @@ /div /lili div + a title=Storage volume encryption XML format class=inactive href=formatstorageencryption.htmlStorage Encryption/a +/div + /lili +div span class=activeCapabilities/span /div /lili diff --git a/docs/formatdomain.html b/docs/formatdomain.html index 6b655ad..efba65a 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -64,6 +64,10 @@ /div /lili div + a title=Storage volume encryption XML format class=inactive href=formatstorageencryption.htmlStorage Encryption/a +/div + /lili +div a title=The driver capabilities XML format class=inactive href=formatcaps.htmlCapabilities/a /div /lili diff --git a/docs/formatnetwork.html b/docs/formatnetwork.html index 72a3cda..845e558 100644 --- a/docs/formatnetwork.html +++ b/docs/formatnetwork.html @@ -64,6 +64,10 @@ /div /lili div + a title=Storage volume encryption XML format class=inactive href=formatstorageencryption.htmlStorage Encryption/a +/div + /lili +div a title=The driver capabilities XML format class=inactive href=formatcaps.htmlCapabilities/a /div /lili diff --git a/docs/formatnode.html b/docs/formatnode.html index 516c27b..b269baa 100644 --- a/docs/formatnode.html +++ b/docs/formatnode.html @@ -64,6 +64,10 @@ /div /lili div + a title=Storage volume encryption XML format class=inactive href=formatstorageencryption.htmlStorage Encryption/a +/div + /lili +div a title=The
[libvirt] [PATCH 12/20] Attach encryption information to virStorageVolDef.
The XML allows encryption format='unencrypted'/, this implementation canonicalizes the internal representation so that vol-encryption is non-NULL iff the volume is encrypted. Note that partial encryption information (e.g. specifying an encryption format, but not the key/passphrase) is valid, libvirt will automatically choose value for the missing information during volume creation. The user can read the volume XML, and use the unmodified encryption tag in future operations (without having to be able to understand) its contents. --- docs/formatstorage.html |6 ++ docs/formatstorage.html.in |8 docs/schemas/storagevol.rng |5 + src/storage_conf.c | 15 +++ src/storage_conf.h |3 +++ tests/storagevolschemadata/vol-qcow2.xml |3 +++ 6 files changed, 40 insertions(+), 0 deletions(-) diff --git a/docs/formatstorage.html b/docs/formatstorage.html index 8c16a0f..cb95263 100644 --- a/docs/formatstorage.html +++ b/docs/formatstorage.html @@ -252,6 +252,9 @@ lt;modegt;0744lt;/modegt; lt;labelgt;virt_image_tlt;/labelgt; lt;/permissionsgt; + lt;encryption type='...'gt; +... + lt;/encryptiongt; lt;/targetgt; lt;/poolgt;/pre dldtcodepath/code/dtddProvides the location at which the pool will be mapped into @@ -274,6 +277,9 @@ element contains the numeric group ID. The codelabel/code element contains the MAC (eg SELinux) label string. span class=sinceSince 0.4.1/span + /dddtcodeencryption/code/dtddIf present, specifies how the volume is encrypted. See +the a href=formatstorageencryption.htmlStorage Encryption/a page +for more information. /dd/dl h3 a name=StoragePoolExtents id=StoragePoolExtentsDevice extents/a diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index 4878d72..3ed88a2 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -124,6 +124,9 @@ lt;modegt;0744lt;/modegt; lt;labelgt;virt_image_tlt;/labelgt; lt;/permissionsgt; + lt;encryption type='...'gt; +... + lt;/encryptiongt; lt;/targetgt; lt;/poolgt;/pre @@ -152,6 +155,11 @@ contains the MAC (eg SELinux) label string. span class=sinceSince 0.4.1/span /dd + dtcodeencryption/code/dt + ddIf present, specifies how the volume is encrypted. See +the a href=formatstorageencryption.htmlStorage Encryption/a page +for more information. + /dd /dl h3a name=StoragePoolExtentsDevice extents/a/h3 diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng index 5b0b038..00b70f6 100644 --- a/docs/schemas/storagevol.rng +++ b/docs/schemas/storagevol.rng @@ -5,6 +5,8 @@ ref name='vol'/ /start + include href='storageencryption.rng'/ + define name='vol' element name='volume' @@ -73,6 +75,9 @@ /optional ref name='format'/ ref name='permissions'/ + optional +ref name='encryption'/ + /optional /element /define diff --git a/src/storage_conf.c b/src/storage_conf.c index 245b2d0..c446069 100644 --- a/src/storage_conf.c +++ b/src/storage_conf.c @@ -260,8 +260,10 @@ virStorageVolDefFree(virStorageVolDefPtr def) { VIR_FREE(def-target.path); VIR_FREE(def-target.perms.label); +virStorageEncryptionFree(def-target.encryption); VIR_FREE(def-backingStore.path); VIR_FREE(def-backingStore.perms.label); +virStorageEncryptionFree(def-backingStore.encryption); VIR_FREE(def); } @@ -955,6 +957,7 @@ virStorageVolDefParseXML(virConnectPtr conn, char *allocation = NULL; char *capacity = NULL; char *unit = NULL; +xmlNodePtr node; options = virStorageVolOptionsForPoolType(pool-type); if (options == NULL) @@ -1019,6 +1022,14 @@ virStorageVolDefParseXML(virConnectPtr conn, ./target/permissions, 0600) 0) goto cleanup; +node = virXPathNode(conn, ./target/encryption, ctxt); +if (node != NULL) { +ret-target.encryption = virStorageEncryptionParseNode(conn, ctxt-doc, + node); +if (ret-target.encryption == NULL) +goto cleanup; +} + ret-backingStore.path = virXPathString(conn, string(./backingStore/path), ctxt); @@ -1189,6 +1200,10 @@ virStorageVolTargetDefFormat(virConnectPtr conn, virBufferAddLit(buf,/permissions\n); +if (def-encryption != NULL +virStorageEncryptionFormat(conn, buf, def-encryption) 0) +return -1; + virBufferVSprintf(buf, /%s\n, type); return 0; diff --git a/src/storage_conf.h b/src/storage_conf.h index a6c3650..2fa14e9 100644 --- a/src/storage_conf.h +++
[libvirt] [PATCH 14/20] Add support for encrypted (qcow) volume creation.
Supports only virStorageVolCreateXML, not virStorageVolCreateXMLFrom. Curiously, qemu-img does not need the passphrase for anything to create an encrypted volume. This implementation thus does not need to touch any secrets to work with cooperating clients. More generic passphrase handling is added in the next patch. --- src/storage_backend.c | 47 +++- src/storage_backend_disk.c|7 ++ src/storage_backend_fs.c |7 ++ src/storage_backend_logical.c |7 ++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/storage_backend.c b/src/storage_backend.c index 8824218..c818142 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -246,6 +246,13 @@ virStorageBackendCreateRaw(virConnectPtr conn, unsigned long long remain; char *buf = NULL; +if (vol-target.encryption != NULL) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + %s, _(storage pool does not support encrypted + volumes)); +return -1; +} + if ((fd = open(vol-target.path, O_RDWR | O_CREAT | O_EXCL, vol-target.perms.mode)) 0) { virReportSystemError(conn, errno, @@ -346,15 +353,17 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, NULL; const char **imgargv; +/* The extra NULL field is for indicating encryption (-e). */ const char *imgargvnormal[] = { NULL, create, -f, type, vol-target.path, size, NULL, +NULL }; /* Extra NULL fields are for including backingType when using - * kvm-img. It's -F backingType + * kvm-img (-F backingType), and for indicating encryption (-e). */ const char *imgargvbacking[] = { NULL, create, @@ -364,6 +373,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, size, NULL, NULL, +NULL, NULL }; const char *convargv[] = { @@ -417,6 +427,28 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, } } +if (vol-target.encryption != NULL) { +if (vol-target.format != VIR_STORAGE_VOL_FILE_QCOW +vol-target.format != VIR_STORAGE_VOL_FILE_QCOW2) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + _(qcow volume encryption unsupported with +volume format %s), type); +return -1; +} +if (vol-target.encryption-format != +VIR_STORAGE_ENCRYPTION_FORMAT_QCOW) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + _(unsupported volume encryption format %d), + vol-target.encryption-format); +return -1; +} +if (vol-target.encryption-nsecrets 1) { +virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, + _(too many secrets for qcow encryption)); +return -1; +} +} + if ((create_tool = virFindFileInPath(kvm-img)) != NULL) use_kvmimg = 1; else if ((create_tool = virFindFileInPath(qemu-img)) != NULL) @@ -437,11 +469,16 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, imgargvbacking[7] = backingType; imgargvbacking[8] = vol-target.path; imgargvbacking[9] = size; -} +if (vol-target.encryption != NULL) +imgargvbacking[10] = -e; +} else if (vol-target.encryption != NULL) +imgargvbacking[8] = -e; imgargv = imgargvbacking; } else { imgargvnormal[0] = create_tool; imgargv = imgargvnormal; +if (vol-target.encryption != NULL) +imgargv[6] = -e; } @@ -489,6 +526,12 @@ virStorageBackendCreateQcowCreate(virConnectPtr conn, qcow-create)); return -1; } +if (vol-target.encryption != NULL) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + %s, _(encrypted volumes not supported with + qcow-create)); +return -1; +} /* Size in MB - yes different units to qemu-img :-( */ snprintf(size, sizeof(size), %llu, vol-capacity/1024/1024); diff --git a/src/storage_backend_disk.c b/src/storage_backend_disk.c index ae2acae..6fdb566 100644 --- a/src/storage_backend_disk.c +++ b/src/storage_backend_disk.c @@ -557,6 +557,13 @@ virStorageBackendDiskCreateVol(virConnectPtr conn, NULL }; +if (vol-target.encryption != NULL) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, + %s, _(storage pool does not support encrypted + volumes)); +return -1; +} + if
[libvirt] [PATCH 15/20] Provide missing passphrase when creating a volume.
If the encryption format='qcow' element does not specify a secret during volume creation, generate a suitable secret and add it to the encryption tag. The caller can view the updated encryption tag using virStorageVolGetXMLDesc(). Similarly, when encryption format='default'/ is specified while creating a qcow or qcow2-formatted volume, change the format to qcow and generate a secret as described above. Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/storage_backend.c | 127 +++- 1 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/storage_backend.c b/src/storage_backend.c index c818142..5fa0035 100644 --- a/src/storage_backend.c +++ b/src/storage_backend.c @@ -43,6 +43,7 @@ #include selinux/selinux.h #endif +#include datatypes.h #include virterror_internal.h #include util.h #include memory.h @@ -331,6 +332,118 @@ cleanup: } static int +virStorageGenerateQcowEncryption(virConnectPtr conn, + virStorageVolDefPtr vol) +{ +virBuffer buf = VIR_BUFFER_INITIALIZER; +virStorageEncryptionPtr enc; +virStorageEncryptionSecretPtr enc_secret = NULL; +virSecretPtr secret = NULL; +char *uuid = NULL, *xml; +unsigned char value[16]; +int ret = -1, fd = -1; +size_t i; + +if (conn-secretDriver == NULL || conn-secretDriver-defineXML == NULL || +conn-secretDriver-setValue == NULL) { +virStorageReportError(conn, VIR_ERR_NO_SUPPORT, %s, + _(secret storage not supported)); +goto cleanup; +} + +enc = vol-target.encryption; +if (enc-nsecrets != 0) { +virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, %s, + _(secrets already defined)); +goto cleanup; +} + +if (VIR_ALLOC(enc_secret) 0 || VIR_REALLOC_N(enc-secrets, 1) 0) { +virReportOOMError(conn); +goto cleanup; +} + +virBufferAddLit(buf, secret ephemeral='no' private='no'); +/* uuid/ is chosen by the secret driver */ +virBufferEscapeString(buf, + descriptionqcow passphrase for %s/description, + vol-target.path); +virBufferEscapeString(buf, volume%s/volume, vol-target.path); +virBufferAddLit(buf, /secret); +if (virBufferError(buf)) { +virReportOOMError(conn); +goto cleanup; +} +xml = virBufferContentAndReset(buf); +secret = conn-secretDriver-defineXML(conn, xml, 0); +if (secret == NULL) { +VIR_FREE(xml); +goto cleanup; +} +VIR_FREE(xml); + +uuid = strdup(secret-uuid); +if (uuid == NULL) { +virReportOOMError(conn); +goto cleanup; +} + +/* A qcow passphrase is up to 16 bytes, with any data following a NUL + ignored. Prohibit control and non-ASCII characters to avoid possible + unpleasant surprises with the qemu monitor input mechanism. */ +fd = open(/dev/urandom, O_RDONLY); +if (fd 0) { +virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, %s, + _(Cannot open /dev/urandom)); +goto cleanup; +} +i = 0; +while (i sizeof (value)) { +ssize_t r; + +while ((r = read(fd, value + i, 1)) == -1 errno == EINTR) +; +if (r = 0) { +virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, %s, + _(Cannot read from /dev/urandom)); +goto cleanup; +} +if (value[i] = 0x20 value[i] = 0x7E) +i++; /* Got an acceptable character */ +} +close(fd); +fd = -1; + +if (conn-secretDriver-setValue(secret, value, sizeof(value), 0) 0) +goto cleanup; +secret = NULL; + +enc_secret-type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE; +enc_secret-uuid = uuid; +uuid = NULL; +enc-format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; +enc-secrets[0] = enc_secret; /* Space for secrets[0] allocated above */ +enc_secret = NULL; +enc-nsecrets = 1; + +ret = 0; + +cleanup: +if (fd != -1) +close(fd); +VIR_FREE(uuid); +if (secret != NULL) { +if (conn-secretDriver-undefine != NULL) +conn-secretDriver-undefine(secret); +virSecretFree(secret); +} +xml = virBufferContentAndReset(buf); +VIR_FREE(xml); +VIR_FREE(enc_secret); +return ret; +} + +static int virStorageBackendCreateQemuImg(virConnectPtr conn, virStorageVolDefPtr vol, virStorageVolDefPtr inputvol, @@ -428,6 +541,8 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, } if (vol-target.encryption != NULL) { +virStorageEncryptionPtr enc; + if (vol-target.format != VIR_STORAGE_VOL_FILE_QCOW
[libvirt] [PATCH 16/20] Attach encryption information to virDomainDiskDef.
The XML allows encryption format='unencrypted'/, this implementation canonicalizes the internal representation so that disk-encryption is non-NULL iff encryption information is available. A domain with partial encryption information can be defined, completeness of the information is not verified. The domain won't start until the remaining information is added, of course. --- docs/formatdomain.html|6 ++ docs/formatdomain.html.in |8 docs/schemas/domain.rng |5 + src/domain_conf.c | 14 ++ src/domain_conf.h |2 ++ 5 files changed, 35 insertions(+), 0 deletions(-) diff --git a/docs/formatdomain.html b/docs/formatdomain.html index efba65a..3368ad5 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -453,6 +453,9 @@ lt;driver name=tap type=aiogt; lt;source file='/var/lib/xen/images/fv0'/gt; lt;target dev='hda' bus='ide'/gt; +lt;encryption type='...'gt; + ... +lt;/encryptiongt; lt;/diskgt; .../pre dldtcodedisk/code/dtddThe codedisk/code element is the main container for describing @@ -478,6 +481,9 @@ codedriver/code element allows them to be selected. The codename/code attribute is the primary backend driver name, while the optional codetype/code attribute provides the sub-type. span class=sinceSince 0.1.8/span + /dddtcodeencryption/code/dtddIf present, specifies how the volume is encrypted. See +the a href=formatstorageencryption.htmlStorage Encryption/a page +for more information. /dd/dl h4 a name=elementsUSB id=elementsUSBUSB and PCI devices/a diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index eb12784..211f7ed 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -338,6 +338,9 @@ lt;driver name=tap type=aiogt; lt;source file='/var/lib/xen/images/fv0'/gt; lt;target dev='hda' bus='ide'/gt; +lt;encryption type='...'gt; + ... +lt;/encryptiongt; lt;/diskgt; .../pre @@ -373,6 +376,11 @@ attribute is the primary backend driver name, while the optional codetype/code attribute provides the sub-type. span class=sinceSince 0.1.8/span /dd + dtcodeencryption/code/dt + ddIf present, specifies how the volume is encrypted. See +the a href=formatstorageencryption.htmlStorage Encryption/a page +for more information. + /dd /dl h4a name=elementsUSBUSB and PCI devices/a/h4 diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index f857301..df31f4a 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -4,6 +4,8 @@ start ref name=domain/ /start + + include href='storageencryption.rng'/ !-- We handle only document defining a domain -- @@ -336,6 +338,9 @@ empty/ /element /optional +optional + ref name=encryption/ +/optional /define !-- A disk description can be either of type file or block diff --git a/src/domain_conf.c b/src/domain_conf.c index 1d2cc7c..46acf5e 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -288,6 +288,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) VIR_FREE(def-dst); VIR_FREE(def-driverName); VIR_FREE(def-driverType); +virStorageEncryptionFree(def-encryption); VIR_FREE(def); } @@ -661,6 +662,7 @@ virDomainDiskDefParseXML(virConnectPtr conn, char *bus = NULL; char *cachetag = NULL; char *devaddr = NULL; +virStorageEncryptionPtr encryption = NULL; if (VIR_ALLOC(def) 0) { virReportOOMError(conn); @@ -718,6 +720,12 @@ virDomainDiskDefParseXML(virConnectPtr conn, } else if ((flags VIR_DOMAIN_XML_INTERNAL_STATUS) xmlStrEqual(cur-name, BAD_CAST state)) { devaddr = virXMLPropString(cur, devaddr); +} else if (encryption == NULL + xmlStrEqual(cur-name, BAD_CAST encryption)) { +encryption = virStorageEncryptionParseNode(conn, node-doc, + cur); +if (encryption == NULL) +goto error; } } cur = cur-next; @@ -836,6 +844,8 @@ virDomainDiskDefParseXML(virConnectPtr conn, driverName = NULL; def-driverType = driverType; driverType = NULL; +def-encryption = encryption; +encryption = NULL; cleanup: VIR_FREE(bus); @@ -847,6 +857,7 @@ cleanup: VIR_FREE(driverName); VIR_FREE(cachetag); VIR_FREE(devaddr); +virStorageEncryptionFree(encryption); return def; @@ -3519,6 +3530,9 @@ virDomainDiskDefFormat(virConnectPtr conn, virBufferAddLit(buf, readonly/\n); if (def-shared)
[libvirt] [PATCH 17/20] Don't assume buffered output echoes the command.
The if ((nlptr...)) implicitly assumes commptr != NULL (and that buf starts with cmd). Make the assumption explicit, it will be broken in a future patch. --- src/qemu_driver.c |7 --- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index eb22940..e92276e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2473,10 +2473,11 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, * occurence, and inbetween the command and the newline starting * the response */ -if ((commptr = strstr(buf, cmd))) +if ((commptr = strstr(buf, cmd))) { memmove(buf, commptr, strlen(commptr)+1); -if ((nlptr = strchr(buf, '\n'))) -memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); +if ((nlptr = strchr(buf, '\n'))) +memmove(buf+strlen(cmd), nlptr, strlen(nlptr)+1); +} break; } -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 18/20] Make handling of monitor prompts more general.
Support arbitrary callbacks for secondary prompts. Reimplement qemudMonitorCommandExtra using such a callback. --- src/qemu_driver.c | 84 +--- 1 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index e92276e..3ab0fcc 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -88,6 +88,12 @@ static void qemuDriverUnlock(struct qemud_driver *driver) virMutexUnlock(driver-lock); } +/* Return -1 for error, 0 for success */ +typedef int qemudMonitorExtraPromptHandler(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data); + static void qemuDomainEventFlush(int timer, void *opaque); static void qemuDomainEventQueue(struct qemud_driver *driver, virDomainEventPtr event); @@ -116,6 +122,13 @@ static int qemudMonitorCommandWithFd(const virDomainObjPtr vm, const char *cmd, int scm_fd, char **reply); +static int qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply); static int qemudMonitorCommandExtra(const virDomainObjPtr vm, const char *cmd, const char *extra, @@ -2406,12 +2419,13 @@ out: } static int -qemudMonitorCommandExtra(const virDomainObjPtr vm, - const char *cmd, - const char *extra, - const char *extraPrompt, - int scm_fd, - char **reply) { +qemudMonitorCommandWithHandler(const virDomainObjPtr vm, + const char *cmd, + const char *extraPrompt, + qemudMonitorExtraPromptHandler extraHandler, + void *handlerData, + int scm_fd, + char **reply) { int size = 0; char *buf = NULL; @@ -2455,12 +2469,20 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, /* Look for QEMU prompt to indicate completion */ if (buf) { -if (extra) { -if (strstr(buf, extraPrompt) != NULL) { -if (qemudMonitorSend(vm, extra, -1) 0) -return -1; -extra = NULL; -} +char *foundPrompt; + +if (extraPrompt +(foundPrompt = strstr(buf, extraPrompt)) != NULL) { +char *promptEnd; + +if (extraHandler(vm, buf, foundPrompt, handlerData) 0) +return -1; +/* Discard output so far, necessary to detect whether + extraPrompt appears again. We don't need the output between + original command and this prompt anyway. */ +promptEnd = foundPrompt + strlen(extraPrompt); +memmove(buf, promptEnd, strlen(promptEnd)+1); +size -= promptEnd - buf; } else if ((tmp = strstr(buf, QEMU_CMD_PROMPT)) != NULL) { char *commptr = NULL, *nlptr = NULL; /* Preserve the newline */ @@ -2498,6 +2520,44 @@ qemudMonitorCommandExtra(const virDomainObjPtr vm, return -1; } +struct extraHandlerData +{ +const char *reply; +bool first; +}; + +static int +qemudMonitorCommandSimpleExtraHandler(const virDomainObjPtr vm, + const char *buf ATTRIBUTE_UNUSED, + const char *prompt ATTRIBUTE_UNUSED, + void *data_) +{ +struct extraHandlerData *data = data_; + +if (!data-first) +return 0; +if (qemudMonitorSend(vm, data-reply, -1) 0) +return -1; +data-first = false; +return 0; +} + +static int +qemudMonitorCommandExtra(const virDomainObjPtr vm, + const char *cmd, + const char *extra, + const char *extraPrompt, + int scm_fd, + char **reply) { +struct extraHandlerData data; + +data.reply = extra; +data.first = true; +return qemudMonitorCommandWithHandler(vm, cmd, extraPrompt, + qemudMonitorCommandSimpleExtraHandler, +
[libvirt] [PATCH 19/20] Consolidate cont into qemudMonitorSendCont()
The interface allows qemudMonitorSendCont() to report errors that are not overridden by its callers. Also fix a potential infinite loop in qemuDomainCoreDump() if sending cont repeatedly fails. --- src/qemu_driver.c | 89 +++-- 1 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 3ab0fcc..d013007 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -28,6 +28,7 @@ #include dirent.h #include limits.h #include string.h +#include stdbool.h #include stdio.h #include strings.h #include stdarg.h @@ -135,6 +136,9 @@ static int qemudMonitorCommandExtra(const virDomainObjPtr vm, const char *extraPrompt, int scm_fd, char **reply); +static int qemudMonitorSendCont(virConnectPtr conn, +const virDomainObjPtr vm, +bool *error_reported); static int qemudDomainSetMemoryBalloon(virConnectPtr conn, virDomainObjPtr vm, unsigned long newmem); @@ -1237,7 +1241,6 @@ static int qemudInitCpus(virConnectPtr conn, virDomainObjPtr vm, const char *migrateFrom) { -char *info = NULL; #if HAVE_SCHED_GETAFFINITY cpu_set_t mask; int i, maxcpu = QEMUD_CPUMASK_LEN; @@ -1272,13 +1275,15 @@ qemudInitCpus(virConnectPtr conn, #endif /* HAVE_SCHED_GETAFFINITY */ if (migrateFrom == NULL) { +bool error_reported; + /* Allow the CPUS to start executing */ -if (qemudMonitorCommand(vm, cont, info) 0) { -qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - %s, _(resume operation failed)); +if (qemudMonitorSendCont(conn, vm, error_reported) 0) { +if (!error_reported) +qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + %s, _(resume operation failed)); return -1; } -VIR_FREE(info); } return 0; @@ -2573,6 +2578,20 @@ qemudMonitorCommand(const virDomainObjPtr vm, return qemudMonitorCommandWithFd(vm, cmd, -1, reply); } +static int +qemudMonitorSendCont(virConnectPtr conn ATTRIBUTE_UNUSED, + const virDomainObjPtr vm, + bool *error_reported) { +char *reply; + +*error_reported = false; +if (qemudMonitorCommand(vm, cont, reply) 0) +return -1; +qemudDebug (%s: cont reply: %s, vm-def-name, info); +VIR_FREE(reply); +return 0; +} + static virDrvOpenStatus qemudOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { @@ -3057,7 +3076,6 @@ cleanup: static int qemudDomainResume(virDomainPtr dom) { struct qemud_driver *driver = dom-conn-privateData; -char *info; virDomainObjPtr vm; int ret = -1; virDomainEventPtr event = NULL; @@ -3078,17 +3096,18 @@ static int qemudDomainResume(virDomainPtr dom) { goto cleanup; } if (vm-state == VIR_DOMAIN_PAUSED) { -if (qemudMonitorCommand(vm, cont, info) 0) { -qemudReportError(dom-conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - %s, _(resume operation failed)); +bool error_reported; + +if (qemudMonitorSendCont(dom-conn, vm, error_reported) 0) { +if (!error_reported) +qemudReportError(dom-conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + %s, _(resume operation failed)); goto cleanup; } vm-state = VIR_DOMAIN_RUNNING; -qemudDebug(Reply %s, info); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED, VIR_DOMAIN_EVENT_RESUMED_UNPAUSED); -VIR_FREE(info); } if (virDomainSaveStatus(dom-conn, driver-stateDir, vm) 0) goto cleanup; @@ -3822,13 +3841,13 @@ cleanup: will support synchronous operations so we always get here after the migration is complete. */ if (resume paused) { -if (qemudMonitorCommand(vm, cont, info) 0) { -qemudReportError(dom-conn, dom, NULL, VIR_ERR_OPERATION_FAILED, - %s, _(resuming after dump failed)); -goto cleanup; +bool error_reported; + +if (qemudMonitorSendCont(dom-conn, vm, error_reported) 0) { +if (!error_reported) +qemudReportError(dom-conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + %s, _(resuming after dump failed)); } -DEBUG (%s: cont reply: %s, vm-def-name, info); -VIR_FREE(info); } if (vm)
[libvirt] [PATCH 20/20] Add support for qcow encrypted volumes to qemu.
Changes since the third submission: - Add flags parameter to virSecretDefineXML(), virSecretGetXMLDesc(), virSecretGetValue(), virSecretSetValue(), and all derived interfaces. --- src/qemu_driver.c | 161 ++--- 1 files changed, 153 insertions(+), 8 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index d013007..b73d665 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1296,12 +1296,6 @@ qemudInitPasswords(virConnectPtr conn, virDomainObjPtr vm) { char *info = NULL; -/* - * NB: Might have more passwords to set in the future. eg a qcow - * disk decryption password, but there's no monitor command - * for that yet... - */ - if ((vm-def-ngraphics == 1) vm-def-graphics[0]-type == VIR_DOMAIN_GRAPHICS_TYPE_VNC (vm-def-graphics[0]-data.vnc.passwd || driver-vncPassword)) { @@ -2578,14 +2572,165 @@ qemudMonitorCommand(const virDomainObjPtr vm, return qemudMonitorCommandWithFd(vm, cmd, -1, reply); } +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 encryption 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-lookupByUUIDString == 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 encryption for volume %s), path); +return NULL; +} + +if (enc-secrets[0]-uuid == NULL) { +qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN, + _(missing secret uuid for volume %s), path); +return NULL; +} +secret = conn-secretDriver-lookupByUUIDString(conn, +enc-secrets[0]-uuid); +if (secret == NULL) +return NULL; +data = conn-secretDriver-getValue(secret, size, true, 0); +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; +} + +struct sendVolumePassphraseState { +virConnectPtr conn; +bool *error_reported; +}; + +static int +qemudMonitorSendVolumePassphrase(const virDomainObjPtr vm, + const char *buf, + const char *prompt, + void *data) +{ +const struct sendVolumePassphraseState *state = data; +char *passphrase, *path; +const char *prompt_path; +size_t path_len, passphrase_len = 0; +int res; + +/* The complete prompt looks like this: + ide0-hd0 (/path/to/volume) is encrypted. + Password: + prompt starts with ) is encrypted. Extract /path/to/volume. */ +for (prompt_path = prompt; prompt_path buf prompt_path[-1] != '('; + prompt_path--) +; +if (prompt_path == buf) +
[libvirt] [PATCH] Ignores EOPNOTSUPP when attempting to access an image on an NFS share.
rhbz#517157 Signed-off-by: Darryl L. Pierce dpie...@redhat.com --- src/security_selinux.c | 23 --- 1 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/security_selinux.c b/src/security_selinux.c index 0db9f49..f1e3f17 100644 --- a/src/security_selinux.c +++ b/src/security_selinux.c @@ -323,6 +323,8 @@ SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon) VIR_INFO(Setting SELinux context on '%s' to '%s', path, tcon); if (setfilecon(path, tcon) 0) { +int setfilecon_errno = errno; + if (getfilecon(path, econ) = 0) { if (STREQ(tcon, econ)) { freecon(econ); @@ -331,14 +333,21 @@ SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon) } freecon(econ); } -virSecurityReportError(conn, VIR_ERR_ERROR, - _(%s: unable to set security context - '\%s\' on %s: %s.), __func__, - tcon, - path, - virStrerror(errno, ebuf, sizeof ebuf)); -if (security_getenforce() == 1) + + /* if the error complaint is related to an image hosted on +* an nfs mount, then ignore it. +* rhbz 517157 +*/ + if (setfilecon_errno != EOPNOTSUPP) { + virSecurityReportError(conn, VIR_ERR_ERROR, +_(%s: unable to set security context + '\%s\' on %s: %s.), __func__, +tcon, +path, +virStrerror(errno, ebuf, sizeof ebuf)); + if (security_getenforce() == 1) return -1; + } } return 0; } -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] Re: OpenVZ : The restriction of domain name should be addressed
2009/7/24 Daniel P. Berrange berra...@redhat.com We should make use of this --name parameter then - I guess it didn't exist when we first wrote the driver. It is useful to users to have separate ID vs Name parameters - and in fact the current reusing of 'ID' for the name, causes a little confusion in virsh's lookup routines because it can't tell whether the parameter its given is a name or an ID, since they are identical. There is still a question of how to specify both a name and CTID in XML description. By default, CTID can be obtained as openvzGimmeFirstUnusedCTID(), but actually I think that there exists a number of persons interested in giving CTIDs manually. Well, can domain id='' be used for CTID remaining name for alphabetical domain name? I worte a small patch and tried with following XML setting. ### Patch ### --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -130,9 +130,6 @@ ADD_ARG_LIT(VZCTL); ADD_ARG_LIT(--quiet); ADD_ARG_LIT(create); -ADD_ARG_LIT(vmdef-id); - -ADD_ARG_LIT(--name); ADD_ARG_LIT(vmdef-name); ### XML ### domain id='100' nameabc/name I found the type of id was identified as number( obj-type == XPATH_NUMBER ) in virXPathLongBase, but it is clearly string before converted. I think correct path is to go in the first if context( obj-type == XPATH_STRING ) and run strtol. Then I tried with following XML. ### XML ### domain id=100 nameabc/name I got following error. AttValue: or ' expected I'm not sure from which function should return this result. Maybe this is the first step to go forward. I am doubting openvz*LookupBy* functions be also modified, right? - Yuji Nishida nish...@nict.go.jp -- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list