[libvirt] [PATCH 06/12] Define basic internal API for access control

Daniel P. Berrange berrange at redhat.com
Wed May 2 11:44:13 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

---
 include/libvirt/virterror.h       |    3 +
 po/POTFILES.in                    |    1 +
 src/Makefile.am                   |   16 +
 src/access/apis.txt               |  577 +++++++++++++++++++++++++++++++++++++
 src/access/viraccessdriver.h      |   51 ++++
 src/access/viraccessdrivernop.c   |   44 +++
 src/access/viraccessdrivernop.h   |   28 ++
 src/access/viraccessdriverstack.c |  105 +++++++
 src/access/viraccessdriverstack.h |   32 ++
 src/access/viraccessmanager.c     |  338 ++++++++++++++++++++++
 src/access/viraccessmanager.h     |   56 ++++
 src/access/viraccessperm.c        |   37 +++
 src/access/viraccessperm.h        |   73 +++++
 src/libvirt_private.syms          |   21 ++
 src/util/virterror.c              |    9 +
 15 files changed, 1391 insertions(+)
 create mode 100644 src/access/apis.txt
 create mode 100644 src/access/viraccessdriver.h
 create mode 100644 src/access/viraccessdrivernop.c
 create mode 100644 src/access/viraccessdrivernop.h
 create mode 100644 src/access/viraccessdriverstack.c
 create mode 100644 src/access/viraccessdriverstack.h
 create mode 100644 src/access/viraccessmanager.c
 create mode 100644 src/access/viraccessmanager.h
 create mode 100644 src/access/viraccessperm.c
 create mode 100644 src/access/viraccessperm.h

diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index e44390e..1daba04 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -88,6 +88,7 @@ typedef enum {
     VIR_FROM_URI = 45,          /* Error from URI handling */
     VIR_FROM_AUTH = 46,         /* Error from auth handling */
     VIR_FROM_DBUS = 47,         /* Error from DBus */
+    VIR_FROM_ACCESS = 48,       /* Error from access control manager */
 } virErrorDomain;
 
 
@@ -252,6 +253,8 @@ typedef enum {
     VIR_ERR_OVERFLOW = 82,              /* integer overflow */
     VIR_ERR_BLOCK_COPY_ACTIVE = 83,     /* action prevented by block copy job */
     VIR_ERR_INVALID_IDENTITY = 84,      /* Invalid identity pointer */
+    VIR_ERR_ACCESS_DENIED = 85,         /* operation on the object/resource
+                                           was denied */
 } virErrorNumber;
 
 /**
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4ea544b..f898887 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ daemon/remote_dispatch.h
 daemon/stream.c
 gnulib/lib/gai_strerror.c
 gnulib/lib/regcomp.c
+src/access/viraccessmanager.c
 src/conf/cpu_conf.c
 src/conf/domain_conf.c
 src/conf/domain_event.c
diff --git a/src/Makefile.am b/src/Makefile.am
index e48dfa5..0293562 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -531,6 +531,13 @@ SECURITY_DRIVER_APPARMOR_SOURCES =				\
 		security/security_apparmor.h security/security_apparmor.c
 
 
+ACCESS_DRIVER_SOURCES = \
+		access/viraccessperm.h access/viraccessperm.c \
+		access/viraccessmanager.h access/viraccessmanager.c \
+		access/viraccessdriver.h \
+		access/viraccessdrivernop.h access/viraccessdrivernop.c \
+		access/viraccessdriverstack.h access/viraccessdriverstack.c
+
 NODE_DEVICE_DRIVER_SOURCES =					\
 		node_device/node_device_driver.c \
 		node_device/node_device_driver.h \
@@ -1115,6 +1122,15 @@ libvirt_driver_security_la_CFLAGS += $(APPARMOR_CFLAGS)
 libvirt_driver_security_la_LIBADD += $(APPARMOR_LIBS)
 endif
 
+libvirt_driver_access_la_SOURCES = $(ACCESS_DRIVER_SOURCES)
+noinst_LTLIBRARIES += libvirt_driver_access.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_access.la
+libvirt_driver_access_la_CFLAGS = \
+		-I at top_srcdir@/src/conf $(AM_CFLAGS)
+libvirt_driver_access_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_access_la_LIBADD =
+
+
 # Add all conditional sources just in case...
 EXTRA_DIST +=							\
 		$(TEST_DRIVER_SOURCES)				\
diff --git a/src/access/apis.txt b/src/access/apis.txt
new file mode 100644
index 0000000..16cc49c
--- /dev/null
+++ b/src/access/apis.txt
@@ -0,0 +1,577 @@
+
+Non-driver based APIs
+
+
+virConnCopyLastError:
+virResetError:
+virResetLastError:
+virSaveLastError:
+virSetErrorFunc:
+virConnGetLastError:
+virConnResetLastError:
+virConnSetErrorFunc:
+virCopyLastError:
+virDefaultErrorFunc:
+virFreeError:
+virGetLastError:
+
+virInitialize:
+virConnectClose:
+virConnectGetLibVersion:
+virGetVersion:
+virConnectGetVersion:
+virConnectGetType:
+virConnectGetURI:
+
+
+virConnectRef:
+virDomainRef:
+virInterfaceRef:
+virNetworkRef:
+virNodeDeviceRef:
+virNWFilterRef:
+virSecretRef:
+virStoragePoolRef:
+virStorageVolRef:
+virStreamRef:
+
+virIdentityFree:
+virDomainFree:
+virDomainSnapshotFree:
+virInterfaceFree:
+virNetworkFree:
+virNodeDeviceFree:
+virNWFilterFree:
+virSecretFree:
+virStoragePoolFree:
+virStorageVolFree:
+virStreamFree:
+
+virDomainGetConnect:
+virInterfaceGetConnect:
+virDomainSnapshotGetConnect:
+virNetworkGetConnect:
+virSecretGetConnect:
+virStoragePoolGetConnect:
+virStorageVolGetConnect:
+virDomainSnapshotGetDomain:
+
+virEventAddHandle:
+virEventAddTimeout:
+virEventRegisterDefaultImpl:
+virEventRegisterImpl:
+virEventRemoveHandle:
+virEventRemoveTimeout:
+virEventRunDefaultImpl:
+virEventUpdateHandle:
+virEventUpdateTimeout:
+
+
+virConnectBaselineCPU:
+
+ - No state access
+
+virConnectCompareCPU:
+
+ - Access host CPU
+
+virConnectGetCapabilities:
+
+ - Access host CPU, emulators, NUMA
+
+virConnectGetHostname:
+
+ - hostname resolve
+
+virConnectGetIdentity:
+
+ - No state
+
+virConnectGetMaxVcpus:
+
+ - Hypercall
+
+virConnectGetSysinfo:
+
+ - Sysfs / dmidecode ? (cached from capabilities)
+
+virConnectIsAlive:
+
+ - Driver check
+
+virConnectIsEncrypted:
+virConnectIsSecure:
+
+ - Property lookup
+
+virConnectOpen:
+virConnectOpenAuth:
+virConnectOpenReadOnly:
+
+ - RPC layer
+
+virConnectSetIdentity:
+
+ - RPC layer
+
+virConnectSetKeepAlive:
+
+ - RPC layer
+
+virNodeGetCellsFreeMemory:
+
+ - NUMA props
+
+virNodeGetCPUStats:
+
+ - Cgroups
+
+virNodeGetFreeMemory:
+
+ - NUMA props
+
+virNodeGetInfo:
+
+ - NUMA / sysfs
+
+virNodeGetMemoryStats:
+
+ - CGroups
+
+virNodeGetSecurityModel:
+
+ - Capabilities
+
+virNodeSuspendForDuration:
+
+ - PM utils invoke
+
+
+
+virConnectNumOfDefinedDomains:
+virConnectNumOfDomains:
+virConnectListDefinedDomains:
+virConnectListDomains:
+
+ - 'search_domains' on libvirtd
+ - 'getattr' on each domain
+
+
+virConnectDomainEventDeregister:
+virConnectDomainEventDeregisterAny:
+virConnectDomainEventRegister:
+virConnectDomainEventRegisterAny:
+
+ - 'monitor' on domain
+
+virConnectDomainXMLFromNative:
+virConnectDomainXMLToNative:
+
+ - 'domain_xml' on libvirtd
+
+virDomainAbortJob:
+
+ - 'abort_job'
+
+virDomainBlockJobAbort:
+
+ - 'abort_block_job'
+
+virDomainBlockJobSetSpeed:
+
+ - 'setattr_block_job'
+
+virDomainBlockPeek:
+
+ - 'block_peek'
+
+virDomainBlockPull:
+
+ - 'block_pull'
+ - 'create_block_job'
+
+virDomainBlockResize:
+
+ - 'block_resize'
+
+virDomainBlockStats:
+virDomainBlockStatsFlags:
+
+ - 'read'
+
+virDomainCoreDump:
+
+ - 'coredump'
+
+virDomainCreate:
+virDomainCreateLinux:
+virDomainCreateWithFlags:
+
+ - 'start'
+
+virDomainCreateXML:
+
+ - 'start' + 'write'
+
+virDomainDefineXML:
+
+ - 'save'  + 'write'
+
+virDomainDestroy:
+virDomainDestroyFlags:
+
+ - 'stop'
+
+
+virDomainGetID:
+virDomainGetName:
+virDomainGetUUID:
+virDomainGetUUIDString:
+virDomainLookupByUUIDString:
+
+ - Outside driver
+
+virDomainLookupByID:
+virDomainLookupByName:
+virDomainLookupByUUID:
+
+ - getattr
+
+virDomainGetAutostart:
+virDomainGetBlkioParameters:
+virDomainGetBlockInfo:
+virDomainGetBlockIoTune:
+virDomainGetBlockJobInfo:
+virDomainGetControlInfo:
+virDomainGetInfo:
+virDomainGetInterfaceParameters:
+virDomainGetJobInfo:
+virDomainGetMaxMemory:
+virDomainGetMaxVcpus:
+virDomainGetMemoryParameters:
+virDomainGetNumaParameters:
+virDomainGetOSType:
+virDomainGetSchedulerParameters:
+virDomainGetSchedulerParametersFlags:
+virDomainGetSchedulerType:
+virDomainGetSecurityLabel:
+virDomainGetState:
+virDomainGetVcpuPinInfo:
+virDomainGetVcpus:
+virDomainGetVcpusFlags:
+virDomainGetXMLDesc:
+virDomainHasCurrentSnapshot:
+virDomainHasManagedSaveImage:
+virDomainInterfaceStats:
+virDomainIsActive:
+virDomainIsPersistent:
+virDomainIsUpdated:
+virDomainMemoryStats:
+
+ - 'read'
+
+virDomainInjectNMI:
+
+ - inject_nmi
+
+
+virDomainManagedSave:
+
+ - save_create
+
+virDomainManagedSaveRemove:
+
+ - save_delete
+
+virDomainMemoryPeek:
+
+ - memory_peek
+
+
+virDomainMigrate:
+virDomainMigrate2:
+virDomainMigrateGetMaxSpeed:
+virDomainMigrateSetMaxDowntime:
+virDomainMigrateSetMaxSpeed:
+virDomainMigrateToURI:
+virDomainMigrateToURI2:
+
+ - migrate
+
+virDomainOpenConsole:
+
+ - open_console
+
+virDomainOpenGraphics:
+
+ - open_graphics
+
+virDomainPinVcpu:
+virDomainPinVcpuFlags:
+
+ - write ?
+
+virDomainReboot:
+
+ - reboot
+
+virDomainReset:
+
+ - reset
+
+virDomainRestore:
+virDomainRestoreFlags:
+
+ - restore
+ - start
+
+virDomainResume:
+
+ - resume
+
+virDomainRevertToSnapshot:
+
+ - snapshot_revert
+
+virDomainSave:
+virDomainSaveFlags:
+
+ - stop
+ - save
+
+virDomainSaveImageDefineXML:
+
+ - save_write  (setattr ?)
+
+virDomainSaveImageGetXMLDesc:
+
+ - save_getattr
+
+
+virDomainScreenshot:
+
+ - screenshot
+
+virDomainSendKey:
+
+ - sendkey
+
+virDomainSetAutostart:
+virDomainSetBlkioParameters:
+virDomainSetBlockIoTune:
+virDomainSetInterfaceParameters:
+virDomainSetMaxMemory:
+virDomainSetMemory:
+virDomainSetMemoryFlags:
+virDomainSetMemoryParameters:
+virDomainSetNumaParameters:
+virDomainSetSchedulerParameters:
+virDomainSetSchedulerParametersFlags:
+virDomainSetVcpus:
+virDomainSetVcpusFlags:
+virDomainAttachDevice:
+virDomainAttachDeviceFlags:
+virDomainUpdateDeviceFlags:
+virDomainDetachDevice:
+virDomainDetachDeviceFlags:
+
+
+ - write (+ possible save)
+
+virDomainShutdown:
+
+ - shutdown
+
+virDomainSnapshotCreateXML:
+
+ - snapshot_create
+
+virDomainSnapshotCurrent:
+
+ - snapshot_getattr (or getattr ?)
+
+virDomainSnapshotDelete:
+
+ - snapshot_delete
+
+virDomainSnapshotGetName:
+virDomainSnapshotGetParent:
+virDomainSnapshotGetXMLDesc:
+
+ - snapshot_getattr
+
+virDomainSnapshotListChildrenNames:
+virDomainSnapshotListNames:
+
+ - snapshot_search
+ - Filter on snapshot_getattr
+
+virDomainSnapshotLookupByName:
+
+ - snapshot_getattr
+
+virDomainSnapshotNum:
+virDomainSnapshotNumChildren:
+
+ - snapshot_search
+ - Filter on snapshot_getattr
+
+virDomainSuspend:
+
+ - suspend
+
+virDomainUndefine:
+virDomainUndefineFlags:
+
+ - delete
+
+
+
+virConnectNumOfDefinedInterfaces:
+virConnectNumOfInterfaces:
+virConnectListDefinedInterfaces:
+virConnectListInterfaces:
+virInterfaceChangeBegin:
+virInterfaceChangeCommit:
+virInterfaceChangeRollback:
+virInterfaceCreate:
+virInterfaceDefineXML:
+virInterfaceDestroy:
+virInterfaceGetMACString:
+virInterfaceGetName:
+virInterfaceGetXMLDesc:
+virInterfaceIsActive:
+virInterfaceLookupByMACString:
+virInterfaceLookupByName:
+virInterfaceUndefine:
+
+
+virConnectNumOfDefinedNetworks:
+virConnectNumOfNetworks:
+virConnectListDefinedNetworks:
+virConnectListNetworks:
+virNetworkCreate:
+virNetworkCreateXML:
+virNetworkDefineXML:
+virNetworkDestroy:
+virNetworkGetAutostart:
+virNetworkGetBridgeName:
+virNetworkGetName:
+virNetworkGetUUID:
+virNetworkGetUUIDString:
+virNetworkGetXMLDesc:
+virNetworkIsActive:
+virNetworkIsPersistent:
+virNetworkLookupByName:
+virNetworkLookupByUUID:
+virNetworkLookupByUUIDString:
+virNetworkSetAutostart:
+virNetworkUndefine:
+
+
+
+virNodeDeviceCreateXML:
+virNodeDeviceDestroy:
+virNodeDeviceDettach:
+virNodeDeviceGetName:
+virNodeDeviceGetParent:
+virNodeDeviceGetXMLDesc:
+virNodeDeviceListCaps:
+virNodeDeviceLookupByName:
+virNodeDeviceNumOfCaps:
+virNodeDeviceReAttach:
+virNodeDeviceReset:
+virNodeListDevices:
+virNodeNumOfDevices:
+
+
+
+virConnectNumOfNWFilters:
+virConnectListNWFilters:
+virNWFilterDefineXML:
+virNWFilterGetName:
+virNWFilterGetUUID:
+virNWFilterGetUUIDString:
+virNWFilterGetXMLDesc:
+virNWFilterLookupByName:
+virNWFilterLookupByUUID:
+virNWFilterLookupByUUIDString:
+virNWFilterUndefine:
+
+
+
+virConnectNumOfSecrets:
+virConnectListSecrets:
+virSecretDefineXML:
+virSecretGetUsageID:
+virSecretGetUsageType:
+virSecretGetUUID:
+virSecretGetUUIDString:
+virSecretGetValue:
+virSecretGetXMLDesc:
+virSecretLookupByUsage:
+virSecretLookupByUUID:
+virSecretLookupByUUIDString:
+virSecretSetValue:
+virSecretUndefine:
+
+
+
+virConnectNumOfDefinedStoragePools:
+virConnectNumOfStoragePools:
+virConnectListDefinedStoragePools:
+virConnectListStoragePools:
+virConnectFindStoragePoolSources:
+virStoragePoolBuild:
+virStoragePoolCreate:
+virStoragePoolCreateXML:
+virStoragePoolDefineXML:
+virStoragePoolDelete:
+virStoragePoolDestroy:
+virStoragePoolGetAutostart:
+virStoragePoolGetInfo:
+virStoragePoolGetName:
+virStoragePoolGetUUID:
+virStoragePoolGetUUIDString:
+virStoragePoolGetXMLDesc:
+virStoragePoolIsActive:
+virStoragePoolIsPersistent:
+virStoragePoolListVolumes:
+virStoragePoolLookupByName:
+virStoragePoolLookupByUUID:
+virStoragePoolLookupByUUIDString:
+virStoragePoolLookupByVolume:
+virStoragePoolNumOfVolumes:
+virStoragePoolRefresh:
+virStoragePoolSetAutostart:
+virStoragePoolUndefine:
+
+
+
+virStorageVolCreateXML:
+virStorageVolCreateXMLFrom:
+virStorageVolDelete:
+virStorageVolDownload:
+virStorageVolGetInfo:
+virStorageVolGetKey:
+virStorageVolGetName:
+virStorageVolGetPath:
+virStorageVolGetXMLDesc:
+virStorageVolLookupByKey:
+virStorageVolLookupByName:
+virStorageVolLookupByPath:
+virStorageVolUpload:
+virStorageVolWipe:
+
+
+
+virStreamAbort:
+virStreamEventAddCallback:
+virStreamEventRemoveCallback:
+virStreamEventUpdateCallback:
+virStreamFinish:
+virStreamNew:
+virStreamRecv:
+virStreamRecvAll:
+virStreamSend:
+virStreamSendAll:
diff --git a/src/access/viraccessdriver.h b/src/access/viraccessdriver.h
new file mode 100644
index 0000000..ae09162
--- /dev/null
+++ b/src/access/viraccessdriver.h
@@ -0,0 +1,51 @@
+/*
+ * viraccessdriver.h: access control driver
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __VIR_ACCESS_DRIVER_H__
+# define __VIR_ACCESS_DRIVER_H__
+
+# include "conf/domain_conf.h"
+# include "access/viraccessmanager.h"
+
+typedef bool (*virAccessDriverCheckConnectDrv)(virAccessManagerPtr manager,
+                                               virAccessPermConnect av);
+typedef bool (*virAccessDriverCheckDomainDrv)(virAccessManagerPtr manager,
+                                              virDomainDefPtr def,
+                                              virAccessPermDomain av);
+
+typedef int (*virAccessDriverSetupDrv)(virAccessManagerPtr manager);
+typedef void (*virAccessDriverCleanupDrv)(virAccessManagerPtr manager);
+
+typedef struct _virAccessDriver virAccessDriver;
+typedef virAccessDriver *virAccessDriverPtr;
+
+struct _virAccessDriver {
+    size_t privateDataLen;
+    const char *name;
+
+    virAccessDriverSetupDrv setup;
+    virAccessDriverCleanupDrv cleanup;
+
+    virAccessDriverCheckConnectDrv checkConnect;
+    virAccessDriverCheckDomainDrv checkDomain;
+};
+
+
+#endif /* __VIR_ACCESS_DRIVER_H__ */
diff --git a/src/access/viraccessdrivernop.c b/src/access/viraccessdrivernop.c
new file mode 100644
index 0000000..7ba0719
--- /dev/null
+++ b/src/access/viraccessdrivernop.c
@@ -0,0 +1,44 @@
+/*
+ * viraccessdrivernop.c: no-op access control driver
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <config.h>
+
+#include "access/viraccessdrivernop.h"
+
+static bool
+virAccessDriverNopCheckConnect(virAccessManagerPtr manager ATTRIBUTE_UNUSED,
+                               virAccessPermConnect av ATTRIBUTE_UNUSED)
+{
+    return true;
+}
+
+static bool
+virAccessDriverNopCheckDomain(virAccessManagerPtr manager ATTRIBUTE_UNUSED,
+                              virDomainDefPtr def ATTRIBUTE_UNUSED,
+                              virAccessPermDomain av ATTRIBUTE_UNUSED)
+{
+    return true;
+}
+
+virAccessDriver accessDriverNop = {
+    .name = "none",
+    .checkConnect = virAccessDriverNopCheckConnect,
+    .checkDomain = virAccessDriverNopCheckDomain,
+};
diff --git a/src/access/viraccessdrivernop.h b/src/access/viraccessdrivernop.h
new file mode 100644
index 0000000..a3d9be3
--- /dev/null
+++ b/src/access/viraccessdrivernop.h
@@ -0,0 +1,28 @@
+/*
+ * viraccessdrivernop.h: no-op access control driver
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __VIR_ACCESS_DRIVER_NOP_H__
+# define __VIR_ACCESS_DRIVER_NOP_H__
+
+# include "access/viraccessdriver.h"
+
+extern virAccessDriver accessDriverNop;
+
+#endif /* __VIR_ACCESS_DRIVER_NOP_H__ */
diff --git a/src/access/viraccessdriverstack.c b/src/access/viraccessdriverstack.c
new file mode 100644
index 0000000..48aaafd
--- /dev/null
+++ b/src/access/viraccessdriverstack.c
@@ -0,0 +1,105 @@
+/*
+ * viraccessdriverstack.c: stacked access control driver
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <config.h>
+
+#include "access/viraccessdriverstack.h"
+#include "memory.h"
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_ACCESS
+
+typedef struct _virAccessDriverStackPrivate virAccessDriverStackPrivate;
+typedef virAccessDriverStackPrivate *virAccessDriverStackPrivatePtr;
+
+struct _virAccessDriverStackPrivate {
+    virAccessManagerPtr *managers;
+    size_t managersLen;
+};
+
+
+int virAccessDriverStackAppend(virAccessManagerPtr manager,
+                               virAccessManagerPtr child)
+{
+    virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager);
+
+    if (VIR_EXPAND_N(priv->managers, priv->managersLen, 1) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    priv->managers[priv->managersLen-1] = child;
+
+    return 0;
+}
+
+
+static void virAccessDriverStackCleanup(virAccessManagerPtr manager)
+{
+    virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager);
+    size_t i;
+
+    for (i = 0 ; i < priv->managersLen ; i++) {
+        virAccessManagerFree(priv->managers[i]);
+    }
+    VIR_FREE(priv->managers);
+}
+
+
+static bool
+virAccessDriverStackCheckConnect(virAccessManagerPtr manager,
+                                 virAccessPermConnect av)
+{
+    virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager);
+    bool ret = true;
+    size_t i;
+
+    for (i = 0 ; i < priv->managersLen ; i++) {
+        /* We do not short-circuit on first denial - always check all drivers */
+        if (!virAccessManagerCheckConnect(priv->managers[i], av))
+            ret = false;
+    }
+
+    return ret;
+}
+
+static bool
+virAccessDriverStackCheckDomain(virAccessManagerPtr manager,
+                                virDomainDefPtr def,
+                                virAccessPermDomain av)
+{
+    virAccessDriverStackPrivatePtr priv = virAccessManagerGetPrivateData(manager);
+    bool ret = true;
+    size_t i;
+
+    for (i = 0 ; i < priv->managersLen ; i++) {
+        /* We do not short-circuit on first denial - always check all drivers */
+        if (!virAccessManagerCheckDomain(priv->managers[i], def, av))
+            ret = false;
+    }
+
+    return ret;
+}
+
+virAccessDriver accessDriverStack = {
+    .cleanup = virAccessDriverStackCleanup,
+    .checkConnect = virAccessDriverStackCheckConnect,
+    .checkDomain = virAccessDriverStackCheckDomain,
+};
diff --git a/src/access/viraccessdriverstack.h b/src/access/viraccessdriverstack.h
new file mode 100644
index 0000000..8ab3a0d
--- /dev/null
+++ b/src/access/viraccessdriverstack.h
@@ -0,0 +1,32 @@
+/*
+ * viraccessdriverstack.h: stacked access control driver
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __VIR_ACCESS_DRIVER_STACK_H__
+# define __VIR_ACCESS_DRIVER_STACK_H__
+
+# include "access/viraccessdriver.h"
+
+
+int virAccessDriverStackAppend(virAccessManagerPtr manager,
+                               virAccessManagerPtr child);
+
+extern virAccessDriver accessDriverStack;
+
+#endif /* __VIR_ACCESS_DRIVER_STACK_H__ */
diff --git a/src/access/viraccessmanager.c b/src/access/viraccessmanager.c
new file mode 100644
index 0000000..4e77bd6
--- /dev/null
+++ b/src/access/viraccessmanager.c
@@ -0,0 +1,338 @@
+/*
+ * viraccessmanager.c: access control manager
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <config.h>
+
+#include "viraccessmanager.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "threads.h"
+#if HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+#include "access/viraccessdrivernop.h"
+#include "access/viraccessdriverstack.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_ACCESS
+#define virAccessError(code, ...)                                       \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,                 \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+static volatile bool onceInitErr = false;
+static virOnceControl onceInit = VIR_ONCE_CONTROL_INITIALIZER;
+static virThreadLocal realIdentity;
+static virThreadLocal effectiveIdentity;
+
+struct _virAccessManager {
+    virAccessDriverPtr drv;
+};
+
+
+static void virAccessManagerOnceInit(void)
+{
+    if (virThreadLocalInit(&realIdentity,
+                           (virThreadLocalCleanup)virIdentityFree) < 0)
+        onceInitErr = true;
+    if (virThreadLocalInit(&effectiveIdentity,
+                           (virThreadLocalCleanup)virIdentityFree) < 0)
+        onceInitErr = true;
+}
+
+static bool virAccessManagerInit(void)
+{
+    if (virOnce(&onceInit, virAccessManagerOnceInit) < 0 ||
+        onceInitErr) {
+        virReportSystemError(errno, "%s",
+                             _("Failed to initialize access manager"));
+        return false;
+    }
+
+    return true;
+}
+
+virIdentityPtr virAccessManagerGetSystemIdentity(void)
+{
+    char *username = NULL;
+    char *groupname = NULL;
+    char *seccontext = NULL;
+    virIdentityPtr ret = NULL;
+    gid_t gid = getgid();
+    uid_t uid = getuid();
+#if HAVE_SELINUX
+    security_context_t con;
+#endif
+
+    if (!(username = virGetUserName(uid)))
+        goto cleanup;
+    if (!(groupname = virGetGroupName(gid)))
+        goto cleanup;
+
+#if HAVE_SELINUX
+    if (getcon(&con) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to lookup SELinux process context"));
+        goto cleanup;
+    }
+    seccontext = strdup(con);
+    freecon(con);
+    if (!seccontext) {
+        virReportOOMError();
+        goto cleanup;
+    }
+#endif
+
+    if (!(ret = virIdentityNew()))
+        goto cleanup;
+
+    if (username &&
+        virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_USER_NAME, username) < 0)
+        goto error;
+    if (groupname &&
+        virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_UNIX_GROUP_NAME, groupname) < 0)
+        goto error;
+    if (seccontext &&
+        virIdentitySetAttr(ret, VIR_IDENTITY_ATTR_SECURITY_CONTEXT, seccontext) < 0)
+        goto error;
+
+cleanup:
+    VIR_FREE(username);
+    VIR_FREE(groupname);
+    VIR_FREE(seccontext);
+    return ret;
+
+error:
+    virIdentityFree(ret);
+    ret = NULL;
+    goto cleanup;
+}
+
+virIdentityPtr virAccessManagerGetEffectiveIdentity(void)
+{
+    virIdentityPtr ret;
+
+    if (!virAccessManagerInit())
+        return NULL;
+
+    ret = virThreadLocalGet(&effectiveIdentity);
+    virIdentityRef(ret);
+    return ret;
+}
+
+int virAccessManagerSetEffectiveIdentity(virIdentityPtr identity)
+{
+    virIdentityPtr old;
+
+    if (!virAccessManagerInit())
+        return -1;
+
+    old = virThreadLocalGet(&effectiveIdentity);
+    if (old)
+        virIdentityFree(old);
+
+    if (virThreadLocalSet(&effectiveIdentity, identity) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to set thread local identity"));
+        return -1;
+    }
+
+    if (identity)
+        virIdentityRef(identity);
+    return 0;
+}
+
+virIdentityPtr virAccessManagerGetRealIdentity(void)
+{
+    virIdentityPtr ret;
+
+    if (!virAccessManagerInit())
+        return NULL;
+
+    ret = virThreadLocalGet(&realIdentity);
+    virIdentityRef(ret);
+    return ret;
+}
+
+int virAccessManagerSetRealIdentity(virIdentityPtr identity)
+{
+    virIdentityPtr old;
+
+    if (!virAccessManagerInit())
+        return -1;
+
+    old = virThreadLocalGet(&realIdentity);
+    if (old)
+        virIdentityFree(old);
+
+    if (virThreadLocalSet(&realIdentity, identity) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to set thread local identity"));
+        return -1;
+    }
+
+    if (identity)
+        virIdentityRef(identity);
+    return 0;
+}
+
+
+static virAccessManagerPtr virAccessManagerNewDriver(virAccessDriverPtr drv)
+{
+    virAccessManagerPtr mgr;
+
+    if (VIR_ALLOC_VAR(mgr, char, drv->privateDataLen) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    mgr->drv = drv;
+
+    if (mgr->drv->setup &&
+        mgr->drv->setup(mgr) < 0) {
+        VIR_FREE(mgr);
+        return NULL;
+    }
+
+    return mgr;
+}
+
+
+static virAccessDriverPtr accessDrivers[] = {
+    &accessDriverNop,
+};
+
+
+static virAccessDriverPtr virAccessManagerFindDriver(const char *name)
+{
+    size_t i;
+    for (i = 0 ; i < ARRAY_CARDINALITY(accessDrivers) ; i++) {
+        if (STREQ(name, accessDrivers[i]->name))
+            return accessDrivers[i];
+    }
+
+    return NULL;
+}
+
+
+virAccessManagerPtr virAccessManagerNew(const char *name)
+{
+    virAccessDriverPtr drv = virAccessManagerFindDriver(name);
+    if (!drv)
+        return NULL;
+
+    return virAccessManagerNewDriver(drv);
+}
+
+
+virAccessManagerPtr virAccessManagerNewStack(const char **names,
+                                             size_t namesLen)
+{
+    virAccessManagerPtr manager = virAccessManagerNewDriver(&accessDriverStack);
+    size_t i;
+
+    if (!manager)
+        return NULL;
+
+    for (i = 0 ; i < namesLen ; i++) {
+        virAccessManagerPtr child = virAccessManagerNew(names[i]);
+
+        if (!child)
+            goto error;
+
+        if (virAccessDriverStackAppend(manager, child) < 0) {
+            virAccessManagerFree(child);
+            goto error;
+        }
+    }
+
+    return manager;
+
+error:
+    virAccessManagerFree(manager);
+    return NULL;
+}
+
+
+void *virAccessManagerGetPrivateData(virAccessManagerPtr mgr)
+{
+    /* This accesses the memory just beyond mgr, which was allocated
+     * via VIR_ALLOC_VAR earlier.  */
+    return mgr + 1;
+}
+
+
+void virAccessManagerFree(virAccessManagerPtr mgr)
+{
+    if (!mgr)
+        return;
+
+    if (mgr->drv->cleanup)
+        mgr->drv->cleanup(mgr);
+
+    VIR_FREE(mgr);
+}
+
+
+/* Standard security practice is to not tell the caller *why*
+ * they were denied access. So this method takes the real
+ * libvirt errors & replaces it with a generic error. Fortunately
+ * the daemon logs will still contain the original error message
+ * should the admin need to debug things
+ */
+static bool
+virAccessManagerSanitizeError(bool ret)
+{
+    if (!ret) {
+        virResetLastError();
+        virAccessError(VIR_ERR_ACCESS_DENIED, NULL);
+    }
+
+    return ret;
+}
+
+bool virAccessManagerCheckConnect(virAccessManagerPtr manager,
+                                  virAccessPermConnect av)
+{
+    bool ret = true;
+    VIR_DEBUG("manager=%p driver=%s av=%d",
+              manager, manager->drv->name, av);
+
+    if (manager->drv->checkConnect &&
+        !manager->drv->checkConnect(manager, av))
+        ret = false;
+
+    return virAccessManagerSanitizeError(ret);
+}
+
+
+bool virAccessManagerCheckDomain(virAccessManagerPtr manager,
+                                 virDomainDefPtr def,
+                                 virAccessPermDomain av)
+{
+    bool ret = true;
+    VIR_DEBUG("manager=%p driver=%s def=%p av=%d",
+              manager, manager->drv->name, def, av);
+
+    if (manager->drv->checkDomain &&
+        !manager->drv->checkDomain(manager, def, av))
+        ret = false;
+
+    return virAccessManagerSanitizeError(ret);
+}
diff --git a/src/access/viraccessmanager.h b/src/access/viraccessmanager.h
new file mode 100644
index 0000000..b7e19b5
--- /dev/null
+++ b/src/access/viraccessmanager.h
@@ -0,0 +1,56 @@
+/*
+ * viraccessmanager.h: access control manager
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __VIR_ACCESS_MANAGER_H__
+# define __VIR_ACCESS_MANAGER_H__
+
+# include "rpc/virnetserverclient.h"
+# include "conf/domain_conf.h"
+# include "access/viraccessperm.h"
+
+virIdentityPtr virAccessManagerGetClientIdentity(virNetServerClientPtr client);
+virIdentityPtr virAccessManagerGetSystemIdentity(void);
+
+virIdentityPtr virAccessManagerGetEffectiveIdentity(void);
+int virAccessManagerSetEffectiveIdentity(virIdentityPtr identity);
+
+virIdentityPtr virAccessManagerGetRealIdentity(void);
+int virAccessManagerSetRealIdentity(virIdentityPtr identity);
+
+typedef struct _virAccessManager virAccessManager;
+typedef virAccessManager *virAccessManagerPtr;
+
+virAccessManagerPtr virAccessManagerNew(const char *name);
+virAccessManagerPtr virAccessManagerNewStack(const char **names,
+                                             size_t namesLen);
+
+
+void *virAccessManagerGetPrivateData(virAccessManagerPtr manager);
+void virAccessManagerFree(virAccessManagerPtr manager);
+
+
+bool virAccessManagerCheckConnect(virAccessManagerPtr manager,
+                                  virAccessPermConnect av);
+bool virAccessManagerCheckDomain(virAccessManagerPtr manager,
+                                 virDomainDefPtr def,
+                                 virAccessPermDomain av);
+
+
+#endif /* __VIR_ACCESS_MANAGER_H__ */
diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c
new file mode 100644
index 0000000..7ccded5
--- /dev/null
+++ b/src/access/viraccessperm.c
@@ -0,0 +1,37 @@
+/*
+ * viraccessperm.c: access control permissions
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <config.h>
+
+#include "viraccessperm.h"
+
+
+VIR_ENUM_IMPL(virAccessPermConnect,
+              VIR_ACCESS_PERM_CONNECT_LAST,
+              "getattr", "search_domains");
+
+VIR_ENUM_IMPL(virAccessPermDomain,
+              VIR_ACCESS_PERM_DOMAIN_LAST,
+              "getattr", "read", "write", "read_secure",
+              "start", "stop", "save", "delete",
+              "shutdown", "reboot", "reset",
+              "migrate", "snapshot", "suspend", "hibernate", "core_dump",
+              "inject_nmi", "send_key", "read_block", "read_mem",
+              "open_graphics", "open_console", "screenshot");
diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h
new file mode 100644
index 0000000..83b17ad
--- /dev/null
+++ b/src/access/viraccessperm.h
@@ -0,0 +1,73 @@
+/*
+ * viraccessperm.h: access control permissions
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#ifndef __VIR_ACCESS_PERM_H__
+# define __VIR_ACCESS_PERM_H__
+
+# include "internal.h"
+# include "util.h"
+
+typedef enum {
+    VIR_ACCESS_PERM_CONNECT_GETATTR,
+    VIR_ACCESS_PERM_CONNECT_SEARCH_DOMAINS,
+
+    VIR_ACCESS_PERM_CONNECT_LAST,
+} virAccessPermConnect;
+
+typedef enum {
+    VIR_ACCESS_PERM_DOMAIN_GETATTR,  /* Name/ID/UUID access */
+    VIR_ACCESS_PERM_DOMAIN_READ,     /* Config access */
+    VIR_ACCESS_PERM_DOMAIN_WRITE,    /* Config change */
+    VIR_ACCESS_PERM_DOMAIN_READ_SECURE,
+
+    VIR_ACCESS_PERM_DOMAIN_START,
+    VIR_ACCESS_PERM_DOMAIN_STOP,
+
+    VIR_ACCESS_PERM_DOMAIN_SAVE,
+    VIR_ACCESS_PERM_DOMAIN_DELETE,
+
+    /* Merge these 3 into 1 ? */
+    VIR_ACCESS_PERM_DOMAIN_SHUTDOWN,
+    VIR_ACCESS_PERM_DOMAIN_REBOOT,
+    VIR_ACCESS_PERM_DOMAIN_RESET,
+
+    VIR_ACCESS_PERM_DOMAIN_MIGRATE,
+    VIR_ACCESS_PERM_DOMAIN_SNAPSHOT,
+    VIR_ACCESS_PERM_DOMAIN_SUSPEND,
+    VIR_ACCESS_PERM_DOMAIN_HIBERNATE,
+    VIR_ACCESS_PERM_DOMAIN_CORE_DUMP,
+
+    VIR_ACCESS_PERM_DOMAIN_INJECT_NMI,
+    VIR_ACCESS_PERM_DOMAIN_SEND_KEY,
+
+    VIR_ACCESS_PERM_DOMAIN_READ_BLOCK,
+    VIR_ACCESS_PERM_DOMAIN_READ_MEM,
+
+    VIR_ACCESS_PERM_DOMAIN_OPEN_GRAPHICS,
+    VIR_ACCESS_PERM_DOMAIN_OPEN_CONSOLE,
+    VIR_ACCESS_PERM_DOMAIN_SCREENSHOT,
+
+    VIR_ACCESS_PERM_DOMAIN_LAST,
+} virAccessPermDomain;
+
+VIR_ENUM_DECL(virAccessPermConnect);
+VIR_ENUM_DECL(virAccessPermDomain);
+
+#endif /* __VIR_ACCESS_PERM_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 391c977..ca60eb3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1181,6 +1181,27 @@ virAuthConfigNew;
 virAuthConfigNewData;
 
 
+# viraccessmanager.h
+virAccessManagerInit;
+virAccessManagerGetSystemIdentity;
+virAccessManagerGetRealIdentity;
+virAccessManagerGetEffectiveIdentity;
+virAccessManagerSetRealIdentity;
+virAccessManagerSetEffectiveIdentity;
+virAccessManagerNew;
+virAccessManagerNewStack;
+virAccessManagerFree;
+virAccessManagerCheckConnect;
+virAccessManagerCheckDomain;
+
+
+# viraccessvector.h
+virAccessVectorConnectTypeFromString;
+virAccessVectorConnectTypeToString;
+virAccessVectorDomainTypeFromString;
+virAccessVectorDomainTypeToString;
+
+
 # viraudit.h
 virAuditClose;
 virAuditEncode;
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 33ef713..e60a008 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -187,6 +187,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_DBUS:
             dom = "DBus ";
             break;
+        case VIR_FROM_ACCESS:
+            dom = "Access Manager ";
+            break;
     }
     return dom;
 }
@@ -1265,6 +1268,12 @@ virErrorMsg(virErrorNumber error, const char *info)
             else
                 errmsg = _("invalid identity pointer in %s");
             break;
+        case VIR_ERR_ACCESS_DENIED:
+            if (info == NULL)
+                errmsg = _("access denied");
+            else
+                errmsg = _("access denied: %s");
+            break;
     }
     return errmsg;
 }
-- 
1.7.10




More information about the libvir-list mailing list