[libvirt] [PATCH 2/3] virfile: Introduce internal API for managing ACL

Michal Privoznik mprivozn at redhat.com
Wed Aug 28 10:27:39 UTC 2013


For now, only three APIs are implemented:
virFileGetACL to retrieve permission for a specific user
virFileSetACL for setting requested permissions for a specific user,
virFileRemoveACL to remove those permissions.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 configure.ac             |   2 +
 libvirt.spec.in          |   1 +
 m4/virt-acl.m4           |   9 +++
 src/Makefile.am          |   4 +-
 src/libvirt_private.syms |   3 +
 src/util/virfile.c       | 190 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virfile.h       |  15 ++++
 7 files changed, 222 insertions(+), 2 deletions(-)
 create mode 100644 m4/virt-acl.m4

diff --git a/configure.ac b/configure.ac
index 94a2e19..7d4affd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,7 @@ LIBVIRT_COMPILE_PIE
 LIBVIRT_LINKER_RELRO
 LIBVIRT_LINKER_NO_INDIRECT
 
+LIBVIRT_CHECK_ACL
 LIBVIRT_CHECK_APPARMOR
 LIBVIRT_CHECK_ATTR
 LIBVIRT_CHECK_AUDIT
@@ -2589,6 +2590,7 @@ fi
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([Libraries])
 AC_MSG_NOTICE([])
+LIBVIRT_RESULT_ACL
 LIBVIRT_RESULT_APPARMOR
 LIBVIRT_RESULT_ATTR
 LIBVIRT_RESULT_AUDIT
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 85881ae..50f40d8 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -443,6 +443,7 @@ BuildRequires: libgcrypt-devel
 %endif
 BuildRequires: gnutls-devel
 BuildRequires: libattr-devel
+BuildRequires: lobacl-devel
 %if %{with_libvirtd}
 # For pool-build probing for existing pools
 BuildRequires: libblkid-devel >= 2.17
diff --git a/m4/virt-acl.m4 b/m4/virt-acl.m4
new file mode 100644
index 0000000..7f16dca
--- /dev/null
+++ b/m4/virt-acl.m4
@@ -0,0 +1,9 @@
+dnl The libacl.so library
+
+AC_DEFUN([LIBVIRT_CHECK_ACL],[
+  LIBVIRT_CHECK_LIB([ACL], [acl], [acl_init], [sys/acl.h])
+])
+
+AC_DEFUN([LIBVIRT_RESULT_ACL],[
+  LIBVIRT_RESULT_LIB([ACL])
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index d8b943d..6aceee3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -901,12 +901,12 @@ libvirt_util_la_SOURCES =					\
 		$(UTIL_SOURCES)
 libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
 		$(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \
-		$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS)	\
+		$(DBUS_CFLAGS) $(LDEXP_LIBM) $(NUMACTL_CFLAGS)	$(ACL_CFLAGS) \
 		-I$(top_srcdir)/src/conf
 libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
 		$(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \
 		$(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \
-		$(SECDRIVER_LIBS) $(NUMACTL_LIBS)
+		$(SECDRIVER_LIBS) $(NUMACTL_LIBS) $(ACL_LIBS)
 
 
 noinst_LTLIBRARIES += libvirt_conf.la
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c1a51b2..af3bdb6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1369,6 +1369,7 @@ virFileExists;
 virFileFclose;
 virFileFdopen;
 virFileFindMountPoint;
+virFileGetACL;
 virFileGetAttr;
 virFileHasSuffix;
 virFileIsAbsPath;
@@ -1387,11 +1388,13 @@ virFileOpenTty;
 virFilePrintf;
 virFileReadAll;
 virFileReadLimFD;
+virFileRemoveACL;
 virFileRemoveAttr;
 virFileResolveAllLinks;
 virFileResolveLink;
 virFileRewrite;
 virFileSanitizePath;
+virFileSetACL;
 virFileSetAttr;
 virFileSkipRoot;
 virFileStripSuffix;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 064ea2f..fe055d1 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -52,6 +52,10 @@
 # include <attr/xattr.h>
 #endif
 
+#ifdef WITH_ACL
+# include <acl/libacl.h>
+#endif
+
 #include "configmake.h"
 #include "viralloc.h"
 #include "vircommand.h"
@@ -2473,3 +2477,189 @@ virFileRemoveAttr(const char *file ATTRIBUTE_UNUSED,
     return -1;
 }
 #endif /* WITH_ATTR */
+
+#ifdef WITH_ACL
+static acl_entry_t
+virFileACLFindEntry(acl_t acl, acl_tag_t type, id_t id)
+{
+    acl_entry_t ent;
+    acl_tag_t e_type;
+    id_t *e_id_p;
+
+    /* acl_get_entry returns 1 if there's an entry in @acl */
+    if (acl_get_entry(acl, ACL_FIRST_ENTRY, &ent) != 1)
+        return NULL;
+
+    do {
+        acl_get_tag_type(ent, &e_type);
+        if (e_type == type) {
+            if (id == ACL_UNDEFINED_ID)
+                return ent;
+
+            if (!(e_id_p = acl_get_qualifier(ent)))
+                return NULL;
+            if (*e_id_p == id) {
+                acl_free(e_id_p);
+                return ent;
+            }
+            acl_free(e_id_p);
+        }
+    } while (acl_get_entry(acl, ACL_NEXT_ENTRY, &ent) == 1);
+
+    return NULL;
+}
+
+static void
+virFileACLSetPerms(acl_entry_t ent, mode_t perms)
+{
+    acl_permset_t set;
+
+    acl_get_permset(ent, &set);
+    if (perms & S_IRUSR)
+        acl_add_perm(set, ACL_READ);
+    else
+        acl_delete_perm(set, ACL_READ);
+    if (perms & S_IWUSR)
+        acl_add_perm(set, ACL_WRITE);
+    else
+        acl_delete_perm(set, ACL_WRITE);
+    if (perms & S_IXUSR)
+        acl_add_perm(set, ACL_EXECUTE);
+    else
+        acl_delete_perm(set, ACL_EXECUTE);
+}
+
+static void
+virFileACLGetPerms(acl_entry_t ent, mode_t *perms)
+{
+    acl_permset_t set;
+
+    *perms = 0;
+    acl_get_permset(ent, &set);
+    if (acl_get_perm(set, ACL_READ))
+        *perms |= S_IRUSR;
+    if (acl_get_perm(set, ACL_WRITE))
+        *perms |= S_IWUSR;
+    if (acl_get_perm(set, ACL_EXECUTE))
+        *perms |= S_IXUSR;
+}
+
+static int
+virFileACLSetOrRemove(const char *path,
+                      uid_t user,
+                      mode_t perms,
+                      bool set)
+{
+    int ret = -1;
+    acl_t acl;
+    acl_entry_t ent;
+
+    if (!(acl = acl_get_file(path, ACL_TYPE_ACCESS))) {
+        virReportSystemError(errno, _("Unable to get ACL on %s"), path);
+        return ret;
+    }
+
+    ent = virFileACLFindEntry(acl, ACL_USER, user);
+    if (set) {
+        if (!ent && acl_create_entry(&acl, &ent) < 0) {
+            virReportSystemError(errno, "%s", _("Unable to create ACL entity"));
+            goto cleanup;
+        }
+        acl_set_tag_type(ent, ACL_USER);
+        acl_set_qualifier(ent, &user);
+
+        virFileACLSetPerms(ent, perms);
+
+    } else if (ent) {
+        if (acl_delete_entry(acl, ent) < 0) {
+            virReportSystemError(errno, "%s", _("Unable to delete ACL entity"));
+            goto cleanup;
+        }
+    }
+
+    if ((ent = virFileACLFindEntry(acl, ACL_MASK, ACL_UNDEFINED_ID)) &&
+        acl_delete_entry(acl, ent) < 0) {
+        virReportSystemError(errno, "%s", _("Unable to delete ACL mask"));
+        goto cleanup;
+    }
+
+    if (acl_equiv_mode(acl, NULL) && acl_calc_mask(&acl) < 0) {
+        virReportSystemError(errno, "%s", _("Unable to calculate ACL mask"));
+        goto cleanup;
+    }
+
+    if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
+        virReportSystemError(errno, _("Unable to set ACL on %s"), path);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    acl_free(acl);
+    return ret;
+}
+
+int
+virFileSetACL(const char *file,
+              uid_t user,
+              mode_t perms)
+{
+    return virFileACLSetOrRemove(file, user, perms, true);
+}
+
+int
+virFileRemoveACL(const char *file,
+                 uid_t user)
+{
+    return virFileACLSetOrRemove(file, user, 0, false);
+}
+
+int
+virFileGetACL(const char *file,
+              uid_t user,
+              mode_t *perms)
+{
+    acl_t acl;
+    acl_entry_t ent;
+
+    if (!(acl = acl_get_file(file, ACL_TYPE_ACCESS))) {
+        virReportSystemError(errno, _("Unable to get ACL on %s"), file);
+        return -1;
+    }
+
+    if ((ent = virFileACLFindEntry(acl, ACL_USER, user)))
+        virFileACLGetPerms(ent, perms);
+    else
+        *perms = 0;
+
+    acl_free(acl);
+    return 0;
+}
+
+#else /* WITH_ACL */
+
+int
+virFileSetACL(const char *file ATTRIBUTE_UNUSED,
+              uid_t user ATTRIBUTE_UNUSED,
+              mode_t perms ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s", _("Unable to set ACL"));
+    return -1;
+}
+
+int
+virFileRemoveACL(const char *file ATTRIBUTE_UNUSED,
+                 uid_t user ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s", _("Unable to remove ACL"));
+    return -1;
+}
+int
+virFileGetACL(const char *file ATTRIBUTE_UNUSED,
+              uid_t user ATTRIBUTE_UNUSED,
+              mode_t *perms ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s", _("Unable to get ACL"));
+    return -1;
+}
+#endif /* WITH_ACL */
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 08c59b0..fcdf9fa 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -245,4 +245,19 @@ int virFileGetAttr(const char *file,
 int virFileRemoveAttr(const char *file,
                       const char *name)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int virFileSetACL(const char *file,
+                  uid_t user,
+                  mode_t perms)
+    ATTRIBUTE_NONNULL(1);
+
+int virFileGetACL(const char *file,
+                  uid_t user,
+                  mode_t *perms)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+
+int virFileRemoveACL(const char *file,
+                     uid_t user)
+    ATTRIBUTE_NONNULL(1);
+
 #endif /* __VIR_FILE_H */
-- 
1.8.1.5




More information about the libvir-list mailing list