[libvirt] [RFC PATCHv2 4/5] smartcard: add domain conf support

Eric Blake eblake at redhat.com
Fri Jan 14 00:34:36 UTC 2011


* 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




More information about the libvir-list mailing list