* 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 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 b1cc6c8..8575cf6 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, @@ -5250,6 +5455,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, @@ -5927,6 +6152,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 @@ -5953,6 +6217,9 @@ int virDomainDefAddImplicitControllers(virDomainDefPtr def) if (virDomainDefMaybeAddVirtioSerialController(def) < 0) return -1; + if (virDomainDefMaybeAddSmartcardController(def) < 0) + return -1; + return 0; } @@ -6732,6 +6999,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) @@ -7534,6 +7851,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; @@ -8612,6 +8933,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 871fa9a..0f43d9d 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, @@ -1031,6 +1068,9 @@ struct _virDomainDef { int nhostdevs; virDomainHostdevDefPtr *hostdevs; + int nsmartcards; + virDomainSmartcardDefPtr *smartcards; + int nserials; virDomainChrDefPtr *serials; @@ -1109,6 +1149,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); @@ -1257,6 +1298,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); @@ -1266,7 +1316,6 @@ int virDomainChrDefForeach(virDomainDefPtr def, virDomainChrDefIterator iter, void *opaque); - typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk, const char *path, size_t depth, @@ -1305,6 +1354,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.3.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list