]> xenbits.xensource.com Git - libvirt.git/commitdiff
Move security drivers to src/security/
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 15 Sep 2009 18:06:37 +0000 (19:06 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 21 Sep 2009 13:41:44 +0000 (14:41 +0100)
* src/Makefile.am, src/qemu/qemu_conf.h, src/qemu/qemu_driver.c,
  tests/seclabeltest.c: Adapt for changed paths
* src/security.c: Rename to src/security/security_driver.c
* src/security.h: Rename to src/security/security_driver.h
* src/security_selinux.c, src/security_selinux.h: Move to src/security/

12 files changed:
src/Makefile.am
src/qemu/qemu_conf.h
src/qemu/qemu_driver.c
src/security.c [deleted file]
src/security.h [deleted file]
src/security/security_driver.c [new file with mode: 0644]
src/security/security_driver.h [new file with mode: 0644]
src/security/security_selinux.c [new file with mode: 0644]
src/security/security_selinux.h [new file with mode: 0644]
src/security_selinux.c [deleted file]
src/security_selinux.h [deleted file]
tests/seclabeltest.c

index 87785925e30e8ee85dc05274a8e0c34127a30eb0..373b2b30f8b7111ee813971268528922f2d973ef 100644 (file)
@@ -219,10 +219,10 @@ STORAGE_HELPER_DISK_SOURCES =                                     \
 
 # Security framework and drivers for various models
 SECURITY_DRIVER_SOURCES =                                      \
-               security.h security.c
+               security/security_driver.h security/security_driver.c
 
 SECURITY_DRIVER_SELINUX_SOURCES =                              \
-               security_selinux.h security_selinux.c
+               security/security_selinux.h security/security_selinux.c
 
 
 NODE_DEVICE_DRIVER_SOURCES =                                   \
index ed91d2cd2ad8de6fed3d980234c73651ff3f8fa7..7b35b6d9cf212b17475842d16b38c043af5bfdde 100644 (file)
@@ -33,7 +33,7 @@
 #include "domain_conf.h"
 #include "domain_event.h"
 #include "threads.h"
-#include "security.h"
+#include "security/security_driver.h"
 #include "cgroup.h"
 #include "pci.h"
 
index 068b0642f3f2861956b3ece84900d7b0ef999b6b..a1f3c83f0adbc7779282482e49c3896c76d6e6be 100644 (file)
@@ -68,7 +68,7 @@
 #include "node_device_conf.h"
 #include "pci.h"
 #include "hostusb.h"
-#include "security.h"
+#include "security/security_driver.h"
 #include "cgroup.h"
 
 
diff --git a/src/security.c b/src/security.c
deleted file mode 100644 (file)
index 4138547..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- *
- * Authors:
- *     James Morris <jmorris@namei.org>
- *
- */
-#include <config.h>
-#include <string.h>
-
-#include "virterror_internal.h"
-
-#include "security.h"
-#ifdef WITH_SECDRIVER_SELINUX
-#include "security_selinux.h"
-#endif
-
-static virSecurityDriverPtr security_drivers[] = {
-#ifdef WITH_SECDRIVER_SELINUX
-    &virSELinuxSecurityDriver,
-#endif
-    NULL
-};
-
-int
-virSecurityDriverVerify(virConnectPtr conn, virDomainDefPtr def)
-{
-    unsigned int i;
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
-
-    if (!secdef->model ||
-        STREQ(secdef->model, "none"))
-        return 0;
-
-    for (i = 0; security_drivers[i] != NULL ; i++) {
-        if (STREQ(security_drivers[i]->name, secdef->model)) {
-            return security_drivers[i]->domainSecurityVerify(conn, def);
-        }
-    }
-    virSecurityReportError(conn, VIR_ERR_XML_ERROR,
-                           _("invalid security model '%s'"), secdef->model);
-    return -1;
-}
-
-int
-virSecurityDriverStartup(virSecurityDriverPtr *drv,
-                         const char *name)
-{
-    unsigned int i;
-
-    if (name && STREQ(name, "none"))
-        return -2;
-
-    for (i = 0; security_drivers[i] != NULL ; i++) {
-        virSecurityDriverPtr tmp = security_drivers[i];
-
-        if (name && STRNEQ(tmp->name, name))
-            continue;
-
-        switch (tmp->probe()) {
-        case SECURITY_DRIVER_ENABLE:
-            virSecurityDriverInit(tmp);
-            if (tmp->open(NULL, tmp) == -1) {
-                return -1;
-            } else {
-                *drv = tmp;
-                return 0;
-            }
-            break;
-
-        case SECURITY_DRIVER_DISABLE:
-            break;
-
-        default:
-            return -1;
-        }
-    }
-    return -2;
-}
-
-void
-virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
-{
-    va_list args;
-    char errorMessage[1024];
-
-    if (fmt) {
-        va_start(args, fmt);
-        vsnprintf(errorMessage, sizeof(errorMessage) - 1, fmt, args);
-        va_end(args);
-    } else
-        errorMessage[0] = '\0';
-
-    virRaiseError(conn, NULL, NULL, VIR_FROM_SECURITY, code,
-                  VIR_ERR_ERROR, NULL, NULL, NULL, -1, -1, "%s",
-                  errorMessage);
-}
-
-/*
- * Helpers
- */
-void
-virSecurityDriverInit(virSecurityDriverPtr drv)
-{
-    memset(&drv->_private, 0, sizeof drv->_private);
-}
-
-int
-virSecurityDriverSetDOI(virConnectPtr conn,
-                        virSecurityDriverPtr drv,
-                        const char *doi)
-{
-    if (strlen(doi) >= VIR_SECURITY_DOI_BUFLEN) {
-        virSecurityReportError(conn, VIR_ERR_ERROR,
-                               _("%s: DOI \'%s\' is "
-                               "longer than the maximum allowed length of %d"),
-                               __func__, doi, VIR_SECURITY_DOI_BUFLEN - 1);
-        return -1;
-    }
-    strcpy(drv->_private.doi, doi);
-    return 0;
-}
-
-const char *
-virSecurityDriverGetDOI(virSecurityDriverPtr drv)
-{
-    return drv->_private.doi;
-}
-
-const char *
-virSecurityDriverGetModel(virSecurityDriverPtr drv)
-{
-    return drv->name;
-}
diff --git a/src/security.h b/src/security.h
deleted file mode 100644 (file)
index 40f9d95..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- *
- * Authors:
- *     James Morris <jmorris@namei.org>
- *
- */
-#ifndef __VIR_SECURITY_H__
-#define __VIR_SECURITY_H__
-
-#include "internal.h"
-#include "domain_conf.h"
-
-/*
- * Return values for security driver probing: the driver will determine
- * whether it should be enabled or disabled.
- */
-typedef enum {
-    SECURITY_DRIVER_ENABLE      = 0,
-    SECURITY_DRIVER_ERROR       = -1,
-    SECURITY_DRIVER_DISABLE     = -2,
-} virSecurityDriverStatus;
-
-typedef struct _virSecurityDriver virSecurityDriver;
-typedef virSecurityDriver *virSecurityDriverPtr;
-typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
-typedef int (*virSecurityDriverOpen) (virConnectPtr conn,
-                                      virSecurityDriverPtr drv);
-typedef int (*virSecurityDomainRestoreImageLabel) (virConnectPtr conn,
-                                                   virDomainDiskDefPtr disk);
-typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
-                                               virDomainObjPtr vm,
-                                               virDomainDiskDefPtr disk);
-typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn,
-                                                     virDomainHostdevDefPtr dev);
-typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn,
-                                                 virDomainObjPtr vm,
-                                                 virDomainHostdevDefPtr dev);
-typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
-                                          virDomainObjPtr sec);
-typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
-                                           virDomainObjPtr sec);
-typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
-                                          virDomainObjPtr vm,
-                                          virSecurityLabelPtr sec);
-typedef int (*virSecurityDomainRestoreLabel) (virConnectPtr conn,
-                                              virDomainObjPtr vm);
-typedef int (*virSecurityDomainSetLabel) (virConnectPtr conn,
-                                          virSecurityDriverPtr drv,
-                                          virDomainObjPtr vm);
-typedef int (*virSecurityDomainSecurityVerify) (virConnectPtr conn,
-                                                virDomainDefPtr def);
-
-struct _virSecurityDriver {
-    const char *name;
-    virSecurityDriverProbe probe;
-    virSecurityDriverOpen open;
-    virSecurityDomainSecurityVerify domainSecurityVerify;
-    virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
-    virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
-    virSecurityDomainGenLabel domainGenSecurityLabel;
-    virSecurityDomainReserveLabel domainReserveSecurityLabel;
-    virSecurityDomainGetLabel domainGetSecurityLabel;
-    virSecurityDomainSetLabel domainSetSecurityLabel;
-    virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
-    virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel;
-    virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel;
-
-    /*
-     * This is internally managed driver state and should only be accessed
-     * via helpers below.
-     */
-    struct {
-        char doi[VIR_SECURITY_DOI_BUFLEN];
-    } _private;
-};
-
-/* Global methods */
-int virSecurityDriverStartup(virSecurityDriverPtr *drv,
-                             const char *name);
-
-int
-virSecurityDriverVerify(virConnectPtr conn, virDomainDefPtr def);
-
-void
-virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
-    ATTRIBUTE_FMT_PRINTF(3, 4);
-
-/* Helpers */
-void virSecurityDriverInit(virSecurityDriverPtr drv);
-int virSecurityDriverSetDOI(virConnectPtr conn,
-                            virSecurityDriverPtr drv,
-                            const char *doi);
-const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
-const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
-
-#endif /* __VIR_SECURITY_H__ */
diff --git a/src/security/security_driver.c b/src/security/security_driver.c
new file mode 100644 (file)
index 0000000..f94a2e2
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ * Authors:
+ *     James Morris <jmorris@namei.org>
+ *
+ */
+#include <config.h>
+#include <string.h>
+
+#include "virterror_internal.h"
+
+#include "security_driver.h"
+#ifdef WITH_SECDRIVER_SELINUX
+#include "security_selinux.h"
+#endif
+
+static virSecurityDriverPtr security_drivers[] = {
+#ifdef WITH_SECDRIVER_SELINUX
+    &virSELinuxSecurityDriver,
+#endif
+    NULL
+};
+
+int
+virSecurityDriverVerify(virConnectPtr conn, virDomainDefPtr def)
+{
+    unsigned int i;
+    const virSecurityLabelDefPtr secdef = &def->seclabel;
+
+    if (!secdef->model ||
+        STREQ(secdef->model, "none"))
+        return 0;
+
+    for (i = 0; security_drivers[i] != NULL ; i++) {
+        if (STREQ(security_drivers[i]->name, secdef->model)) {
+            return security_drivers[i]->domainSecurityVerify(conn, def);
+        }
+    }
+    virSecurityReportError(conn, VIR_ERR_XML_ERROR,
+                           _("invalid security model '%s'"), secdef->model);
+    return -1;
+}
+
+int
+virSecurityDriverStartup(virSecurityDriverPtr *drv,
+                         const char *name)
+{
+    unsigned int i;
+
+    if (name && STREQ(name, "none"))
+        return -2;
+
+    for (i = 0; security_drivers[i] != NULL ; i++) {
+        virSecurityDriverPtr tmp = security_drivers[i];
+
+        if (name && STRNEQ(tmp->name, name))
+            continue;
+
+        switch (tmp->probe()) {
+        case SECURITY_DRIVER_ENABLE:
+            virSecurityDriverInit(tmp);
+            if (tmp->open(NULL, tmp) == -1) {
+                return -1;
+            } else {
+                *drv = tmp;
+                return 0;
+            }
+            break;
+
+        case SECURITY_DRIVER_DISABLE:
+            break;
+
+        default:
+            return -1;
+        }
+    }
+    return -2;
+}
+
+void
+virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
+{
+    va_list args;
+    char errorMessage[1024];
+
+    if (fmt) {
+        va_start(args, fmt);
+        vsnprintf(errorMessage, sizeof(errorMessage) - 1, fmt, args);
+        va_end(args);
+    } else
+        errorMessage[0] = '\0';
+
+    virRaiseError(conn, NULL, NULL, VIR_FROM_SECURITY, code,
+                  VIR_ERR_ERROR, NULL, NULL, NULL, -1, -1, "%s",
+                  errorMessage);
+}
+
+/*
+ * Helpers
+ */
+void
+virSecurityDriverInit(virSecurityDriverPtr drv)
+{
+    memset(&drv->_private, 0, sizeof drv->_private);
+}
+
+int
+virSecurityDriverSetDOI(virConnectPtr conn,
+                        virSecurityDriverPtr drv,
+                        const char *doi)
+{
+    if (strlen(doi) >= VIR_SECURITY_DOI_BUFLEN) {
+        virSecurityReportError(conn, VIR_ERR_ERROR,
+                               _("%s: DOI \'%s\' is "
+                               "longer than the maximum allowed length of %d"),
+                               __func__, doi, VIR_SECURITY_DOI_BUFLEN - 1);
+        return -1;
+    }
+    strcpy(drv->_private.doi, doi);
+    return 0;
+}
+
+const char *
+virSecurityDriverGetDOI(virSecurityDriverPtr drv)
+{
+    return drv->_private.doi;
+}
+
+const char *
+virSecurityDriverGetModel(virSecurityDriverPtr drv)
+{
+    return drv->name;
+}
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
new file mode 100644 (file)
index 0000000..40f9d95
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ * Authors:
+ *     James Morris <jmorris@namei.org>
+ *
+ */
+#ifndef __VIR_SECURITY_H__
+#define __VIR_SECURITY_H__
+
+#include "internal.h"
+#include "domain_conf.h"
+
+/*
+ * Return values for security driver probing: the driver will determine
+ * whether it should be enabled or disabled.
+ */
+typedef enum {
+    SECURITY_DRIVER_ENABLE      = 0,
+    SECURITY_DRIVER_ERROR       = -1,
+    SECURITY_DRIVER_DISABLE     = -2,
+} virSecurityDriverStatus;
+
+typedef struct _virSecurityDriver virSecurityDriver;
+typedef virSecurityDriver *virSecurityDriverPtr;
+typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
+typedef int (*virSecurityDriverOpen) (virConnectPtr conn,
+                                      virSecurityDriverPtr drv);
+typedef int (*virSecurityDomainRestoreImageLabel) (virConnectPtr conn,
+                                                   virDomainDiskDefPtr disk);
+typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
+                                               virDomainObjPtr vm,
+                                               virDomainDiskDefPtr disk);
+typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn,
+                                                     virDomainHostdevDefPtr dev);
+typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn,
+                                                 virDomainObjPtr vm,
+                                                 virDomainHostdevDefPtr dev);
+typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
+                                          virDomainObjPtr sec);
+typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
+                                           virDomainObjPtr sec);
+typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
+                                          virDomainObjPtr vm,
+                                          virSecurityLabelPtr sec);
+typedef int (*virSecurityDomainRestoreLabel) (virConnectPtr conn,
+                                              virDomainObjPtr vm);
+typedef int (*virSecurityDomainSetLabel) (virConnectPtr conn,
+                                          virSecurityDriverPtr drv,
+                                          virDomainObjPtr vm);
+typedef int (*virSecurityDomainSecurityVerify) (virConnectPtr conn,
+                                                virDomainDefPtr def);
+
+struct _virSecurityDriver {
+    const char *name;
+    virSecurityDriverProbe probe;
+    virSecurityDriverOpen open;
+    virSecurityDomainSecurityVerify domainSecurityVerify;
+    virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
+    virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
+    virSecurityDomainGenLabel domainGenSecurityLabel;
+    virSecurityDomainReserveLabel domainReserveSecurityLabel;
+    virSecurityDomainGetLabel domainGetSecurityLabel;
+    virSecurityDomainSetLabel domainSetSecurityLabel;
+    virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
+    virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel;
+    virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel;
+
+    /*
+     * This is internally managed driver state and should only be accessed
+     * via helpers below.
+     */
+    struct {
+        char doi[VIR_SECURITY_DOI_BUFLEN];
+    } _private;
+};
+
+/* Global methods */
+int virSecurityDriverStartup(virSecurityDriverPtr *drv,
+                             const char *name);
+
+int
+virSecurityDriverVerify(virConnectPtr conn, virDomainDefPtr def);
+
+void
+virSecurityReportError(virConnectPtr conn, int code, const char *fmt, ...)
+    ATTRIBUTE_FMT_PRINTF(3, 4);
+
+/* Helpers */
+void virSecurityDriverInit(virSecurityDriverPtr drv);
+int virSecurityDriverSetDOI(virConnectPtr conn,
+                            virSecurityDriverPtr drv,
+                            const char *doi);
+const char *virSecurityDriverGetDOI(virSecurityDriverPtr drv);
+const char *virSecurityDriverGetModel(virSecurityDriverPtr drv);
+
+#endif /* __VIR_SECURITY_H__ */
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
new file mode 100644 (file)
index 0000000..b84de8f
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2008,2009 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.
+ *
+ * Authors:
+ *     James Morris <jmorris@namei.org>
+ *     Dan Walsh <dwalsh@redhat.com>
+ *
+ * SELinux security driver.
+ */
+#include <config.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "security_driver.h"
+#include "security_selinux.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "pci.h"
+#include "hostusb.h"
+
+#define VIR_FROM_THIS VIR_FROM_SECURITY
+
+static char default_domain_context[1024];
+static char default_content_context[1024];
+static char default_image_context[1024];
+#define SECURITY_SELINUX_VOID_DOI       "0"
+#define SECURITY_SELINUX_NAME "selinux"
+
+/* TODO
+   The data struct of used mcs should be replaced with a better data structure in the future
+*/
+
+struct MCS {
+    char *mcs;
+    struct MCS *next;
+};
+static struct MCS *mcsList = NULL;
+
+static int
+mcsAdd(const char *mcs)
+{
+    struct MCS *ptr;
+
+    for (ptr = mcsList; ptr; ptr = ptr->next) {
+        if (STREQ(ptr->mcs, mcs))
+            return -1;
+    }
+    if (VIR_ALLOC(ptr) < 0)
+        return -1;
+    ptr->mcs = strdup(mcs);
+    ptr->next = mcsList;
+    mcsList = ptr;
+    return 0;
+}
+
+static int
+mcsRemove(const char *mcs)
+{
+    struct MCS *prevptr = NULL;
+    struct MCS *ptr = NULL;
+
+    for (ptr = mcsList; ptr; ptr = ptr->next) {
+        if (STREQ(ptr->mcs, mcs)) {
+            if (prevptr)
+                prevptr->next = ptr->next;
+            else {
+                mcsList = ptr->next;
+            }
+            free(ptr->mcs);
+            free(ptr);
+            return 0;
+        }
+        prevptr = ptr;
+    }
+    return -1;
+}
+
+static char *
+SELinuxGenNewContext(const char *oldcontext, const char *mcs)
+{
+    char *newcontext = NULL;
+    char *scontext = strdup(oldcontext);
+    if (!scontext) goto err;
+    context_t con = context_new(scontext);
+    if (!con) goto err;
+    context_range_set(con, mcs);
+    newcontext = strdup(context_str(con));
+    context_free(con);
+err:
+    freecon(scontext);
+    return (newcontext);
+}
+
+static int
+SELinuxInitialize(virConnectPtr conn)
+{
+    char *ptr = NULL;
+    int fd = 0;
+
+    virRandomInitialize(time(NULL) ^ getpid());
+
+    fd = open(selinux_virtual_domain_context_path(), O_RDONLY);
+    if (fd < 0) {
+        virReportSystemError(conn, errno,
+                             _("cannot open SELinux virtual domain context file '%s'"),
+                             selinux_virtual_domain_context_path());
+        return -1;
+    }
+
+    if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) {
+        virReportSystemError(conn, errno,
+                             _("cannot read SELinux virtual domain context file %s"),
+                             selinux_virtual_domain_context_path());
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    ptr = strchrnul(default_domain_context, '\n');
+    *ptr = '\0';
+
+    if ((fd = open(selinux_virtual_image_context_path(), O_RDONLY)) < 0) {
+        virReportSystemError(conn, errno,
+                             _("cannot open SELinux virtual image context file %s"),
+                             selinux_virtual_image_context_path());
+        return -1;
+    }
+
+    if (saferead(fd, default_image_context, sizeof(default_image_context)) < 0) {
+        virReportSystemError(conn, errno,
+                             _("cannot read SELinux virtual image context file %s"),
+                             selinux_virtual_image_context_path());
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    ptr = strchrnul(default_image_context, '\n');
+    if (*ptr == '\n') {
+        *ptr = '\0';
+        strcpy(default_content_context, ptr+1);
+        ptr = strchrnul(default_content_context, '\n');
+        if (*ptr == '\n')
+            *ptr = '\0';
+    }
+    return 0;
+}
+
+static int
+SELinuxGenSecurityLabel(virConnectPtr conn,
+                        virDomainObjPtr vm)
+{
+    int rc = -1;
+    char mcs[1024];
+    char *scontext = NULL;
+    int c1 = 0;
+    int c2 = 0;
+
+    if (vm->def->seclabel.label ||
+        vm->def->seclabel.model ||
+        vm->def->seclabel.imagelabel) {
+        virSecurityReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s", _("security label already defined for VM"));
+        return rc;
+    }
+
+    do {
+        c1 = virRandom(1024);
+        c2 = virRandom(1024);
+
+        if ( c1 == c2 ) {
+            sprintf(mcs, "s0:c%d", c1);
+        } else {
+            if ( c1 < c2 )
+                sprintf(mcs, "s0:c%d,c%d", c1, c2);
+            else
+                sprintf(mcs, "s0:c%d,c%d", c2, c1);
+        }
+    } while(mcsAdd(mcs) == -1);
+
+    vm->def->seclabel.label = SELinuxGenNewContext(default_domain_context, mcs);
+    if (! vm->def->seclabel.label)  {
+        virSecurityReportError(conn, VIR_ERR_ERROR,
+                               _("cannot generate selinux context for %s"), mcs);
+        goto err;
+    }
+    vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
+    if (! vm->def->seclabel.imagelabel)  {
+        virSecurityReportError(conn, VIR_ERR_ERROR,
+                               _("cannot generate selinux context for %s"), mcs);
+        goto err;
+    }
+    vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME);
+    if (!vm->def->seclabel.model) {
+        virReportOOMError(conn);
+        goto err;
+    }
+
+
+    rc = 0;
+    goto done;
+err:
+    VIR_FREE(vm->def->seclabel.label);
+    VIR_FREE(vm->def->seclabel.imagelabel);
+    VIR_FREE(vm->def->seclabel.model);
+done:
+    VIR_FREE(scontext);
+    return rc;
+}
+
+static int
+SELinuxReserveSecurityLabel(virConnectPtr conn,
+                            virDomainObjPtr vm)
+{
+    security_context_t pctx;
+    context_t ctx = NULL;
+    const char *mcs;
+
+    if (getpidcon(vm->pid, &pctx) == -1) {
+        virReportSystemError(conn, errno,
+                             _("unable to get PID %d security context"), vm->pid);
+        return -1;
+    }
+
+    ctx = context_new(pctx);
+    VIR_FREE(pctx);
+    if (!ctx)
+        goto err;
+
+    mcs = context_range_get(ctx);
+    if (!mcs)
+        goto err;
+
+    mcsAdd(mcs);
+
+    context_free(ctx);
+
+    return 0;
+
+err:
+    context_free(ctx);
+    return -1;
+}
+
+
+
+static int
+SELinuxSecurityDriverProbe(void)
+{
+    return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
+}
+
+static int
+SELinuxSecurityDriverOpen(virConnectPtr conn, virSecurityDriverPtr drv)
+{
+    /*
+     * Where will the DOI come from?  SELinux configuration, or qemu
+     * configuration? For the moment, we'll just set it to "0".
+     */
+    virSecurityDriverSetDOI(conn, drv, SECURITY_SELINUX_VOID_DOI);
+    return SELinuxInitialize(conn);
+}
+
+static int
+SELinuxGetSecurityLabel(virConnectPtr conn,
+                        virDomainObjPtr vm,
+                        virSecurityLabelPtr sec)
+{
+    security_context_t ctx;
+
+    if (getpidcon(vm->pid, &ctx) == -1) {
+        virReportSystemError(conn, errno,
+                             _("unable to get PID %d security context"),
+                             vm->pid);
+        return -1;
+    }
+
+    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
+        virSecurityReportError(conn, VIR_ERR_ERROR,
+                               _("security label exceeds "
+                                 "maximum lenth: %d"),
+                               VIR_SECURITY_LABEL_BUFLEN - 1);
+        return -1;
+    }
+
+    strcpy(sec->label, (char *) ctx);
+    free(ctx);
+
+    sec->enforcing = security_getenforce();
+    if (sec->enforcing == -1) {
+        virReportSystemError(conn, errno, "%s",
+                             _("error calling security_getenforce()"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon)
+{
+    security_context_t econ;
+
+    VIR_INFO("Setting SELinux context on '%s' to '%s'", path, tcon);
+
+    if (setfilecon(path, tcon) < 0) {
+        int setfilecon_errno = errno;
+
+        if (getfilecon(path, &econ) >= 0) {
+            if (STREQ(tcon, econ)) {
+                freecon(econ);
+                /* It's alright, there's nothing to change anyway. */
+                return 0;
+            }
+            freecon(econ);
+        }
+
+        /* if the error complaint is related to an image hosted on
+         * an nfs mount, or a usbfs/sysfs filesystem not supporting
+         * labelling, then just ignore it & hope for the best.
+         * The user hopefully set one of the neccessary SELinux
+         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
+         */
+        if (setfilecon_errno != EOPNOTSUPP) {
+            virReportSystemError(conn, setfilecon_errno,
+                                 _("unable to set security context '%s' on '%s'"),
+                                 tcon, path);
+            if (security_getenforce() == 1)
+                return -1;
+        } else {
+            VIR_INFO("Setting security context '%s' on '%s' not supported",
+                     tcon, path);
+        }
+    }
+    return 0;
+}
+
+static int
+SELinuxRestoreSecurityFileLabel(virConnectPtr conn,
+                                const char *path)
+{
+    struct stat buf;
+    security_context_t fcon = NULL;
+    int rc = -1;
+    int err;
+    char *newpath = NULL;
+
+    VIR_INFO("Restoring SELinux context on '%s'", path);
+
+    if ((err = virFileResolveLink(path, &newpath)) < 0) {
+        virReportSystemError(conn, err,
+                             _("cannot resolve symlink %s"), path);
+        goto err;
+    }
+
+    if (stat(newpath, &buf) != 0)
+        goto err;
+
+    if (matchpathcon(newpath, buf.st_mode, &fcon) == 0)  {
+        rc = SELinuxSetFilecon(conn, newpath, fcon);
+    }
+err:
+    VIR_FREE(fcon);
+    VIR_FREE(newpath);
+    return rc;
+}
+
+static int
+SELinuxRestoreSecurityImageLabel(virConnectPtr conn,
+                                 virDomainDiskDefPtr disk)
+{
+    /* Don't restore labels on readoly/shared disks, because
+     * other VMs may still be accessing these
+     * Alternatively we could iterate over all running
+     * domains and try to figure out if it is in use, but
+     * this would not work for clustered filesystems, since
+     * we can't see running VMs using the file on other nodes
+     * Safest bet is thus to skip the restore step.
+     */
+    if (disk->readonly || disk->shared)
+        return 0;
+
+    if (!disk->src)
+        return 0;
+
+    return SELinuxRestoreSecurityFileLabel(conn, disk->src);
+}
+
+static int
+SELinuxSetSecurityImageLabel(virConnectPtr conn,
+                             virDomainObjPtr vm,
+                             virDomainDiskDefPtr disk)
+
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+
+    if (!disk->src)
+        return 0;
+
+    if (disk->shared) {
+        return SELinuxSetFilecon(conn, disk->src, default_image_context);
+    } else if (disk->readonly) {
+        return SELinuxSetFilecon(conn, disk->src, default_content_context);
+    } else if (secdef->imagelabel) {
+        return SELinuxSetFilecon(conn, disk->src, secdef->imagelabel);
+    }
+
+    return 0;
+}
+
+
+static int
+SELinuxSetSecurityPCILabel(virConnectPtr conn,
+                           pciDevice *dev ATTRIBUTE_UNUSED,
+                           const char *file, void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+
+    return SELinuxSetFilecon(conn, file, secdef->imagelabel);
+}
+
+static int
+SELinuxSetSecurityUSBLabel(virConnectPtr conn,
+                           usbDevice *dev ATTRIBUTE_UNUSED,
+                           const char *file, void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+
+    return SELinuxSetFilecon(conn, file, secdef->imagelabel);
+}
+
+static int
+SELinuxSetSecurityHostdevLabel(virConnectPtr conn,
+                               virDomainObjPtr vm,
+                               virDomainHostdevDefPtr dev)
+
+{
+    int ret = -1;
+
+    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+        return 0;
+
+    switch (dev->source.subsys.type) {
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
+        if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) {
+            usbDevice *usb = usbGetDevice(conn,
+                                          dev->source.subsys.u.usb.bus,
+                                          dev->source.subsys.u.usb.device);
+
+            if (!usb)
+                goto done;
+
+            ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm);
+            usbFreeDevice(conn, usb);
+
+            break;
+        } else {
+            /* XXX deal with product/vendor better */
+            ret = 0;
+        }
+    }
+
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
+        pciDevice *pci = pciGetDevice(conn,
+                                      dev->source.subsys.u.pci.domain,
+                                      dev->source.subsys.u.pci.bus,
+                                      dev->source.subsys.u.pci.slot,
+                                      dev->source.subsys.u.pci.function);
+
+        if (!pci)
+            goto done;
+
+        ret = pciDeviceFileIterate(conn, pci, SELinuxSetSecurityPCILabel, vm);
+        pciFreeDevice(conn, pci);
+
+        break;
+    }
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    return ret;
+}
+
+static int
+SELinuxRestoreSecurityPCILabel(virConnectPtr conn,
+                               pciDevice *dev ATTRIBUTE_UNUSED,
+                               const char *file,
+                               void *opaque ATTRIBUTE_UNUSED)
+{
+    return SELinuxRestoreSecurityFileLabel(conn, file);
+}
+
+static int
+SELinuxRestoreSecurityUSBLabel(virConnectPtr conn,
+                               usbDevice *dev ATTRIBUTE_UNUSED,
+                               const char *file,
+                               void *opaque ATTRIBUTE_UNUSED)
+{
+    return SELinuxRestoreSecurityFileLabel(conn, file);
+}
+
+static int
+SELinuxRestoreSecurityHostdevLabel(virConnectPtr conn,
+                                   virDomainHostdevDefPtr dev)
+
+{
+    int ret = -1;
+
+    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+        return 0;
+
+    switch (dev->source.subsys.type) {
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
+        usbDevice *usb = usbGetDevice(conn,
+                                      dev->source.subsys.u.usb.bus,
+                                      dev->source.subsys.u.usb.device);
+
+        if (!usb)
+            goto done;
+
+        ret = usbDeviceFileIterate(conn, usb, SELinuxRestoreSecurityUSBLabel, NULL);
+        usbFreeDevice(conn, usb);
+
+        break;
+    }
+
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
+        pciDevice *pci = pciGetDevice(conn,
+                                      dev->source.subsys.u.pci.domain,
+                                      dev->source.subsys.u.pci.bus,
+                                      dev->source.subsys.u.pci.slot,
+                                      dev->source.subsys.u.pci.function);
+
+        if (!pci)
+            goto done;
+
+        ret = pciDeviceFileIterate(conn, pci, SELinuxRestoreSecurityPCILabel, NULL);
+        pciFreeDevice(conn, pci);
+
+        break;
+    }
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    return ret;
+}
+
+static int
+SELinuxRestoreSecurityLabel(virConnectPtr conn,
+                            virDomainObjPtr vm)
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    int i;
+    int rc = 0;
+
+    VIR_DEBUG("Restoring security label on %s", vm->def->name);
+
+    if (secdef->imagelabel) {
+        for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+            if (SELinuxRestoreSecurityHostdevLabel(conn, vm->def->hostdevs[i]) < 0)
+                rc = -1;
+        }
+        for (i = 0 ; i < vm->def->ndisks ; i++) {
+            if (SELinuxRestoreSecurityImageLabel(conn, vm->def->disks[i]) < 0)
+                rc = -1;
+        }
+        VIR_FREE(secdef->model);
+        VIR_FREE(secdef->label);
+        context_t con = context_new(secdef->imagelabel);
+        if (con) {
+            mcsRemove(context_range_get(con));
+            context_free(con);
+        }
+        VIR_FREE(secdef->imagelabel);
+    }
+    return rc;
+}
+
+static int
+SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def)
+{
+    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
+        if (security_check_context(secdef->label) != 0) {
+            virSecurityReportError(conn, VIR_ERR_XML_ERROR,
+                                   _("Invalid security label %s"), secdef->label);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int
+SELinuxSetSecurityLabel(virConnectPtr conn,
+                        virSecurityDriverPtr drv,
+                        virDomainObjPtr vm)
+{
+    /* TODO: verify DOI */
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    int i;
+
+    if (!STREQ(drv->name, secdef->model)) {
+        virSecurityReportError(conn, VIR_ERR_ERROR,
+                               _("security label driver mismatch: "
+                                 "'%s' model configured for domain, but "
+                                 "hypervisor driver is '%s'."),
+                               secdef->model, drv->name);
+        if (security_getenforce() == 1)
+            return -1;
+    }
+
+    if (setexeccon(secdef->label) == -1) {
+        virReportSystemError(conn, errno,
+                             _("unable to set security context '%s'"),
+                             secdef->label);
+        if (security_getenforce() == 1)
+            return -1;
+    }
+
+    if (secdef->imagelabel) {
+        for (i = 0 ; i < vm->def->ndisks ; i++) {
+            if (SELinuxSetSecurityImageLabel(conn, vm, vm->def->disks[i]) < 0)
+                return -1;
+        }
+        for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+            if (SELinuxSetSecurityHostdevLabel(conn, vm, vm->def->hostdevs[i]) < 0)
+                return -1;
+        }
+    }
+
+    return 0;
+}
+
+virSecurityDriver virSELinuxSecurityDriver = {
+    .name                       = SECURITY_SELINUX_NAME,
+    .probe                      = SELinuxSecurityDriverProbe,
+    .open                       = SELinuxSecurityDriverOpen,
+    .domainSecurityVerify       = SELinuxSecurityVerify,
+    .domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
+    .domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
+    .domainGenSecurityLabel     = SELinuxGenSecurityLabel,
+    .domainReserveSecurityLabel     = SELinuxReserveSecurityLabel,
+    .domainGetSecurityLabel     = SELinuxGetSecurityLabel,
+    .domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel,
+    .domainSetSecurityLabel     = SELinuxSetSecurityLabel,
+    .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
+    .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
+};
diff --git a/src/security/security_selinux.h b/src/security/security_selinux.h
new file mode 100644 (file)
index 0000000..1e32209
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2008 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.
+ *
+ * Authors:
+ *     James Morris <jmorris@namei.org>
+ *
+ */
+#ifndef __VIR_SECURITY_SELINUX_H__
+#define __VIR_SECURITY_SELINUX_H__
+
+extern virSecurityDriver virSELinuxSecurityDriver;
+
+#endif /* __VIR_SECURITY_SELINUX_H__ */
diff --git a/src/security_selinux.c b/src/security_selinux.c
deleted file mode 100644 (file)
index bc295b1..0000000
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * Copyright (C) 2008,2009 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.
- *
- * Authors:
- *     James Morris <jmorris@namei.org>
- *     Dan Walsh <dwalsh@redhat.com>
- *
- * SELinux security driver.
- */
-#include <config.h>
-#include <selinux/selinux.h>
-#include <selinux/context.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "security.h"
-#include "security_selinux.h"
-#include "virterror_internal.h"
-#include "util.h"
-#include "memory.h"
-#include "logging.h"
-#include "pci.h"
-#include "hostusb.h"
-
-#define VIR_FROM_THIS VIR_FROM_SECURITY
-
-static char default_domain_context[1024];
-static char default_content_context[1024];
-static char default_image_context[1024];
-#define SECURITY_SELINUX_VOID_DOI       "0"
-#define SECURITY_SELINUX_NAME "selinux"
-
-/* TODO
-   The data struct of used mcs should be replaced with a better data structure in the future
-*/
-
-struct MCS {
-    char *mcs;
-    struct MCS *next;
-};
-static struct MCS *mcsList = NULL;
-
-static int
-mcsAdd(const char *mcs)
-{
-    struct MCS *ptr;
-
-    for (ptr = mcsList; ptr; ptr = ptr->next) {
-        if (STREQ(ptr->mcs, mcs))
-            return -1;
-    }
-    if (VIR_ALLOC(ptr) < 0)
-        return -1;
-    ptr->mcs = strdup(mcs);
-    ptr->next = mcsList;
-    mcsList = ptr;
-    return 0;
-}
-
-static int
-mcsRemove(const char *mcs)
-{
-    struct MCS *prevptr = NULL;
-    struct MCS *ptr = NULL;
-
-    for (ptr = mcsList; ptr; ptr = ptr->next) {
-        if (STREQ(ptr->mcs, mcs)) {
-            if (prevptr)
-                prevptr->next = ptr->next;
-            else {
-                mcsList = ptr->next;
-            }
-            free(ptr->mcs);
-            free(ptr);
-            return 0;
-        }
-        prevptr = ptr;
-    }
-    return -1;
-}
-
-static char *
-SELinuxGenNewContext(const char *oldcontext, const char *mcs)
-{
-    char *newcontext = NULL;
-    char *scontext = strdup(oldcontext);
-    if (!scontext) goto err;
-    context_t con = context_new(scontext);
-    if (!con) goto err;
-    context_range_set(con, mcs);
-    newcontext = strdup(context_str(con));
-    context_free(con);
-err:
-    freecon(scontext);
-    return (newcontext);
-}
-
-static int
-SELinuxInitialize(virConnectPtr conn)
-{
-    char *ptr = NULL;
-    int fd = 0;
-
-    virRandomInitialize(time(NULL) ^ getpid());
-
-    fd = open(selinux_virtual_domain_context_path(), O_RDONLY);
-    if (fd < 0) {
-        virReportSystemError(conn, errno,
-                             _("cannot open SELinux virtual domain context file '%s'"),
-                             selinux_virtual_domain_context_path());
-        return -1;
-    }
-
-    if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) {
-        virReportSystemError(conn, errno,
-                             _("cannot read SELinux virtual domain context file %s"),
-                             selinux_virtual_domain_context_path());
-        close(fd);
-        return -1;
-    }
-    close(fd);
-
-    ptr = strchrnul(default_domain_context, '\n');
-    *ptr = '\0';
-
-    if ((fd = open(selinux_virtual_image_context_path(), O_RDONLY)) < 0) {
-        virReportSystemError(conn, errno,
-                             _("cannot open SELinux virtual image context file %s"),
-                             selinux_virtual_image_context_path());
-        return -1;
-    }
-
-    if (saferead(fd, default_image_context, sizeof(default_image_context)) < 0) {
-        virReportSystemError(conn, errno,
-                             _("cannot read SELinux virtual image context file %s"),
-                             selinux_virtual_image_context_path());
-        close(fd);
-        return -1;
-    }
-    close(fd);
-
-    ptr = strchrnul(default_image_context, '\n');
-    if (*ptr == '\n') {
-        *ptr = '\0';
-        strcpy(default_content_context, ptr+1);
-        ptr = strchrnul(default_content_context, '\n');
-        if (*ptr == '\n')
-            *ptr = '\0';
-    }
-    return 0;
-}
-
-static int
-SELinuxGenSecurityLabel(virConnectPtr conn,
-                        virDomainObjPtr vm)
-{
-    int rc = -1;
-    char mcs[1024];
-    char *scontext = NULL;
-    int c1 = 0;
-    int c2 = 0;
-
-    if (vm->def->seclabel.label ||
-        vm->def->seclabel.model ||
-        vm->def->seclabel.imagelabel) {
-        virSecurityReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                               "%s", _("security label already defined for VM"));
-        return rc;
-    }
-
-    do {
-        c1 = virRandom(1024);
-        c2 = virRandom(1024);
-
-        if ( c1 == c2 ) {
-            sprintf(mcs, "s0:c%d", c1);
-        } else {
-            if ( c1 < c2 )
-                sprintf(mcs, "s0:c%d,c%d", c1, c2);
-            else
-                sprintf(mcs, "s0:c%d,c%d", c2, c1);
-        }
-    } while(mcsAdd(mcs) == -1);
-
-    vm->def->seclabel.label = SELinuxGenNewContext(default_domain_context, mcs);
-    if (! vm->def->seclabel.label)  {
-        virSecurityReportError(conn, VIR_ERR_ERROR,
-                               _("cannot generate selinux context for %s"), mcs);
-        goto err;
-    }
-    vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
-    if (! vm->def->seclabel.imagelabel)  {
-        virSecurityReportError(conn, VIR_ERR_ERROR,
-                               _("cannot generate selinux context for %s"), mcs);
-        goto err;
-    }
-    vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME);
-    if (!vm->def->seclabel.model) {
-        virReportOOMError(conn);
-        goto err;
-    }
-
-
-    rc = 0;
-    goto done;
-err:
-    VIR_FREE(vm->def->seclabel.label);
-    VIR_FREE(vm->def->seclabel.imagelabel);
-    VIR_FREE(vm->def->seclabel.model);
-done:
-    VIR_FREE(scontext);
-    return rc;
-}
-
-static int
-SELinuxReserveSecurityLabel(virConnectPtr conn,
-                            virDomainObjPtr vm)
-{
-    security_context_t pctx;
-    context_t ctx = NULL;
-    const char *mcs;
-
-    if (getpidcon(vm->pid, &pctx) == -1) {
-        virReportSystemError(conn, errno,
-                             _("unable to get PID %d security context"), vm->pid);
-        return -1;
-    }
-
-    ctx = context_new(pctx);
-    VIR_FREE(pctx);
-    if (!ctx)
-        goto err;
-
-    mcs = context_range_get(ctx);
-    if (!mcs)
-        goto err;
-
-    mcsAdd(mcs);
-
-    context_free(ctx);
-
-    return 0;
-
-err:
-    context_free(ctx);
-    return -1;
-}
-
-
-
-static int
-SELinuxSecurityDriverProbe(void)
-{
-    return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
-}
-
-static int
-SELinuxSecurityDriverOpen(virConnectPtr conn, virSecurityDriverPtr drv)
-{
-    /*
-     * Where will the DOI come from?  SELinux configuration, or qemu
-     * configuration? For the moment, we'll just set it to "0".
-     */
-    virSecurityDriverSetDOI(conn, drv, SECURITY_SELINUX_VOID_DOI);
-    return SELinuxInitialize(conn);
-}
-
-static int
-SELinuxGetSecurityLabel(virConnectPtr conn,
-                        virDomainObjPtr vm,
-                        virSecurityLabelPtr sec)
-{
-    security_context_t ctx;
-
-    if (getpidcon(vm->pid, &ctx) == -1) {
-        virReportSystemError(conn, errno,
-                             _("unable to get PID %d security context"),
-                             vm->pid);
-        return -1;
-    }
-
-    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
-        virSecurityReportError(conn, VIR_ERR_ERROR,
-                               _("security label exceeds "
-                                 "maximum lenth: %d"),
-                               VIR_SECURITY_LABEL_BUFLEN - 1);
-        return -1;
-    }
-
-    strcpy(sec->label, (char *) ctx);
-    free(ctx);
-
-    sec->enforcing = security_getenforce();
-    if (sec->enforcing == -1) {
-        virReportSystemError(conn, errno, "%s",
-                             _("error calling security_getenforce()"));
-        return -1;
-    }
-
-    return 0;
-}
-
-static int
-SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon)
-{
-    security_context_t econ;
-
-    VIR_INFO("Setting SELinux context on '%s' to '%s'", path, tcon);
-
-    if (setfilecon(path, tcon) < 0) {
-        int setfilecon_errno = errno;
-
-        if (getfilecon(path, &econ) >= 0) {
-            if (STREQ(tcon, econ)) {
-                freecon(econ);
-                /* It's alright, there's nothing to change anyway. */
-                return 0;
-            }
-            freecon(econ);
-        }
-
-        /* if the error complaint is related to an image hosted on
-         * an nfs mount, or a usbfs/sysfs filesystem not supporting
-         * labelling, then just ignore it & hope for the best.
-         * The user hopefully set one of the neccessary SELinux
-         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
-         */
-        if (setfilecon_errno != EOPNOTSUPP) {
-            virReportSystemError(conn, setfilecon_errno,
-                                 _("unable to set security context '%s' on '%s'"),
-                                 tcon, path);
-            if (security_getenforce() == 1)
-                return -1;
-        } else {
-            VIR_INFO("Setting security context '%s' on '%s' not supported",
-                     tcon, path);
-        }
-    }
-    return 0;
-}
-
-static int
-SELinuxRestoreSecurityFileLabel(virConnectPtr conn,
-                                const char *path)
-{
-    struct stat buf;
-    security_context_t fcon = NULL;
-    int rc = -1;
-    int err;
-    char *newpath = NULL;
-
-    VIR_INFO("Restoring SELinux context on '%s'", path);
-
-    if ((err = virFileResolveLink(path, &newpath)) < 0) {
-        virReportSystemError(conn, err,
-                             _("cannot resolve symlink %s"), path);
-        goto err;
-    }
-
-    if (stat(newpath, &buf) != 0)
-        goto err;
-
-    if (matchpathcon(newpath, buf.st_mode, &fcon) == 0)  {
-        rc = SELinuxSetFilecon(conn, newpath, fcon);
-    }
-err:
-    VIR_FREE(fcon);
-    VIR_FREE(newpath);
-    return rc;
-}
-
-static int
-SELinuxRestoreSecurityImageLabel(virConnectPtr conn,
-                                 virDomainDiskDefPtr disk)
-{
-    /* Don't restore labels on readoly/shared disks, because
-     * other VMs may still be accessing these
-     * Alternatively we could iterate over all running
-     * domains and try to figure out if it is in use, but
-     * this would not work for clustered filesystems, since
-     * we can't see running VMs using the file on other nodes
-     * Safest bet is thus to skip the restore step.
-     */
-    if (disk->readonly || disk->shared)
-        return 0;
-
-    if (!disk->src)
-        return 0;
-
-    return SELinuxRestoreSecurityFileLabel(conn, disk->src);
-}
-
-static int
-SELinuxSetSecurityImageLabel(virConnectPtr conn,
-                             virDomainObjPtr vm,
-                             virDomainDiskDefPtr disk)
-
-{
-    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-
-    if (!disk->src)
-        return 0;
-
-    if (disk->shared) {
-        return SELinuxSetFilecon(conn, disk->src, default_image_context);
-    } else if (disk->readonly) {
-        return SELinuxSetFilecon(conn, disk->src, default_content_context);
-    } else if (secdef->imagelabel) {
-        return SELinuxSetFilecon(conn, disk->src, secdef->imagelabel);
-    }
-
-    return 0;
-}
-
-
-static int
-SELinuxSetSecurityPCILabel(virConnectPtr conn,
-                           pciDevice *dev ATTRIBUTE_UNUSED,
-                           const char *file, void *opaque)
-{
-    virDomainObjPtr vm = opaque;
-    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-
-    return SELinuxSetFilecon(conn, file, secdef->imagelabel);
-}
-
-static int
-SELinuxSetSecurityUSBLabel(virConnectPtr conn,
-                           usbDevice *dev ATTRIBUTE_UNUSED,
-                           const char *file, void *opaque)
-{
-    virDomainObjPtr vm = opaque;
-    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-
-    return SELinuxSetFilecon(conn, file, secdef->imagelabel);
-}
-
-static int
-SELinuxSetSecurityHostdevLabel(virConnectPtr conn,
-                               virDomainObjPtr vm,
-                               virDomainHostdevDefPtr dev)
-
-{
-    int ret = -1;
-
-    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-        return 0;
-
-    switch (dev->source.subsys.type) {
-    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
-        if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) {
-            usbDevice *usb = usbGetDevice(conn,
-                                          dev->source.subsys.u.usb.bus,
-                                          dev->source.subsys.u.usb.device);
-
-            if (!usb)
-                goto done;
-
-            ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm);
-            usbFreeDevice(conn, usb);
-
-            break;
-        } else {
-            /* XXX deal with product/vendor better */
-            ret = 0;
-        }
-    }
-
-    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
-        pciDevice *pci = pciGetDevice(conn,
-                                      dev->source.subsys.u.pci.domain,
-                                      dev->source.subsys.u.pci.bus,
-                                      dev->source.subsys.u.pci.slot,
-                                      dev->source.subsys.u.pci.function);
-
-        if (!pci)
-            goto done;
-
-        ret = pciDeviceFileIterate(conn, pci, SELinuxSetSecurityPCILabel, vm);
-        pciFreeDevice(conn, pci);
-
-        break;
-    }
-
-    default:
-        ret = 0;
-        break;
-    }
-
-done:
-    return ret;
-}
-
-static int
-SELinuxRestoreSecurityPCILabel(virConnectPtr conn,
-                               pciDevice *dev ATTRIBUTE_UNUSED,
-                               const char *file,
-                               void *opaque ATTRIBUTE_UNUSED)
-{
-    return SELinuxRestoreSecurityFileLabel(conn, file);
-}
-
-static int
-SELinuxRestoreSecurityUSBLabel(virConnectPtr conn,
-                               usbDevice *dev ATTRIBUTE_UNUSED,
-                               const char *file,
-                               void *opaque ATTRIBUTE_UNUSED)
-{
-    return SELinuxRestoreSecurityFileLabel(conn, file);
-}
-
-static int
-SELinuxRestoreSecurityHostdevLabel(virConnectPtr conn,
-                                   virDomainHostdevDefPtr dev)
-
-{
-    int ret = -1;
-
-    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-        return 0;
-
-    switch (dev->source.subsys.type) {
-    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
-        usbDevice *usb = usbGetDevice(conn,
-                                      dev->source.subsys.u.usb.bus,
-                                      dev->source.subsys.u.usb.device);
-
-        if (!usb)
-            goto done;
-
-        ret = usbDeviceFileIterate(conn, usb, SELinuxRestoreSecurityUSBLabel, NULL);
-        usbFreeDevice(conn, usb);
-
-        break;
-    }
-
-    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
-        pciDevice *pci = pciGetDevice(conn,
-                                      dev->source.subsys.u.pci.domain,
-                                      dev->source.subsys.u.pci.bus,
-                                      dev->source.subsys.u.pci.slot,
-                                      dev->source.subsys.u.pci.function);
-
-        if (!pci)
-            goto done;
-
-        ret = pciDeviceFileIterate(conn, pci, SELinuxRestoreSecurityPCILabel, NULL);
-        pciFreeDevice(conn, pci);
-
-        break;
-    }
-
-    default:
-        ret = 0;
-        break;
-    }
-
-done:
-    return ret;
-}
-
-static int
-SELinuxRestoreSecurityLabel(virConnectPtr conn,
-                            virDomainObjPtr vm)
-{
-    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-    int i;
-    int rc = 0;
-
-    VIR_DEBUG("Restoring security label on %s", vm->def->name);
-
-    if (secdef->imagelabel) {
-        for (i = 0 ; i < vm->def->nhostdevs ; i++) {
-            if (SELinuxRestoreSecurityHostdevLabel(conn, vm->def->hostdevs[i]) < 0)
-                rc = -1;
-        }
-        for (i = 0 ; i < vm->def->ndisks ; i++) {
-            if (SELinuxRestoreSecurityImageLabel(conn, vm->def->disks[i]) < 0)
-                rc = -1;
-        }
-        VIR_FREE(secdef->model);
-        VIR_FREE(secdef->label);
-        context_t con = context_new(secdef->imagelabel);
-        if (con) {
-            mcsRemove(context_range_get(con));
-            context_free(con);
-        }
-        VIR_FREE(secdef->imagelabel);
-    }
-    return rc;
-}
-
-static int
-SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def)
-{
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
-        if (security_check_context(secdef->label) != 0) {
-            virSecurityReportError(conn, VIR_ERR_XML_ERROR,
-                                   _("Invalid security label %s"), secdef->label);
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static int
-SELinuxSetSecurityLabel(virConnectPtr conn,
-                        virSecurityDriverPtr drv,
-                        virDomainObjPtr vm)
-{
-    /* TODO: verify DOI */
-    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-    int i;
-
-    if (!STREQ(drv->name, secdef->model)) {
-        virSecurityReportError(conn, VIR_ERR_ERROR,
-                               _("security label driver mismatch: "
-                                 "'%s' model configured for domain, but "
-                                 "hypervisor driver is '%s'."),
-                               secdef->model, drv->name);
-        if (security_getenforce() == 1)
-            return -1;
-    }
-
-    if (setexeccon(secdef->label) == -1) {
-        virReportSystemError(conn, errno,
-                             _("unable to set security context '%s'"),
-                             secdef->label);
-        if (security_getenforce() == 1)
-            return -1;
-    }
-
-    if (secdef->imagelabel) {
-        for (i = 0 ; i < vm->def->ndisks ; i++) {
-            if (SELinuxSetSecurityImageLabel(conn, vm, vm->def->disks[i]) < 0)
-                return -1;
-        }
-        for (i = 0 ; i < vm->def->nhostdevs ; i++) {
-            if (SELinuxSetSecurityHostdevLabel(conn, vm, vm->def->hostdevs[i]) < 0)
-                return -1;
-        }
-    }
-
-    return 0;
-}
-
-virSecurityDriver virSELinuxSecurityDriver = {
-    .name                       = SECURITY_SELINUX_NAME,
-    .probe                      = SELinuxSecurityDriverProbe,
-    .open                       = SELinuxSecurityDriverOpen,
-    .domainSecurityVerify       = SELinuxSecurityVerify,
-    .domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
-    .domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
-    .domainGenSecurityLabel     = SELinuxGenSecurityLabel,
-    .domainReserveSecurityLabel     = SELinuxReserveSecurityLabel,
-    .domainGetSecurityLabel     = SELinuxGetSecurityLabel,
-    .domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel,
-    .domainSetSecurityLabel     = SELinuxSetSecurityLabel,
-    .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
-    .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
-};
diff --git a/src/security_selinux.h b/src/security_selinux.h
deleted file mode 100644 (file)
index 1e32209..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- *
- * Authors:
- *     James Morris <jmorris@namei.org>
- *
- */
-#ifndef __VIR_SECURITY_SELINUX_H__
-#define __VIR_SECURITY_SELINUX_H__
-
-extern virSecurityDriver virSELinuxSecurityDriver;
-
-#endif /* __VIR_SECURITY_SELINUX_H__ */
index fe83db856aaa272ed7ab7c18374427c2dabacd75..26d1f86f90cc1404d8c8ad31e2a00f9efd455bff 100644 (file)
@@ -5,7 +5,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
-#include "security.h"
+#include "security/security_driver.h"
 
 int
 main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)