提交 c1be1a2e 编写于 作者: E Eric Blake

smartcard: add domain conf support

* 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.
上级 ffdf478b
......@@ -100,6 +100,7 @@ useless_free_options = \
--name=virDomainInputDefFree \
--name=virDomainNetDefFree \
--name=virDomainObjFree \
--name=virDomainSmartcardDefFree \
--name=virDomainSnapshotDefFree \
--name=virDomainSnapshotObjFree \
--name=virDomainSoundDefFree \
......
......@@ -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;
}
......@@ -6740,6 +7007,56 @@ virDomainChrDefFormat(virBufferPtr buf,
return ret;
}
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,
......@@ -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,
......
......@@ -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)
......
......@@ -283,6 +283,10 @@ virDomainRemoveInactive;
virDomainSaveConfig;
virDomainSaveStatus;
virDomainSaveXML;
virDomainSmartcardDefForeach;
virDomainSmartcardDefFree;
virDomainSmartcardTypeFromString;
virDomainSmartcardTypeToString;
virDomainSnapshotAssignDef;
virDomainSnapshotDefFormat;
virDomainSnapshotDefFree;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册