[libvirt] [PATCHv5 0/9] smartcard round 5

Next round. The first 5 patches were previously ack'd in round 4: https://www.redhat.com/archives/libvir-list/2011-February/msg00026.html However, I heavily rewrote patch 3 to support later spicevmc patches, as well as tweaked patch 1 and 5 to avoid the need for memory rounding. Patch 6 is mostly a port of a patch that has already seen use in RHEL 6.0 which adds the use of -chardev spicevmc,name=vdagent as a means of communicating with the guest using messages across the main SPICE graphics channel, but tweaked to be a bit more robust. Patch 7 was an experiment to add a new vdagent channel type instead of reusing virtio for the spicevmc channel; I think it failed, but wanted to at least post it in case I was on the right track after all. Patch 8 undoes 7. It won't hurt my feelings if you skip those. Patch 9 therefore immediately follows patch 6, and marries the two concepts to create a smartcard passthrough device that uses a new smartcard channel of the SPICE server. Again, this entire series depends on a feature that has been proposed for upstream qemu, but not accepted yet; while it has probably stabilized to some degree, it may have minor tweaks. Conversely, I feel that the XML representation (the most important part to get right, since it becomes our API contract) is accurate and flexible enough to cover whatever minor modifiations qemu throws at us as followup patches to qemu_command.c. Daniel P. Berrange (1): spicevmc: support new qemu chardev Eric Blake (8): smartcard: add XML support for <smartcard> device smartcard: add domain conf support smartcard: check for qemu capability smartcard: enable SELinux support smartcard: turn on qemu support RFC: spicevmc: call out vdagent as a channel target Revert "RFC: spicevmc: call out vdagent as a channel target" smartcard: add spicevmc support cfg.mk | 1 + docs/formatdomain.html.in | 120 ++++++- docs/schemas/domain.rng | 70 ++++- src/conf/domain_conf.c | 395 +++++++++++++++++++- src/conf/domain_conf.h | 64 +++- src/libvirt_private.syms | 6 + src/qemu/qemu_capabilities.c | 17 +- src/qemu/qemu_capabilities.h | 3 + src/qemu/qemu_command.c | 154 +++++++- src/security/security_selinux.c | 76 ++++ tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 | 229 +++++++++++ tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device | 74 ++++ tests/qemuhelptest.c | 43 +++ .../qemuxml2argv-channel-spicevmc.args | 9 + .../qemuxml2argv-channel-spicevmc.xml | 34 ++ .../qemuxml2argv-smartcard-controller.args | 7 + .../qemuxml2argv-smartcard-controller.xml | 19 + .../qemuxml2argv-smartcard-host-certificates.args | 8 + .../qemuxml2argv-smartcard-host-certificates.xml | 20 + .../qemuxml2argv-smartcard-host.args | 7 + .../qemuxml2argv-smartcard-host.xml | 16 + ...emuxml2argv-smartcard-passthrough-spicevmc.args | 7 + ...qemuxml2argv-smartcard-passthrough-spicevmc.xml | 16 + .../qemuxml2argv-smartcard-passthrough-tcp.args | 8 + .../qemuxml2argv-smartcard-passthrough-tcp.xml | 19 + tests/qemuxml2argvtest.c | 20 + 26 files changed, 1410 insertions(+), 32 deletions(-) create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-spicevmc.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-spicevmc.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-spicevmc.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-spicevmc.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml -- 1.7.4

Assuming a hypervisor that supports multiple smartcard devices in the guest, this would be a valid XML description: <devices> <smartcard mode='host'/> <smartcard mode='host-certificates'> <certificate>/path/to/cert1</certificate> <certificate>/path/to/cert2</certificate> <certificate>/path/to/cert3</certificate> </smartcard> <smartcard mode='passthrough' type='tcp'> <source mode='bind' host='127.0.0.1' service='2001'/> <protocol type='raw'/> </smartcard> </devices> (As of this commit, the qemu hypervisor will be the first implementation, but it only supports one smartcard.) * docs/formatdomain.html.in (Smartcard devices): New section. * docs/schemas/domain.rng (smartcard): New define, used in devices. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml: New file to test schema. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml: Likewise. --- Notes: v2: incoporate feedback from RFC, make passthrough type default to tcp v3: add optional <address> per <smartcard>, enhance <controller> to understand ccid, add optional <database> in mode hosts-certificates, optional <source> in mode hosts, add another test file, revert v2 passthrough mode back to requiring explicit type v4: drop <source> in host mode, relax <certificate> in host-certificates, document default <database> directory v5: avoid rounding in tests docs/formatdomain.html.in | 95 +++++++++++++++++++- docs/schemas/domain.rng | 66 ++++++++++++++ .../qemuxml2argv-smartcard-controller.xml | 19 ++++ .../qemuxml2argv-smartcard-host-certificates.xml | 20 ++++ .../qemuxml2argv-smartcard-host.xml | 16 ++++ .../qemuxml2argv-smartcard-passthrough-tcp.xml | 19 ++++ 6 files changed, 234 insertions(+), 1 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index db0b762..9f1bb5f 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -892,7 +892,7 @@ <p> Each controller has a mandatory attribute <code>type</code>, - which must be one of "ide", "fdc", "scsi", "sata", or + which must be one of "ide", "fdc", "scsi", "sata", "ccid", or "virtio-serial", and a mandatory attribute <code>index</code> which is the decimal integer describing in which order the bus controller is encountered (for use in <code>controller</code> @@ -991,6 +991,99 @@ not used by qemu.</dd> </dl> + <h4><a name="elementsSmartcard">Smartcard devices</a></h4> + + <p> + A virtual smartcard device can be supplied to the guest via the + <code>smartcard</code> element. A USB smartcard reader device on + the host cannot be used on a guest with simple device + passthrough, since it will then not be available on the host, + possibly locking the host computer when it is "removed". + Therefore, some hypervisors provide a specialized virtual device + that can present a smartcard interface to the guest, with + several modes for describing how credentials are obtained from + the host or even a from a channel created to a third-party + smartcard provider. <span class="since">Since 0.8.8</span> + </p> + +<pre> + ... + <devices> + <smartcard mode='host'/> + <smartcard mode='host-certificates'> + <certificate>cert1</certificate> + <certificate>cert2</certificate> + <certificate>cert3</certificate> + <database>/etc/pki/nssdb/</database> + </smartcard> + <smartcard mode='passthrough' type='tcp'> + <source mode='bind' host='127.0.0.1' service='2001'/> + <protocol type='raw'/> + <address type='ccid' controller='0' slot='0'/> + </smartcard> + </devices> + ... +</pre> + + <p> + The <code><smartcard></code> element has a mandatory + attribute <code>mode</code>. The following modes are supported; + in each mode, the guest sees a device on its USB bus that + behaves like a physical USB CCID (Chip/Smart Card Interface + Device) card. + </p> + + <dl> + <dt><code>mode='host'</code></dt> + <dd>The simplest operation, where the hypervisor relays all + requests from the guest into direct access to the host's + smartcard via NSS. No other attributes or sub-elements are + required. See below about the use of an + optional <code><address></code> sub-element.</dd> + + <dt><code>mode='host-certificates'</code></dt> + <dd>Rather than requiring a smartcard to be plugged into the + host, it is possible to provide three NSS certificate names + residing in a database on the host. These certificates can be + generated via the command <code>certutil -d /etc/pki/nssdb -x -t + CT,CT,CT -S -s CN=cert1 -n cert1</code>, and the resulting three + certificate names must be supplied as the content of each of + three <code><certificate></code> sub-elements. An + additional sub-element <code><database></code> can specify + the absolute path to an alternate directory (matching + the <code>-d</code> option of the <code>certutil</code> command + when creating the certificates); if not present, it defaults to + /etc/pki/nssdb.</dd> + + <dt><code>mode='passthrough'</code></dt> + <dd>Rather than having the hypervisor directly communicate with + the host, it is possible to tunnel all requests through a + secondary character device to a third-party provider (which may + in turn be talking to a smartcard or using three certificate + files). In this mode of operation, an additional + attribute <code>type</code> is required, matching one of the + supported <a href="#elementsConsole">serial device</a> types, to + describe the host side of the tunnel; <code>type='tcp'</code> is + typical. Further sub-elements, such + as <code><source></code>, are required according to the + given type, although a <code><target></code> sub-element + is not required (since the consumer of the character device is + the hypervisor itself, rather than a device visible in the + guest).</dd> + </dl> + + <p> + Each mode supports an optional + sub-element <code><address></code>, which fine-tunes the + correlation between the smartcard and a ccid bus controller. + If present, the element must have an attribute + of <code>type='ccid'</code> as well as a <code>bus</code> + attribute listing the index of the bus that the smartcard + utilizes. An optional <code>slot</code> attribute lists which + slot within the bus. For now, qemu only supports at most one + smartcard, with an address of bus=0 slot=0. + </p> + <h4><a name="elementsNICS">Network interfaces</a></h4> <pre> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 8a2e7c7..69fb432 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -749,6 +749,7 @@ <value>ide</value> <value>scsi</value> <value>sata</value> + <value>ccid</value> </choice> </attribute> </optional> @@ -1632,6 +1633,51 @@ </interleave> </element> </define> + <define name="smartcard"> + <element name="smartcard"> + <choice> + <group> + <attribute name="mode"> + <value>host</value> + </attribute> + <!-- might need to add optional database element here later --> + </group> + <group> + <attribute name="mode"> + <value>host-certificates</value> + </attribute> + <ref name='certificate'/> + <ref name='certificate'/> + <ref name='certificate'/> + <optional> + <element name="database"> + <ref name="absDirPath"/> + </element> + </optional> + </group> + <group> + <attribute name="mode"> + <value>passthrough</value> + </attribute> + <ref name="qemucdevSrcType"/> + <interleave> + <ref name="qemucdevSrcDef"/> + <optional> + <ref name="qemucdevTgtDef"/> + </optional> + </interleave> + </group> + </choice> + <optional> + <ref name="address"/> + </optional> + </element> + </define> + <define name="certificate"> + <element name="certificate"> + <text/> + </element> + </define> <define name="input"> <element name="input"> <attribute name="type"> @@ -1768,8 +1814,21 @@ </attribute> </optional> </define> + <define name="ccidaddress"> + <attribute name="controller"> + <ref name="driveController"/> + </attribute> + <optional> + <attribute name="slot"> + <ref name="driveUnit"/> + </attribute> + </optional> + </define> <!-- Devices attached to a domain. + Sub-elements such as <alias> are not documented here, as they + can only exist when generated for a live domain and are ignored + when defining a domain. --> <define name="devices"> <element name="devices"> @@ -1792,6 +1851,7 @@ <ref name="parallel"/> <ref name="serial"/> <ref name="channel"/> + <ref name="smartcard"/> </choice> </zeroOrMore> <optional> @@ -2021,6 +2081,12 @@ </attribute> <ref name="virtioserialaddress"/> </group> + <group> + <attribute name="type"> + <value>ccid</value> + </attribute> + <ref name="ccidaddress"/> + </group> </choice> </element> </define> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml new file mode 100644 index 0000000..2a53dbb --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml @@ -0,0 +1,19 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='ccid' index='0'/> + <smartcard mode='host'> + <address type='ccid' controller='0' slot='0'/> + </smartcard> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml new file mode 100644 index 0000000..5a9844b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml @@ -0,0 +1,20 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <smartcard mode='host-certificates'> + <certificate>cert1</certificate> + <certificate>cert2</certificate> + <certificate>cert3</certificate> + </smartcard> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml new file mode 100644 index 0000000..95790f2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml @@ -0,0 +1,16 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <smartcard mode='host'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml new file mode 100644 index 0000000..f133391 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml @@ -0,0 +1,19 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219136</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <devices> + <emulator>/usr/bin/qemu</emulator> + <smartcard mode='passthrough' type='tcp'> + <source mode='bind' host='127.0.0.1' service='2001'/> + <protocol type='raw'/> + </smartcard> + <memballoon model='virtio'/> + </devices> +</domain> -- 1.7.4

Assuming a hypervisor that supports multiple smartcard devices in the guest, this would be a valid XML description:
<devices> <smartcard mode='host'/> <smartcard mode='host-certificates'> <certificate>/path/to/cert1</certificate> <certificate>/path/to/cert2</certificate> <certificate>/path/to/cert3</certificate> </smartcard> <smartcard mode='passthrough' type='tcp'> <source mode='bind' host='127.0.0.1' service='2001'/> <protocol type='raw'/> </smartcard> </devices>
(As of this commit, the qemu hypervisor will be the first implementation, but it only supports one smartcard.)
* docs/formatdomain.html.in (Smartcard devices): New section. * docs/schemas/domain.rng (smartcard): New define, used in devices. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.xml: New file to test schema. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.xml: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.xml: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.xml: Likewise.
Same as previously acked v4, except for memory amount in test XMLs. ACK Jirka

* src/conf/domain_conf.h (virDomainSmartcardType): New enum. (virDomainSmartcardDef, virDomainDeviceCcidAddress): New structs. (virDomainDef): Include smartcards. (virDomainSmartcardDefIterator): New typedef. (virDomainSmartcardDefFree, virDomainSmartcardDefForeach): New prototypes. (virDomainControllerType, virDomainDeviceAddressType): Add ccid enum values. (virDomainDeviceInfo): Add ccid address type. * src/conf/domain_conf.c (virDomainSmartcard): Convert between enum and string. (virDomainSmartcardDefParseXML, virDomainSmartcardDefFormat) (virDomainSmartcardDefFree, virDomainDeviceCcidAddressParseXML) (virDomainDefMaybeAddSmartcardController): New functions. (virDomainDefParseXML): Parse the new XML. (virDomainDefFormat): Convert back to XML. (virDomainDefFree): Clean up. (virDomainDeviceInfoIterate): Iterate over passthrough aliases. (virDomainController, virDomainDeviceAddress) (virDomainDeviceInfoParseXML, virDomainDeviceInfoFormat) (virDomainDefAddImplicitControllers): Support new values. * src/libvirt_private.syms (domain_conf.h): New exports. * cfg.mk (useless_free_options): List new function. --- Notes: v2: first version of patch (v1 was xml proposal only) v3: add controller type='ccid' support, extra smartcard element support v4: remove host/dev, relax host-certificates/cert to be any string, define default host-certificates/database value v5: no change cfg.mk | 1 + src/conf/domain_conf.c | 366 ++++++++++++++++++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 52 +++++++- src/libvirt_private.syms | 4 + 4 files changed, 411 insertions(+), 12 deletions(-) diff --git a/cfg.mk b/cfg.mk index 2cc6f90..7664bdf 100644 --- a/cfg.mk +++ b/cfg.mk @@ -100,6 +100,7 @@ useless_free_options = \ --name=virDomainInputDefFree \ --name=virDomainNetDefFree \ --name=virDomainObjFree \ + --name=virDomainSmartcardDefFree \ --name=virDomainSnapshotDefFree \ --name=virDomainSnapshotObjFree \ --name=virDomainSoundDefFree \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index aba4223..b1c775b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -109,7 +109,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", "pci", "drive", - "virtio-serial") + "virtio-serial", + "ccid") VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", @@ -159,7 +160,8 @@ VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST, "fdc", "scsi", "sata", - "virtio-serial") + "virtio-serial", + "ccid") VIR_ENUM_IMPL(virDomainControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST, "auto", @@ -232,6 +234,11 @@ VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST, "telnets", "tls") +VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST, + "host", + "host-certificates", + "passthrough") + VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST, "sb16", "es1370", @@ -693,6 +700,35 @@ void virDomainChrDefFree(virDomainChrDefPtr def) VIR_FREE(def); } +void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def) +{ + size_t i; + if (!def) + return; + + switch (def->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++) + VIR_FREE(def->data.cert.file[i]); + VIR_FREE(def->data.cert.database); + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + virDomainChrSourceDefClear(&def->data.passthru); + break; + + default: + break; + } + + virDomainDeviceInfoClear(&def->info); + + VIR_FREE(def); +} + void virDomainSoundDefFree(virDomainSoundDefPtr def) { if (!def) @@ -834,6 +870,10 @@ void virDomainDefFree(virDomainDefPtr def) virDomainNetDefFree(def->nets[i]); VIR_FREE(def->nets); + for (i = 0 ; i < def->nsmartcards ; i++) + virDomainSmartcardDefFree(def->smartcards[i]); + VIR_FREE(def->smartcards); + for (i = 0 ; i < def->nserials ; i++) virDomainChrDefFree(def->serials[i]); VIR_FREE(def->serials); @@ -1198,6 +1238,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, for (i = 0; i < def->ncontrollers ; i++) if (cb(def, &def->controllers[i]->info, opaque) < 0) return -1; + for (i = 0; i < def->nsmartcards ; i++) + if (cb(def, &def->smartcards[i]->info, opaque) < 0) + return -1; for (i = 0; i < def->nserials ; i++) if (cb(def, &def->serials[i]->info, opaque) < 0) return -1; @@ -1240,16 +1283,11 @@ void virDomainDefClearDeviceAliases(virDomainDefPtr def) /* Generate a string representation of a device address * @param address Device address to stringify */ -static int virDomainDeviceInfoFormat(virBufferPtr buf, - virDomainDeviceInfoPtr info, - int flags) +static int ATTRIBUTE_NONNULL(2) +virDomainDeviceInfoFormat(virBufferPtr buf, + virDomainDeviceInfoPtr info, + int flags) { - if (!info) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("missing device information")); - return -1; - } - if (info->alias && !(flags & VIR_DOMAIN_XML_INACTIVE)) { virBufferVSprintf(buf, " <alias name='%s'/>\n", info->alias); @@ -1285,6 +1323,12 @@ static int virDomainDeviceInfoFormat(virBufferPtr buf, info->addr.vioserial.port); break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID: + virBufferVSprintf(buf, " controller='%d' slot='%d'", + info->addr.ccid.controller, + info->addr.ccid.slot); + break; + default: virDomainReportError(VIR_ERR_INTERNAL_ERROR, _("unknown address type '%d'"), info->type); @@ -1458,6 +1502,40 @@ cleanup: return ret; } +static int +virDomainDeviceCcidAddressParseXML(xmlNodePtr node, + virDomainDeviceCcidAddressPtr addr) +{ + char *controller, *slot; + int ret = -1; + + memset(addr, 0, sizeof(*addr)); + + controller = virXMLPropString(node, "controller"); + slot = virXMLPropString(node, "slot"); + + if (controller && + virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'controller' attribute")); + goto cleanup; + } + + if (slot && + virStrToLong_ui(slot, NULL, 10, &addr->slot) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse <address> 'slot' attribute")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(controller); + VIR_FREE(slot); + return ret; +} + /* Parse the XML definition for a device address * @param node XML nodeset to parse for device address definition */ @@ -1526,6 +1604,11 @@ virDomainDeviceInfoParseXML(xmlNodePtr node, goto cleanup; break; + case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID: + if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0) + goto cleanup; + break; + default: /* Should not happen */ virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -3185,6 +3268,128 @@ error: goto cleanup; } +static virDomainSmartcardDefPtr +virDomainSmartcardDefParseXML(xmlNodePtr node, + int flags) +{ + xmlNodePtr cur; + char *mode = NULL; + char *type = NULL; + virDomainSmartcardDefPtr def; + int i; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + mode = virXMLPropString(node, "mode"); + if (mode == NULL) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("missing smartcard device mode")); + goto error; + } + if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("unknown smartcard device mode: %s"), + mode); + goto error; + } + + switch (def->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + i = 0; + cur = node->children; + while (cur) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "certificate")) { + if (i == 3) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("host-certificates mode needs " + "exactly three certificates")); + goto error; + } + def->data.cert.file[i] = (char *)xmlNodeGetContent(cur); + if (!def->data.cert.file[i]) { + virReportOOMError(); + goto error; + } + i++; + } else if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "database") && + !def->data.cert.database) { + def->data.cert.database = (char *)xmlNodeGetContent(cur); + if (!def->data.cert.database) { + virReportOOMError(); + goto error; + } + if (*def->data.cert.database != '/') { + virDomainReportError(VIR_ERR_XML_ERROR, + _("expecting absolute path: %s"), + def->data.cert.database); + goto error; + } + } + cur = cur->next; + } + if (i < 3) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("host-certificates mode needs " + "exactly three certificates")); + goto error; + } + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + type = virXMLPropString(node, "type"); + if (type == NULL) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("passthrough mode requires a character " + "device type attribute")); + goto error; + } + if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("unknown type presented to host for " + "character device: %s"), type); + goto error; + } + + cur = node->children; + if (virDomainChrSourceDefParseXML(&def->data.passthru, cur) < 0) + goto error; + break; + + default: + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unknown smartcard mode")); + goto error; + } + + if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0) + goto error; + if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Controllers must use the 'ccid' address type")); + goto error; + } + +cleanup: + VIR_FREE(mode); + VIR_FREE(type); + + return def; + +error: + virDomainSmartcardDefFree(def); + def = NULL; + goto cleanup; +} + /* Parse the XML definition for a network interface */ static virDomainInputDefPtr virDomainInputDefParseXML(const char *ostype, @@ -5258,6 +5463,26 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, VIR_FREE(nodes); + /* analysis of the smartcard devices */ + if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot extract smartcard devices")); + goto error; + } + if (n && VIR_ALLOC_N(def->smartcards, n) < 0) + goto no_memory; + + for (i = 0 ; i < n ; i++) { + virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i], + flags); + if (!card) + goto error; + + def->smartcards[def->nsmartcards++] = card; + } + VIR_FREE(nodes); + + /* analysis of the character devices */ if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -5936,6 +6161,45 @@ static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def) } +static int +virDomainDefMaybeAddSmartcardController(virDomainDefPtr def) +{ + /* Look for any smartcard devs */ + int i; + + for (i = 0 ; i < def->nsmartcards ; i++) { + virDomainSmartcardDefPtr smartcard = def->smartcards[i]; + int idx = 0; + + if (smartcard->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) { + idx = smartcard->info.addr.ccid.controller; + } else if (smartcard->info.type + == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + int j; + int max = -1; + + for (j = 0; j < def->nsmartcards; j++) { + virDomainDeviceInfoPtr info = &def->smartcards[j]->info; + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID && + info->addr.ccid.controller == 0 && + (int) info->addr.ccid.slot > max) + max = info->addr.ccid.slot; + } + smartcard->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID; + smartcard->info.addr.ccid.controller = 0; + smartcard->info.addr.ccid.slot = max + 1; + } + + if (virDomainDefMaybeAddController(def, + VIR_DOMAIN_CONTROLLER_TYPE_CCID, + idx) < 0) + return -1; + } + + return 0; +} + + /* * Based on the declared <address/> info for any devices, * add neccessary drive controllers which are not already present @@ -5962,6 +6226,9 @@ int virDomainDefAddImplicitControllers(virDomainDefPtr def) if (virDomainDefMaybeAddVirtioSerialController(def) < 0) return -1; + if (virDomainDefMaybeAddSmartcardController(def) < 0) + return -1; + return 0; } @@ -6741,6 +7008,56 @@ virDomainChrDefFormat(virBufferPtr buf, } static int +virDomainSmartcardDefFormat(virBufferPtr buf, + virDomainSmartcardDefPtr def, + int flags) +{ + const char *mode = virDomainSmartcardTypeToString(def->type); + size_t i; + + if (!mode) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected smartcard type %d"), def->type); + return -1; + } + + virBufferVSprintf(buf, " <smartcard mode='%s'", mode); + switch (def->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + if (!virDomainDeviceInfoIsSet(&def->info)) { + virBufferAddLit(buf, "/>\n"); + return 0; + } + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + virBufferAddLit(buf, ">\n"); + for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++) + virBufferEscapeString(buf, " <certificate>%s</certificate>\n", + def->data.cert.file[i]); + if (def->data.cert.database) + virBufferEscapeString(buf, " <database>%s</database>\n", + def->data.cert.database); + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + if (virDomainChrSourceDefFormat(buf, &def->data.passthru, false, + flags) < 0) + return -1; + break; + + default: + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected smartcard type %d"), def->type); + return -1; + } + if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) + return -1; + virBufferAddLit(buf, " </smartcard>\n"); + return 0; +} + +static int virDomainSoundDefFormat(virBufferPtr buf, virDomainSoundDefPtr def, int flags) @@ -7546,6 +7863,10 @@ char *virDomainDefFormat(virDomainDefPtr def, if (virDomainNetDefFormat(&buf, def->nets[n], flags) < 0) goto cleanup; + for (n = 0 ; n < def->nsmartcards ; n++) + if (virDomainSmartcardDefFormat(&buf, def->smartcards[n], flags) < 0) + goto cleanup; + for (n = 0 ; n < def->nserials ; n++) if (virDomainChrDefFormat(&buf, def->serials[n], flags) < 0) goto cleanup; @@ -8624,6 +8945,29 @@ done: } +int virDomainSmartcardDefForeach(virDomainDefPtr def, + bool abortOnError, + virDomainSmartcardDefIterator iter, + void *opaque) +{ + int i; + int rc = 0; + + for (i = 0 ; i < def->nsmartcards ; i++) { + if ((iter)(def, + def->smartcards[i], + opaque) < 0) + rc = -1; + + if (abortOnError && rc != 0) + goto done; + } + +done: + return rc; +} + + int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk, bool allowProbing, bool ignoreOpenFailure, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index feae203..81c3f38 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -73,6 +73,7 @@ enum virDomainDeviceAddressType { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL, + VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST }; @@ -102,6 +103,13 @@ struct _virDomainDeviceVirtioSerialAddress { unsigned int port; }; +typedef struct _virDomainDeviceCcidAddress virDomainDeviceCcidAddress; +typedef virDomainDeviceCcidAddress *virDomainDeviceCcidAddressPtr; +struct _virDomainDeviceCcidAddress { + unsigned int controller; + unsigned int slot; +}; + typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { @@ -111,6 +119,7 @@ struct _virDomainDeviceInfo { virDomainDevicePCIAddress pci; virDomainDeviceDriveAddress drive; virDomainDeviceVirtioSerialAddress vioserial; + virDomainDeviceCcidAddress ccid; } addr; }; @@ -220,6 +229,7 @@ enum virDomainControllerType { VIR_DOMAIN_CONTROLLER_TYPE_SCSI, VIR_DOMAIN_CONTROLLER_TYPE_SATA, VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, + VIR_DOMAIN_CONTROLLER_TYPE_CCID, VIR_DOMAIN_CONTROLLER_TYPE_LAST }; @@ -461,6 +471,33 @@ struct _virDomainChrDef { virDomainDeviceInfo info; }; +enum virDomainSmartcardType { + VIR_DOMAIN_SMARTCARD_TYPE_HOST, + VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES, + VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH, + + VIR_DOMAIN_SMARTCARD_TYPE_LAST, +}; + +# define VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES 3 +# define VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE "/etc/pki/nssdb" + +typedef struct _virDomainSmartcardDef virDomainSmartcardDef; +typedef virDomainSmartcardDef *virDomainSmartcardDefPtr; +struct _virDomainSmartcardDef { + int type; /* virDomainSmartcardType */ + union { + /* no extra data for 'host' */ + struct { + char *file[VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES]; + char *database; + } cert; /* 'host-certificates' */ + virDomainChrSourceDef passthru; /* 'passthrough' */ + } data; + + virDomainDeviceInfo info; +}; + enum virDomainInputType { VIR_DOMAIN_INPUT_TYPE_MOUSE, VIR_DOMAIN_INPUT_TYPE_TABLET, @@ -1032,6 +1069,9 @@ struct _virDomainDef { int nhostdevs; virDomainHostdevDefPtr *hostdevs; + int nsmartcards; + virDomainSmartcardDefPtr *smartcards; + int nserials; virDomainChrDefPtr *serials; @@ -1110,6 +1150,7 @@ void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def); void virDomainControllerDefFree(virDomainControllerDefPtr def); void virDomainFSDefFree(virDomainFSDefPtr def); void virDomainNetDefFree(virDomainNetDefPtr def); +void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def); void virDomainChrDefFree(virDomainChrDefPtr def); void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def); void virDomainSoundDefFree(virDomainSoundDefPtr def); @@ -1258,6 +1299,15 @@ int virDomainObjListGetInactiveNames(virDomainObjListPtr doms, char **const names, int maxnames); +typedef int (*virDomainSmartcardDefIterator)(virDomainDefPtr def, + virDomainSmartcardDefPtr dev, + void *opaque); + +int virDomainSmartcardDefForeach(virDomainDefPtr def, + bool abortOnError, + virDomainSmartcardDefIterator iter, + void *opaque); + typedef int (*virDomainChrDefIterator)(virDomainDefPtr def, virDomainChrDefPtr dev, void *opaque); @@ -1267,7 +1317,6 @@ int virDomainChrDefForeach(virDomainDefPtr def, virDomainChrDefIterator iter, void *opaque); - typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk, const char *path, size_t depth, @@ -1306,6 +1355,7 @@ VIR_ENUM_DECL(virDomainNetBackend) VIR_ENUM_DECL(virDomainChrDevice) VIR_ENUM_DECL(virDomainChrChannelTarget) VIR_ENUM_DECL(virDomainChrConsoleTarget) +VIR_ENUM_DECL(virDomainSmartcard) VIR_ENUM_DECL(virDomainChr) VIR_ENUM_DECL(virDomainChrTcpProtocol) VIR_ENUM_DECL(virDomainSoundModel) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3a5aec9..52e44fa 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -283,6 +283,10 @@ virDomainRemoveInactive; virDomainSaveConfig; virDomainSaveStatus; virDomainSaveXML; +virDomainSmartcardDefForeach; +virDomainSmartcardDefFree; +virDomainSmartcardTypeFromString; +virDomainSmartcardTypeToString; virDomainSnapshotAssignDef; virDomainSnapshotDefFormat; virDomainSnapshotDefFree; -- 1.7.4

On Thu, Feb 03, 2011 at 21:01:13 -0700, Eric Blake wrote:
* src/conf/domain_conf.h (virDomainSmartcardType): New enum. (virDomainSmartcardDef, virDomainDeviceCcidAddress): New structs. (virDomainDef): Include smartcards. (virDomainSmartcardDefIterator): New typedef. (virDomainSmartcardDefFree, virDomainSmartcardDefForeach): New prototypes. (virDomainControllerType, virDomainDeviceAddressType): Add ccid enum values. (virDomainDeviceInfo): Add ccid address type. * src/conf/domain_conf.c (virDomainSmartcard): Convert between enum and string. (virDomainSmartcardDefParseXML, virDomainSmartcardDefFormat) (virDomainSmartcardDefFree, virDomainDeviceCcidAddressParseXML) (virDomainDefMaybeAddSmartcardController): New functions. (virDomainDefParseXML): Parse the new XML. (virDomainDefFormat): Convert back to XML. (virDomainDefFree): Clean up. (virDomainDeviceInfoIterate): Iterate over passthrough aliases. (virDomainController, virDomainDeviceAddress) (virDomainDeviceInfoParseXML, virDomainDeviceInfoFormat) (virDomainDefAddImplicitControllers): Support new values. * src/libvirt_private.syms (domain_conf.h): New exports. * cfg.mk (useless_free_options): List new function.
--- Notes: v2: first version of patch (v1 was xml proposal only) v3: add controller type='ccid' support, extra smartcard element support v4: remove host/dev, relax host-certificates/cert to be any string, define default host-certificates/database value v5: no change
True, no change since the previous acked version. ACK Jirka

Qemu smartcard/spicevmc support exists on branches (such as http://cgit.freedesktop.org/~alon/qemu/commit/?h=usb_ccid.v15&id=024a37b) but is not yet upstream. The added -help output matches a scratch build that will be close to the RHEL 6.1 qemu-kvm. * src/qemu/qemu_capabilities.h (QEMUD_CMD_FLAG_CCID_EMULATED) (QEMUD_CMD_FLAG_CCID_PASSTHRU, QEMUD_CMD_FLAG_CHARDEV_SPICEVMC): New flags. * src/qemu/qemu_capabilities.c (qemuCapsComputeCmdFlags) (qemuCapsParseDeviceStr): Check for smartcard capabilities. (qemuCapsExtractVersionInfo): Tweak comment. * tests/qemuhelptest.c (mymain): New test. * tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61: New file. * tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device: Likewise. --- Notes: v2: new patch v3: rebase to latest tree v4: no change v5: split check into two bits, to match upstream qemu configure flags; also check for spicevmc support, add a test from RHEL 6.1 scratch build src/qemu/qemu_capabilities.c | 17 +- src/qemu/qemu_capabilities.h | 3 + tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 | 229 ++++++++++++++++++++ tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device | 74 +++++++ tests/qemuhelptest.c | 43 ++++ 5 files changed, 361 insertions(+), 5 deletions(-) create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index fd46557..10f9d62 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -832,8 +832,11 @@ qemuCapsComputeCmdFlags(const char *help, flags |= QEMUD_CMD_FLAG_PCIDEVICE; if (strstr(help, "-mem-path")) flags |= QEMUD_CMD_FLAG_MEM_PATH; - if (strstr(help, "-chardev")) + if (strstr(help, "-chardev")) { flags |= QEMUD_CMD_FLAG_CHARDEV; + if (strstr(help, "-chardev spicevmc")) + flags |= QEMUD_CMD_FLAG_CHARDEV_SPICEVMC; + } if (strstr(help, "-balloon")) flags |= QEMUD_CMD_FLAG_BALLOON; if (strstr(help, "-device")) { @@ -1052,10 +1055,10 @@ qemuCapsExtractDeviceStr(const char *qemu, * the output format makes it possible to distinguish what we * need. With qemu 0.13.0 and later, unrecognized '-device * bogus,?' cause an error in isolation, but are silently ignored - * in combination with '-device ?'. Qemu 0.12.x doesn't + * in combination with '-device ?'. Upstream qemu 0.12.x doesn't * understand '-device name,?', and always exits with status 1 for * the simpler '-device ?', so this function is really only useful - * for parsing out features added in 0.13.0 or later. */ + * if -help includes "device driver,?". */ cmd = virCommandNewArgList(qemu, "-device", "?", "-device", "pci-assign,?", @@ -1084,6 +1087,10 @@ qemuCapsParseDeviceStr(const char *str, unsigned long long *flags) /* Which devices exist. */ if (strstr(str, "name \"hda-duplex\"")) *flags |= QEMUD_CMD_FLAG_HDA_DUPLEX; + if (strstr(str, "name \"ccid-card-emulated\"")) + *flags |= QEMUD_CMD_FLAG_CCID_EMULATED; + if (strstr(str, "name \"ccid-card-passthru\"")) + *flags |= QEMUD_CMD_FLAG_CCID_PASSTHRU; /* Features of given devices. */ if (strstr(str, "pci-assign.configfd")) @@ -1133,8 +1140,8 @@ int qemuCapsExtractVersionInfo(const char *qemu, &version, &is_kvm, &kvm_version) == -1) goto cleanup; - /* Only call qemuCapsExtractDeviceStr for qemu 0.13.0+, since it - * won't set any additional flags for qemu 0.12.x. */ + /* qemuCapsExtractDeviceStr will only set additional flags if qemu + * understands the 0.13.0+ notion of "-device driver,". */ if ((flags & QEMUD_CMD_FLAG_DEVICE) && strstr(help, "-device driver,?") && qemuCapsExtractDeviceStr(qemu, &flags) < 0) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index c2d09ca..9ee7639 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -88,6 +88,9 @@ enum qemuCapsFlags { QEMUD_CMD_FLAG_DRIVE_AIO = (1LL << 51), /* -drive aio= supported */ QEMUD_CMD_FLAG_PCI_MULTIBUS = (1LL << 52), /* bus=pci.0 vs bus=pci */ QEMUD_CMD_FLAG_PCI_BOOTINDEX = (1LL << 53), /* pci-assign.bootindex */ + QEMUD_CMD_FLAG_CCID_EMULATED = (1LL << 54), /* -device ccid-card-emulated */ + QEMUD_CMD_FLAG_CCID_PASSTHRU = (1LL << 55), /* -device ccid-card-passthru */ + QEMUD_CMD_FLAG_CHARDEV_SPICEVMC = (1LL << 56), /* -chardev spicevmc */ }; virCapsPtr qemuCapsInit(virCapsPtr old_caps); diff --git a/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 b/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 new file mode 100644 index 0000000..e95c6b1 --- /dev/null +++ b/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 @@ -0,0 +1,229 @@ +QEMU PC emulator version 0.12.1 (qemu-kvm-0.12.1.2), Copyright (c) 2003-2008 Fabrice Bellard + +WARNING: Direct use of qemu-kvm from the command line is unsupported. +WARNING: Only use via libvirt. +WARNING: Some options listed here may not be available in future releases. + +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-h or -help display this help and exit +-version display version information and exit +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-smp n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets] + set the number of CPUs to 'n' [default=1] + maxcpus= maximum number of total cpus, including + offline CPUs for hotplug etc. + cores= number of CPU cores on one socket + threads= number of threads on one CPU core + sockets= number of discrete sockets in the system +-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node] +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=writethrough|writeback|none|unsafe][,format=f] + [,serial=s][,addr=A][,id=name][,aio=threads|native] + [,readonly=on|off] + use 'file' as a drive image +-set group.id.arg=value + set <arg> parameter for item <id> of type <group> + i.e. -set drive.$id.file=/path/to/image +-global driver.property=value + set a global default for a driver property +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [order=drives][,once=drives][,menu=on|off] + 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n) +-snapshot write to temporary files instead of disk image files +-m megs set virtual RAM size to megs MB [default=128] +-k language use keyboard layout (for example 'fr' for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-device driver[,prop[=value][,...]] + add device (based on driver) + prop=value,... sets driver properties + use -device ? to print all possible drivers + use -device driver,? to print all possible properties +-name string1[,process=string2] set the name of the guest + string1 sets the window title and string2 the process name (on Linux) +-uuid %08x-%04x-%04x-%04x-%012x + specify machine UUID + +Display options: +-nographic disable graphical output and redirect serial I/Os to console +-spice <args> enable spice +-portrait rotate graphical output 90 deg left (only PXA LCD) +-vga [std|cirrus|vmware|qxl|xenfb|none] + select video card type +-full-screen start in full screen +-vnc display start a VNC server on display + +i386 target only: +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-no-fd-bootchk disable boot signature checking for floppy disks +-no-acpi disable ACPI +-balloon none disable balloon device +-balloon virtio[,addr=str] + enable virtio balloon device (default) +-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...] + ACPI table description +-smbios file=binary + Load SMBIOS entry from binary file +-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d] + Specify SMBIOS type 0 fields +-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str] + [,uuid=uuid][,sku=str][,family=str] + Specify SMBIOS type 1 fields + +Network options: +-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n] + [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f] + [,hostfwd=rule][,guestfwd=rule][,smb=dir[,smbserver=addr]] + connect the user mode network stack to VLAN 'n', configure its + DHCP server and enabled optional services +-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface + use 'sndbuf=nbytes' to limit the size of the send buffer; the + default of 'sndbuf=1048576' can be disabled using 'sndbuf=0' + use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag; use + vnet_hdr=on to make the lack of IFF_VNET_HDR support an error condition + use vhost=on to enable experimental in kernel accelerator + use 'vhostfd=h' to connect to an already opened vhost net device +-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net dump[,vlan=n][,file=f][,len=n] + dump traffic on vlan 'n' to file 'f' (max n bytes per packet) +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' +-netdev [user|tap|socket],id=str[,option][,option][,...] + +Character device options: +-chardev null,id=id +-chardev socket,id=id[,host=host],port=host[,to=to][,ipv4][,ipv6][,nodelay] + [,server][,nowait][,telnet] (tcp) +-chardev socket,id=id,path=path[,server][,nowait][,telnet] (unix) +-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr] + [,localport=localport][,ipv4][,ipv6] +-chardev msmouse,id=id +-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]] +-chardev file,id=id,path=path +-chardev pipe,id=id,path=path +-chardev pty,id=id +-chardev stdio,id=id +-chardev tty,id=id,path=path +-chardev parport,id=id,path=path +-chardev spicevmc,id=id,debug=debug,name=name + +Bluetooth(R) options: +-bt hci,null dumb bluetooth HCI - doesn't respond to commands +-bt hci,host[:id] + use host's HCI with the given name +-bt hci[,vlan=n] + emulate a standard HCI in virtual scatternet 'n' +-bt vhci[,vlan=n] + add host computer to virtual scatternet 'n' using VHCI +-bt device:dev[,vlan=n] + emulate a bluetooth device 'dev' in scatternet 'n' + +Linux/Multiboot boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-monitor dev redirect the monitor to char device 'dev' +-qmp dev like -monitor but opens in 'control' mode. +-mon chardev=[name][,mode=readline|control][,default] +-pidfile file write PID to 'file' +-singlestep always run in singlestep mode +-S freeze CPU at startup (use 'c' to start execution) +-gdb dev wait for gdb connection on 'dev' +-s shorthand for -gdb tcp::1234 +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] + force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-bios file set the filename for the BIOS +-enable-kvm enable KVM full virtualization support +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] + start right away with a saved state (loadvm in monitor) +-daemonize daemonize QEMU after initializing +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-rtc [base=utc|localtime|date][,clock=host|vm][,driftfix=none|slew] + set the RTC base and clock, enable drift fix for clock ticks +-icount [N|auto] + enable virtual instruction counter with 2^N clock ticks per + instruction +-watchdog i6300esb|ib700 + enable virtual hardware watchdog [default=none] +-watchdog-action reset|shutdown|poweroff|pause|debug|none + action when watchdog fires [default=reset] +-echr chr set terminal escape character instead of ctrl-a +-virtioconsole c + set virtio console +-show-cursor show cursor +-tb-size n set TB size +-incoming p prepare for incoming migration, listen on port p +-nodefaults don't create default devices. +-chroot dir Chroot to dir just before starting the VM. +-runas user Change to user id user just before starting the VM. +-nodefconfig + do not load default config files at startup +-readconfig <file> +-writeconfig <file> + read/write config file +-no-kvm disable KVM hardware virtualization +-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC +-no-kvm-pit disable KVM kernel mode PIT +-no-kvm-pit-reinjection disable KVM kernel mode PIT interrupt reinjection +-pcidevice host=bus:dev.func[,dma=none][,name=string] + expose a PCI device to the guest OS. + dma=none: don't perform any dma translations (default is to use an iommu) + 'string' is used in log output. +-enable-nesting enable support for running a VM inside the VM (AMD only) +-nvram FILE provide ia64 nvram contents +-tdf enable guest time drift compensation +-kvm-shadow-memory MEGABYTES + allocate MEGABYTES for kvm mmu shadowing +-mem-path FILE provide backing storage for guest RAM +-mem-prealloc preallocate guest memory (use with -mempath) +-redhat-disable-KSM disable KSM on guest physical memory + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. + +WARNING: Direct use of qemu-kvm from the command line is unsupported. +WARNING: Only use via libvirt. +WARNING: Some options listed here may not be available in future releases. + diff --git a/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device b/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device new file mode 100644 index 0000000..8a0e528 --- /dev/null +++ b/tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device @@ -0,0 +1,74 @@ +open /dev/kvm: No such file or directory +Could not initialize KVM, will disable KVM support +name "pci-bridge", bus PCI +name "virtio-balloon-pci", bus PCI +name "virtio-serial-pci", bus PCI, alias "virtio-serial" +name "virtio-net-pci", bus PCI +name "virtio-blk-pci", bus PCI +name "i82562", bus PCI +name "i82559er", bus PCI +name "i82559c", bus PCI +name "i82559b", bus PCI +name "i82559a", bus PCI +name "i82558b", bus PCI +name "i82558a", bus PCI +name "i82557c", bus PCI +name "i82557b", bus PCI +name "i82557a", bus PCI +name "i82551", bus PCI +name "i82550", bus PCI +name "pcnet", bus PCI +name "rtl8139", bus PCI +name "e1000", bus PCI, desc "Intel Gigabit Ethernet" +name "ide-drive", bus IDE +name "isa-ide", bus ISA +name "ES1370", bus PCI, desc "ENSONIQ AudioPCI ES1370" +name "AC97", bus PCI, desc "Intel 82801AA AC97 Audio" +name "intel-hda", bus PCI, desc "Intel HD Audio Controller" +name "hda-duplex", bus HDA, desc "HDA Audio Codec, duplex" +name "hda-output", bus HDA, desc "HDA Audio Codec, output-only" +name "VGA", bus PCI +name "SUNW,fdtwo", bus System +name "sysbus-fdc", bus System +name "isa-serial", bus ISA +name "cirrus-vga", bus PCI, desc "Cirrus CLGD 54xx VGA" +name "isa-parallel", bus ISA +name "piix4-usb-uhci", bus PCI +name "piix3-usb-uhci", bus PCI +name "vmware-svga", bus PCI +name "ib700", bus ISA +name "ne2k_isa", bus ISA +name "testdev", bus ISA +name "pci-assign", bus PCI, desc "pass through host pci devices to the guest" +name "qxl", bus PCI, desc "Spice QXL GPU (secondary)" +name "qxl-vga", bus PCI, desc "Spice QXL GPU (primary, vga compatible)" +name "smbus-eeprom", bus I2C +name "usb-hub", bus USB +name "usb-host", bus USB +name "usb-kbd", bus USB +name "usb-mouse", bus USB +name "usb-tablet", bus USB +name "usb-wacom-tablet", bus USB, desc "QEMU PenPartner Tablet" +name "usb-braille", bus USB +name "usb-serial", bus USB +name "usb-net", bus USB +name "usb-bt-dongle", bus USB +name "usb-ccid", bus USB, desc "CCID Rev 1.1 smartcard reader" +name "ccid-card-passthru", bus ccid-bus, desc "passthrough smartcard" +name "virtserialport", bus virtio-serial-bus +name "virtconsole", bus virtio-serial-bus +name "i6300esb", bus PCI +name "ne2k_pci", bus PCI +pci-assign.host=pci-hostaddr +pci-assign.iommu=uint32 +pci-assign.configfd=string +virtio-blk-pci.class=hex32 +virtio-blk-pci.drive=drive +virtio-blk-pci.logical_block_size=uint16 +virtio-blk-pci.physical_block_size=uint16 +virtio-blk-pci.min_io_size=uint16 +virtio-blk-pci.opt_io_size=uint32 +virtio-blk-pci.ioeventfd=on/off +virtio-blk-pci.vectors=uint32 +virtio-blk-pci.indirect_desc=on/off +virtio-blk-pci.scsi=on/off diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index e9579de..20ec08d 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -437,6 +437,49 @@ mymain(int argc, char **argv) QEMUD_CMD_FLAG_MIGRATE_QEMU_FD | QEMUD_CMD_FLAG_DRIVE_AIO, 13000, 1, 0); + DO_TEST("qemu-kvm-0.12.1.2-rhel61", + QEMUD_CMD_FLAG_VNC_COLON | + QEMUD_CMD_FLAG_NO_REBOOT | + QEMUD_CMD_FLAG_DRIVE | + QEMUD_CMD_FLAG_NAME | + QEMUD_CMD_FLAG_UUID | + QEMUD_CMD_FLAG_VNET_HDR | + QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP | + QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC | + QEMUD_CMD_FLAG_DRIVE_CACHE_V2 | + QEMUD_CMD_FLAG_KVM | + QEMUD_CMD_FLAG_DRIVE_FORMAT | + QEMUD_CMD_FLAG_DRIVE_SERIAL | + QEMUD_CMD_FLAG_DRIVE_READONLY | + QEMUD_CMD_FLAG_VGA | + QEMUD_CMD_FLAG_0_10 | + QEMUD_CMD_FLAG_PCIDEVICE | + QEMUD_CMD_FLAG_MEM_PATH | + QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX | + QEMUD_CMD_FLAG_CHARDEV | + QEMUD_CMD_FLAG_ENABLE_KVM | + QEMUD_CMD_FLAG_BALLOON | + QEMUD_CMD_FLAG_DEVICE | + QEMUD_CMD_FLAG_SMP_TOPOLOGY | + QEMUD_CMD_FLAG_RTC | + QEMUD_CMD_FLAG_VNET_HOST | + QEMUD_CMD_FLAG_NO_KVM_PIT | + QEMUD_CMD_FLAG_TDF | + QEMUD_CMD_FLAG_PCI_CONFIGFD | + QEMUD_CMD_FLAG_NODEFCONFIG | + QEMUD_CMD_FLAG_BOOT_MENU | + QEMUD_CMD_FLAG_NESTING | + QEMUD_CMD_FLAG_NAME_PROCESS | + QEMUD_CMD_FLAG_SMBIOS_TYPE | + QEMUD_CMD_FLAG_VGA_QXL | + QEMUD_CMD_FLAG_SPICE | + QEMUD_CMD_FLAG_VGA_NONE | + QEMUD_CMD_FLAG_MIGRATE_QEMU_FD | + QEMUD_CMD_FLAG_HDA_DUPLEX | + QEMUD_CMD_FLAG_DRIVE_AIO | + QEMUD_CMD_FLAG_CCID_PASSTHRU | + QEMUD_CMD_FLAG_CHARDEV_SPICEVMC, + 12001, 1, 0); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.4

On Thu, Feb 03, 2011 at 21:01:14 -0700, Eric Blake wrote:
Qemu smartcard/spicevmc support exists on branches (such as http://cgit.freedesktop.org/~alon/qemu/commit/?h=usb_ccid.v15&id=024a37b) but is not yet upstream. The added -help output matches a scratch build that will be close to the RHEL 6.1 qemu-kvm.
* src/qemu/qemu_capabilities.h (QEMUD_CMD_FLAG_CCID_EMULATED) (QEMUD_CMD_FLAG_CCID_PASSTHRU, QEMUD_CMD_FLAG_CHARDEV_SPICEVMC): New flags. * src/qemu/qemu_capabilities.c (qemuCapsComputeCmdFlags) (qemuCapsParseDeviceStr): Check for smartcard capabilities. (qemuCapsExtractVersionInfo): Tweak comment. * tests/qemuhelptest.c (mymain): New test. * tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61: New file. * tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device: Likewise.
--- Notes: v2: new patch v3: rebase to latest tree v4: no change v5: split check into two bits, to match upstream qemu configure flags; also check for spicevmc support, add a test from RHEL 6.1 scratch build src/qemu/qemu_capabilities.c | 17 +- src/qemu/qemu_capabilities.h | 3 + tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 | 229 ++++++++++++++++++++ tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device | 74 +++++++ tests/qemuhelptest.c | 43 ++++ 5 files changed, 361 insertions(+), 5 deletions(-) create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61 create mode 100644 tests/qemuhelpdata/qemu-kvm-0.12.1.2-rhel61-device
ACK Jirka

* src/security/security_selinux.c (SELinuxRestoreSecuritySmartcardCallback) (SELinuxSetSecuritySmartcardCallback): New helper functions. (SELinuxRestoreSecurityAllLabel, SELinuxSetSecurityAllLabel): Use them. --- Notes: v3: new patch v4: match xml changes v5: no change src/security/security_selinux.c | 76 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0 deletions(-) diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 24609bc..587b3b5 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -809,6 +809,38 @@ SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int +SELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainSmartcardDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + const char *database; + + switch (dev->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + database = dev->data.cert.database; + if (!database) + database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE; + return SELinuxRestoreSecurityFileLabel(database); + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + return SELinuxRestoreSecurityChardevLabel(vm, &dev->data.passthru); + + default: + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown smartcard type %d"), + dev->type); + return -1; + } + + return 0; +} + + +static int SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainObjPtr vm, int migrated ATTRIBUTE_UNUSED) @@ -842,6 +874,12 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, vm) < 0) rc = -1; + if (virDomainSmartcardDefForeach(vm->def, + false, + SELinuxRestoreSecuritySmartcardCallback, + vm) < 0) + rc = -1; + if (vm->def->os.kernel && SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0) rc = -1; @@ -1074,6 +1112,38 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, static int +SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainSmartcardDefPtr dev, + void *opaque) +{ + virDomainObjPtr vm = opaque; + const char *database; + + switch (dev->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + database = dev->data.cert.database; + if (!database) + database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE; + return SELinuxSetFilecon(database, default_content_context); + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + return SELinuxSetSecurityChardevLabel(vm, &dev->data.passthru); + + default: + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown smartcard type %d"), + dev->type); + return -1; + } + + return 0; +} + + +static int SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainObjPtr vm, const char *stdin_path) @@ -1108,6 +1178,12 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, vm) < 0) return -1; + if (virDomainSmartcardDefForeach(vm->def, + true, + SELinuxSetSecuritySmartcardCallback, + vm) < 0) + return -1; + if (vm->def->os.kernel && SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0) return -1; -- 1.7.4

On Thu, Feb 03, 2011 at 21:01:15 -0700, Eric Blake wrote:
* src/security/security_selinux.c (SELinuxRestoreSecuritySmartcardCallback) (SELinuxSetSecuritySmartcardCallback): New helper functions. (SELinuxRestoreSecurityAllLabel, SELinuxSetSecurityAllLabel): Use them.
--- Notes: v3: new patch v4: match xml changes v5: no change src/security/security_selinux.c | 76 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0 deletions(-)
ACK, exactly the same as what was acked previously. Jirka

* src/qemu/qemu_command.c (qemuBuildCommandLine): Emit smartcard options. (qemuAssignDeviceAliases): Assign an alias for smartcards. (qemuBuildControllerDevStr): Manage the usb-ccid controller. * tests/qemuxml2argvtest.c (mymain): Add new tests. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args: New file. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough.args: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args: Likewise. --- Notes: v2: new patch v3: reject ',' in cert name, alias for host smartcard use, output usb-ccid controller separate from rest of command line, enforce at most one smartcard for now v4: update to new XML, add comment, rebase on recent changes to testsuite v5: avoid rounding in tests, adjust to new capability names src/qemu/qemu_command.c | 116 +++++++++++++++++++- .../qemuxml2argv-smartcard-controller.args | 7 + .../qemuxml2argv-smartcard-host-certificates.args | 8 ++ .../qemuxml2argv-smartcard-host.args | 7 + .../qemuxml2argv-smartcard-passthrough-tcp.args | 8 ++ tests/qemuxml2argvtest.c | 13 ++ 6 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f57c937..40d92f4 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -638,6 +638,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags) if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0) goto no_memory; } + for (i = 0; i < def->nsmartcards ; i++) { + if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%d", i) < 0) + goto no_memory; + } if (def->console) { if (virAsprintf(&def->console->info.alias, "console%d", i) < 0) goto no_memory; @@ -1002,8 +1006,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs) /* Disk controllers (SCSI only for now) */ for (i = 0; i < def->ncontrollers ; i++) { - /* FDC lives behind the ISA bridge */ - if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC) + /* FDC lives behind the ISA bridge; CCID is a usb device */ + if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC || + def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_CCID) continue; /* First IDE controller lives on the PIIX3 at slot=1, function=1, @@ -1511,6 +1516,10 @@ qemuBuildControllerDevStr(virDomainControllerDefPtr def, } break; + case VIR_DOMAIN_CONTROLLER_TYPE_CCID: + virBufferVSprintf(&buf, "usb-ccid,id=ccid%d", def->idx); + break; + /* We always get an IDE controller, whether we want it or not. */ case VIR_DOMAIN_CONTROLLER_TYPE_IDE: default: @@ -3434,6 +3443,109 @@ qemuBuildCommandLine(virConnectPtr conn, } } + if (def->nsmartcards) { + /* -device usb-ccid was already emitted along with other + * controllers. For now, qemu handles only one smartcard. */ + virDomainSmartcardDefPtr smartcard = def->smartcards[0]; + char *devstr; + virBuffer opt = VIR_BUFFER_INITIALIZER; + int j; + const char *database; + + if (def->nsmartcards > 1 || + smartcard->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID || + smartcard->info.addr.ccid.controller != 0 || + smartcard->info.addr.ccid.slot != 0) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU binary lacks multiple smartcard " + "support")); + virBufferFreeAndReset(&opt); + goto error; + } + + switch (smartcard->type) { + case VIR_DOMAIN_SMARTCARD_TYPE_HOST: + if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) || + !(qemuCmdFlags & QEMUD_CMD_FLAG_CCID_EMULATED)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU binary lacks smartcard host " + "mode support")); + goto error; + } + + virBufferAddLit(&opt, "ccid-card-emulated,backend=nss-emulated"); + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES: + if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) || + !(qemuCmdFlags & QEMUD_CMD_FLAG_CCID_EMULATED)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU binary lacks smartcard host " + "mode support")); + goto error; + } + + virBufferAddLit(&opt, "ccid-card-emulated,backend=certificates"); + for (j = 0; j < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; j++) { + if (strchr(smartcard->data.cert.file[j], ',')) { + virBufferFreeAndReset(&opt); + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid certificate name: %s"), + smartcard->data.cert.file[j]); + goto error; + } + virBufferVSprintf(&opt, ",cert%d=%s", j + 1, + smartcard->data.cert.file[j]); + } + if (smartcard->data.cert.database) { + if (strchr(smartcard->data.cert.database, ',')) { + virBufferFreeAndReset(&opt); + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid database name: %s"), + smartcard->data.cert.database); + goto error; + } + database = smartcard->data.cert.database; + } else { + database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE; + } + virBufferVSprintf(&opt, ",database=%s", database); + break; + + case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH: + if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) || + !(qemuCmdFlags & QEMUD_CMD_FLAG_CCID_PASSTHRU)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU binary lacks smartcard " + "passthrough mode support")); + goto error; + } + + virCommandAddArg(cmd, "-chardev"); + if (!(devstr = qemuBuildChrChardevStr(&smartcard->data.passthru, + smartcard->info.alias))) { + virBufferFreeAndReset(&opt); + goto error; + } + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + + virBufferVSprintf(&opt, "ccid-card-passthru,chardev=char%s", + smartcard->info.alias); + break; + + default: + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected smartcard type %d"), + smartcard->type); + virBufferFreeAndReset(&opt); + goto error; + } + virCommandAddArg(cmd, "-device"); + virBufferVSprintf(&opt, ",id=%s,bus=ccid0.0", smartcard->info.alias); + virCommandAddArgBuffer(cmd, &opt); + } + if (!def->nserials) { /* If we have -device, then we set -nodefault already */ if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args new file mode 100644 index 0000000..a0ee85e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args @@ -0,0 +1,7 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \ +socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \ +chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \ +usb-ccid,id=ccid0 -device \ +ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0 -usb \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args new file mode 100644 index 0000000..46bf38a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \ +socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \ +chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \ +usb-ccid,id=ccid0 -device \ +ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3\ +,database=/etc/pki/nssdb,id=smartcard0,bus=ccid0.0 -usb -device \ +virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args new file mode 100644 index 0000000..a0ee85e --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args @@ -0,0 +1,7 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \ +socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \ +chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \ +usb-ccid,id=ccid0 -device \ +ccid-card-emulated,backend=nss-emulated,id=smartcard0,bus=ccid0.0 -usb \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args new file mode 100644 index 0000000..159ca87 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -chardev \ +socket,id=charmonitor,path=/tmp/test-monitor,server,nowait -mon \ +chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -device \ +usb-ccid,id=ccid0 -chardev \ +socket,id=charsmartcard0,host=127.0.0.1,port=2001,server,nowait \ +-device ccid-card-passthru,chardev=charsmartcard0,id=smartcard0,bus=ccid0.0 \ +-usb -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 0a39791..0b4bfeb 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -408,6 +408,19 @@ mymain(int argc, char **argv) DO_TEST("console-virtio", QEMUD_CMD_FLAG_DEVICE | QEMUD_CMD_FLAG_NODEFCONFIG, false); + DO_TEST("smartcard-host", + QEMUD_CMD_FLAG_CHARDEV | QEMUD_CMD_FLAG_DEVICE | + QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_CCID_EMULATED, false); + DO_TEST("smartcard-host-certificates", + QEMUD_CMD_FLAG_CHARDEV | QEMUD_CMD_FLAG_DEVICE | + QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_CCID_EMULATED, false); + DO_TEST("smartcard-passthrough-tcp", + QEMUD_CMD_FLAG_CHARDEV | QEMUD_CMD_FLAG_DEVICE | + QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_CCID_PASSTHRU, false); + DO_TEST("smartcard-controller", + QEMUD_CMD_FLAG_CHARDEV | QEMUD_CMD_FLAG_DEVICE | + QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_CCID_EMULATED, false); + DO_TEST("smbios", QEMUD_CMD_FLAG_SMBIOS_TYPE, false); DO_TEST("watchdog", 0, false); -- 1.7.4

On Thu, Feb 03, 2011 at 21:01:16 -0700, Eric Blake wrote:
* src/qemu/qemu_command.c (qemuBuildCommandLine): Emit smartcard options. (qemuAssignDeviceAliases): Assign an alias for smartcards. (qemuBuildControllerDevStr): Manage the usb-ccid controller. * tests/qemuxml2argvtest.c (mymain): Add new tests. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args: New file. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough.args: Likewise. * tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args: Likewise.
--- Notes: v2: new patch v3: reject ',' in cert name, alias for host smartcard use, output usb-ccid controller separate from rest of command line, enforce at most one smartcard for now v4: update to new XML, add comment, rebase on recent changes to testsuite v5: avoid rounding in tests, adjust to new capability names src/qemu/qemu_command.c | 116 +++++++++++++++++++- .../qemuxml2argv-smartcard-controller.args | 7 + .../qemuxml2argv-smartcard-host-certificates.args | 8 ++ .../qemuxml2argv-smartcard-host.args | 7 + .../qemuxml2argv-smartcard-passthrough-tcp.args | 8 ++ tests/qemuxml2argvtest.c | 13 ++ 6 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-controller.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host-certificates.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-host.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smartcard-passthrough-tcp.args
ACK Jirka
participants (2)
-
Eric Blake
-
Jiri Denemark