* src/conf/domain_conf.h (virDomainSmartcardType): New enum.
(virDomainSmartcardDef): New struct.
(virDomainDef): Include smartcards.
(virDomainSmartcardDefIterator): New typedef.
(virDomainSmartcardDefFree, virDomainSmartcardDefForeach): New
prototypes.
* src/conf/domain_conf.c (virDomainSmartcard): Convert between
enum and string.
(virDomainSmartcardDefParseXML, virDomainSmartcardDefFormat)
(virDomainSmartcardDefFree): New functions.
(virDomainDefParseXML): Parse the new XML.
(virDomainDefFormat): Convert back to XML.
(virDomainDefFree): Clean up.
(virDomainDeviceInfoIterate): Iterate over passthrough aliases.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): List new function.
---
cfg.mk | 1 +
src/conf/domain_conf.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 40 ++++++++-
src/libvirt_private.syms | 4 +
4 files changed, 268 insertions(+), 1 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index d4c791a..2bf8fd0 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -99,6 +99,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 674eddb..a567136 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -221,6 +221,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",
@@ -680,6 +685,32 @@ 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_CERTIFICATES:
+ for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
+ VIR_FREE(def->data.cert.file[i]);
+ break;
+
+ case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
+ virDomainChrSourceDefClear(&def->data.passthru);
+ break;
+
+ case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
+ default:
+ break;
+ }
+
+ virDomainDeviceInfoClear(&def->info);
+
+ VIR_FREE(def);
+}
+
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
if (!def)
@@ -821,6 +852,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);
@@ -1180,6 +1215,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;
@@ -3067,6 +3105,101 @@ 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;
+ for (cur = node->children;
+ cur && cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "certificate");
+ cur = cur->next) {
+ def->data.cert.file[i++] = (char *)xmlNodeGetContent(cur);
+ }
+ if (i != 3 || cur->next) {
+ 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)
+ def->data.passthru.type = VIR_DOMAIN_CHR_TYPE_TCP;
+ else 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;
+ i = virDomainChrSourceDefParseXML(&def->data.passthru, cur);
+ if (i < 0)
+ goto error;
+ if (i) {
+ if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
+ goto error;
+ /* An active domain may have an alias, but no address. */
+ if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("smartcard should not have an "
+ "<address> element"));
+ goto error;
+ }
+ }
+ break;
+
+ default:
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unknown smartcard mode"));
+ 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,
@@ -5079,6 +5212,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,
@@ -6535,6 +6688,50 @@ 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:
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+
+ 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]);
+ break;
+
+ case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
+ if (virDomainChrSourceDefFormat(buf, &def->data.passthru, false,
+ flags) < 0)
+ return -1;
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+ break;
+
+ default:
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected smartcard type %d"), def->type);
+ return -1;
+ }
+ virBufferAddLit(buf, " </smartcard>\n");
+ return 0;
+}
+
+static int
virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundDefPtr def,
int flags)
@@ -7331,6 +7528,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;
@@ -8409,6 +8610,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 24b82b3..25f1ed0 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -437,6 +437,31 @@ 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
+
+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];
+ } cert; /* host-certificates */
+ virDomainChrSourceDef passthru; /* passthrough */
+ } data;
+
+ virDomainDeviceInfo info;
+};
+
enum virDomainInputType {
VIR_DOMAIN_INPUT_TYPE_MOUSE,
VIR_DOMAIN_INPUT_TYPE_TABLET,
@@ -1005,6 +1030,9 @@ struct _virDomainDef {
int nhostdevs;
virDomainHostdevDefPtr *hostdevs;
+ int nsmartcards;
+ virDomainSmartcardDefPtr *smartcards;
+
int nserials;
virDomainChrDefPtr *serials;
@@ -1083,6 +1111,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);
@@ -1230,6 +1259,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);
@@ -1239,7 +1277,6 @@ int virDomainChrDefForeach(virDomainDefPtr def,
virDomainChrDefIterator iter,
void *opaque);
-
typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
const char *path,
size_t depth,
@@ -1276,6 +1313,7 @@ VIR_ENUM_DECL(virDomainNet)
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 2ce4bed..7e4dfca 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -280,6 +280,10 @@ virDomainRemoveInactive;
virDomainSaveConfig;
virDomainSaveStatus;
virDomainSaveXML;
+virDomainSmartcardDefForeach;
+virDomainSmartcardDefFree;
+virDomainSmartcardTypeFromString;
+virDomainSmartcardTypeToString;
virDomainSnapshotAssignDef;
virDomainSnapshotDefFormat;
virDomainSnapshotDefFree;
--
1.7.3.4