]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Basic framework for auditing integration
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 15 Sep 2010 13:44:11 +0000 (14:44 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 19 Oct 2010 16:31:31 +0000 (17:31 +0100)
Integrate with libaudit.so for auditing of important operations.
libvirtd gains a couple of config entries for auditing. By
default it will enable auditing, if its enabled on the host.
It can be configured to force exit if auditing is disabled
on the host. It will can also send audit messages via libvirt
internal logging API

Places requiring audit reporting can use the VIR_AUDIT
macro to report data. This is a no-op unless auditing is
enabled

* autobuild.sh, mingw32-libvirt.spec.in: Disable audit
  on mingw
* configure.ac: Add check for libaudit
* daemon/libvirtd.aug, daemon/libvirtd.conf,
  daemon/test_libvirtd.aug, daemon/libvirtd.c: Add config
  options to enable auditing
* include/libvirt/virterror.h, src/util/virterror.c: Add
  VIR_FROM_AUDIT source
* libvirt.spec.in: Enable audit
* src/util/virtaudit.h, src/util/virtaudit.c: Simple internal
  API for auditing messages

14 files changed:
autobuild.sh
configure.ac
daemon/libvirtd.aug
daemon/libvirtd.c
daemon/libvirtd.conf
daemon/test_libvirtd.aug
include/libvirt/virterror.h
libvirt.spec.in
mingw32-libvirt.spec.in
po/POTFILES.in
src/Makefile.am
src/util/virtaudit.c [new file with mode: 0644]
src/util/virtaudit.h [new file with mode: 0644]
src/util/virterror.c

index c52747938ad45f17f259d18ee5f0a73cfd7b456d..844ce539944f26e4962254b77f50961bc75ff8e8 100755 (executable)
@@ -85,6 +85,7 @@ if [ -x /usr/bin/i686-pc-mingw32-gcc ]; then
     --without-one \
     --without-phyp \
     --without-netcf \
+    --without-audit \
     --without-libvirtd
 
   make
index 2803aa35ccf91f74ce324ca075163c2e14a131a8..d8c4d0d39c94dc9bac1758dfe7f5a19d98eaeccd 100644 (file)
@@ -911,6 +911,52 @@ AM_CONDITIONAL([HAVE_AVAHI], [test "x$with_avahi" = "xyes"])
 AC_SUBST([AVAHI_CFLAGS])
 AC_SUBST([AVAHI_LIBS])
 
+dnl Audit library
+AC_ARG_WITH([audit],
+  AC_HELP_STRING([--with-audit], [use audit library @<:@default=check@:>@]),
+  [],
+  [with_audit=check])
+
+AUDIT_CFLAGS=
+AUDIT_LIBS=
+if test "$with_audit" != "no" ; then
+  old_cflags="$CFLAGS"
+  old_libs="$LIBS"
+  if test "$with_audit" != "check" && "$with_audit" != "yes" ; then
+    AUDIT_CFLAGS="-I$with_audit/include"
+    AUDIT_LIBS="-L$with_audit/lib"
+  fi
+  CFLAGS="$CFLAGS $AUDIT_CFLAGS"
+  LIBS="$LIBS $AUDIT_LIBS"
+  fail=0
+  AC_CHECK_HEADER([libaudit.h], [], [fail=1])
+  AC_CHECK_LIB([audit], [audit_is_enabled], [], [fail=1])
+
+  if test $fail = 1 ; then
+    if test "$with_audit" = "yes" ; then
+      AC_MSG_ERROR([You must install the Audit library in order to compile and run libvirt])
+    else
+      with_audit=no
+      AUDIT_CFLAGS=
+      AUDIT_LIBS=
+    fi
+  else
+    with_audit=yes
+  fi
+
+  if test "$with_audit" = "yes" ; then
+    AUDIT_LIBS="$AUDIT_LIBS -laudit"
+    AC_DEFINE_UNQUOTED([HAVE_AUDIT], 1, [whether libaudit is available])
+  fi
+
+  CFLAGS="$old_cflags"
+  LIBS="$old_libs"
+fi
+AM_CONDITIONAL([HAVE_AUDIT], [test "$with_audit" = "yes"])
+AC_SUBST([AUDIT_CFLAGS])
+AC_SUBST([AUDIT_LIBS])
+
+
 dnl SELinux
 AC_ARG_WITH([selinux],
   AC_HELP_STRING([--with-selinux], [use SELinux to manage security @<:@default=check@:>@]),
@@ -2273,6 +2319,11 @@ fi
 else
 AC_MSG_NOTICE([  polkit: no])
 fi
+if test "$with_audit" = "yes" ; then
+AC_MSG_NOTICE([   audit: $AUDIT_CFLAGS $AUDIT_LIBS])
+else
+AC_MSG_NOTICE([   audit: no])
+fi
 if test "$with_selinux" = "yes" ; then
 AC_MSG_NOTICE([ selinux: $SELINUX_CFLAGS $SELINUX_LIBS])
 else
index 7406d238f81743b871f57c2f2ab15a3a877cbe78..0e061425daa448977c7d20ba9fc5832b3c55245c 100644 (file)
@@ -61,6 +61,9 @@ module Libvirtd =
                      | str_entry "log_filters"
                      | str_entry "log_outputs"
 
+   let auditing_entry = int_entry "audit_level"
+                      | bool_entry "audit_logging"
+
    (* Each enty in the config is one of the following three ... *)
    let entry = network_entry
              | sock_acl_entry
@@ -69,6 +72,7 @@ module Libvirtd =
              | authorization_entry
              | processing_entry
              | logging_entry
+             | auditing_entry
    let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
    let empty = [ label "#empty" . eol ]
 
index 1543481b07827b31bc95605244a037d790f449b4..88e85ec1ba49556859d2ffb4894a13b6cc5bd007 100644 (file)
@@ -64,6 +64,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "hooks.h"
+#include "virtaudit.h"
 #ifdef HAVE_AVAHI
 # include "mdns.h"
 #endif
@@ -187,6 +188,9 @@ static int max_requests = 20;
 /* Total number of 'in-process' RPC calls allowed by a single client*/
 static int max_client_requests = 5;
 
+static int audit_level = 1;
+static int audit_logging = 0;
+
 #define DH_BITS 1024
 
 static sig_atomic_t sig_errors = 0;
@@ -203,6 +207,7 @@ enum {
     VIR_DAEMON_ERR_NETWORK,
     VIR_DAEMON_ERR_CONFIG,
     VIR_DAEMON_ERR_HOOKS,
+    VIR_DAEMON_ERR_AUDIT,
 
     VIR_DAEMON_ERR_LAST
 };
@@ -217,7 +222,8 @@ VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
               "Unable to drop privileges",
               "Unable to initialize network sockets",
               "Unable to load configuration file",
-              "Unable to look for hook scripts")
+              "Unable to look for hook scripts",
+              "Unable to initialize audit system")
 
 static void sig_handler(int sig, siginfo_t * siginfo,
                         void* context ATTRIBUTE_UNUSED) {
@@ -2854,6 +2860,9 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename)
     GET_CONF_INT (conf, filename, max_requests);
     GET_CONF_INT (conf, filename, max_client_requests);
 
+    GET_CONF_INT (conf, filename, audit_level);
+    GET_CONF_INT (conf, filename, audit_logging);
+
     GET_CONF_STR (conf, filename, host_uuid);
     if (virSetHostUUIDStr(host_uuid)) {
         VIR_ERROR(_("invalid host UUID: %s"), host_uuid);
@@ -3194,6 +3203,16 @@ int main(int argc, char **argv) {
         goto error;
     }
 
+    if (audit_level) {
+        if (virAuditOpen() < 0) {
+            if (audit_level > 1) {
+                ret = VIR_DAEMON_ERR_AUDIT;
+                goto error;
+            }
+        }
+    }
+    virAuditLog(audit_logging);
+
     /* setup the hooks if any */
     if (virHookInitialize() < 0) {
         ret = VIR_DAEMON_ERR_HOOKS;
index d11c0fb083cf233d887d233427641a437f60ca3d..163a80fb03dc932f85e19e4b7dc230382ea8894e 100644 (file)
 # log_outputs="3:syslog:libvirtd"
 # to log all warnings and errors to syslog under the libvirtd ident
 
+
+##################################################################
+#
+# Auditing
+#
+# This setting allows usage of the auditing subsystem to be altered:
+#
+#   audit_level == 0  -> disable all auditing
+#   audit_level == 1  -> enable auditing, only if enabled on host (default)
+#   audit_level == 2  -> enable auditing, and exit if disabled on host
+#
+#audit_level = 2
+#
+# If set to 1, then audit messages will also be sent
+# via libvirt logging infrastructure. Defaults to 0
+#
+#audit_logging = 1
+
+###################################################################
 # UUID of the host:
 # Provide the UUID of the host here in case the command
 # 'dmidecode -s system-uuid' does not provide a valid uuid. In case
index b8da28e0122c143ba131777c1ce2e97c21115638..5f8b6446760af456c9494affdd53cf1c026a3c17 100644 (file)
@@ -268,6 +268,9 @@ log_outputs=\"4:stderr\"
 
 # Logging filters:
 log_filters=\"a\"
+
+# Auditing:
+audit_level = 2
 "
 
    test Libvirtd.lns get conf =
@@ -543,3 +546,6 @@ log_filters=\"a\"
        { "#empty" }
         { "#comment" = "Logging filters:" }
         { "log_filters" = "a" }
+       { "#empty" }
+        { "#comment" = "Auditing:" }
+        { "audit_level" = "2" }
index 3bbb293136ee99955b8f7fcf977178fdf9093fc7..94d686ce13014eca583242a689838fc0391b183b 100644 (file)
@@ -73,6 +73,7 @@ typedef enum {
     VIR_FROM_NWFILTER,  /* Error from network filter driver */
     VIR_FROM_HOOK,      /* Error from Synchronous hooks */
     VIR_FROM_DOMAIN_SNAPSHOT, /* Error from domain snapshot */
+    VIR_FROM_AUDIT      /* Error from auditing subsystem */
 } virErrorDomain;
 
 
index 55e368e6c22c3b1be06d945c73a1520a895f78df..93386fbe9e47f12f97f8bdaa59dc2d9e199561b6 100644 (file)
@@ -66,6 +66,7 @@
 %define with_libpcap       0%{!?_without_libpcap:0}
 %define with_macvtap       0%{!?_without_macvtap:0}
 %define with_libnl         0%{!?_without_libnl:0}
+%define with_audit         0%{!?_without_audit:0}
 
 # Non-server/HV driver defaults which are always enabled
 %define with_python        0%{!?_without_python:1}
 %define with_libnl 1
 %endif
 
+%if 0%{?fedora} >= 11 || 0%{?rhel} >= 5
+%define with_audit    0%{!?_without_audit:1}
+%endif
+
 # Force QEMU to run as non-root
 %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
 %define qemu_user  qemu
@@ -370,6 +375,9 @@ BuildRequires: netcf-devel >= 0.1.4
 %if %{with_esx}
 BuildRequires: libcurl-devel
 %endif
+%if %{with_audit}
+BuildRequires: audit-libs-devel
+%endif
 
 # Fedora build root suckage
 BuildRequires: gawk
@@ -552,6 +560,10 @@ of recent versions of Linux (and other OSes).
 %define _without_macvtap --without-macvtap
 %endif
 
+%if ! %{with_audit}
+%define _without_audit --without-audit
+%endif
+
 %configure %{?_without_xen} \
            %{?_without_qemu} \
            %{?_without_openvz} \
@@ -583,6 +595,7 @@ of recent versions of Linux (and other OSes).
            %{?_without_yajl} \
            %{?_without_libpcap} \
            %{?_without_macvtap} \
+           %{?_without_audit} \
            --with-qemu-user=%{qemu_user} \
            --with-qemu-group=%{qemu_group} \
            --with-init-script=redhat \
index 4bbbc3b1e418ffead6ab853dc2ddc546115c8543..e762c774cfd68c2c13fa07d4200c91df7f3d1966 100644 (file)
@@ -57,6 +57,7 @@ MinGW Windows libvirt virtualization library.
   --without-one \
   --without-phyp \
   --without-netcf \
+  --without-audit \
   --without-libvirtd
 make
 
index 8a148f3949421178b5a2cb3a5a71a908c7e74319..e30fea02696f43f52f49d796e8b44e12897e1677 100644 (file)
@@ -88,6 +88,7 @@ src/util/processinfo.c
 src/util/stats_linux.c
 src/util/storage_file.c
 src/util/util.c
+src/util/virtaudit.c
 src/util/virterror.c
 src/util/xml.c
 src/vbox/vbox_driver.c
index e386bfafaa9c066dd871250ec6289bc3abd9eca6..a10a33c588ca07181a6198b4152c6e74b799b8d3 100644 (file)
@@ -59,6 +59,7 @@ UTIL_SOURCES =                                                        \
                util/conf.c util/conf.h                         \
                util/cgroup.c util/cgroup.h                     \
                util/event.c util/event.h                       \
+               util/files.c util/files.h                       \
                util/hash.c util/hash.h                         \
                util/hooks.c util/hooks.h                       \
                util/iptables.c util/iptables.h                 \
@@ -82,8 +83,8 @@ UTIL_SOURCES =                                                        \
                util/uuid.c util/uuid.h                         \
                util/util.c util/util.h                         \
                util/xml.c util/xml.h                           \
-               util/virterror.c util/virterror_internal.h      \
-               util/files.c util/files.h
+               util/virtaudit.c util/virtaudit.h               \
+               util/virterror.c util/virterror_internal.h
 
 EXTRA_DIST += util/threads-pthread.c util/threads-win32.c
 
@@ -426,8 +427,9 @@ libvirt_la_BUILT_LIBADD = libvirt_util.la
 libvirt_util_la_SOURCES =                                      \
                $(UTIL_SOURCES)
 libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \
-               $(AM_CFLAGS)
-libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) $(LIB_PTHREAD)
+               $(AM_CFLAGS) $(AUDIT_CFLAGS)
+libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \
+               $(LIB_PTHREAD) $(AUDIT_LIBS)
 
 
 noinst_LTLIBRARIES += libvirt_conf.la
@@ -1120,12 +1122,13 @@ libvirt_lxc_SOURCES =                                           \
 libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS)
 libvirt_lxc_LDADD = $(CAPNG_LIBS) $(YAJL_LIBS) \
                $(LIBXML_LIBS) $(NUMACTL_LIBS) $(LIB_PTHREAD) \
-               $(LIBNL_LIBS) ../gnulib/lib/libgnu.la
+               $(LIBNL_LIBS) $(AUDIT_LIBS) ../gnulib/lib/libgnu.la
 libvirt_lxc_CFLAGS =                           \
                $(LIBPARTED_CFLAGS)             \
                $(NUMACTL_CFLAGS)               \
                $(CAPNG_CFLAGS)                 \
                $(YAJL_CFLAGS)                  \
+               $(AUDIT_CFLAGS)                 \
                -I@top_srcdir@/src/conf         \
                $(AM_CFLAGS)
 endif
diff --git a/src/util/virtaudit.c b/src/util/virtaudit.c
new file mode 100644 (file)
index 0000000..036a8b9
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * audit.h: auditing support
+ *
+ * Copyright (C) 2010 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>
+
+#ifdef HAVE_AUDIT
+# include <libaudit.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "virtaudit.h"
+
+/* Provide the macros in case the header file is old.
+   FIXME: should be removed. */
+#ifndef AUDIT_VIRT_CONTROL
+# define AUDIT_VIRT_CONTROL              2500 /* Start, Pause, Stop VM */
+#endif
+#ifndef AUDIT_VIRT_RESOURCE
+# define AUDIT_VIRT_RESOURCE             2501 /* Resource assignment */
+#endif
+#ifndef AUDIT_VIRT_MACHINE_ID
+# define AUDIT_VIRT_MACHINE_ID           2502 /* Binding of label to VM */
+#endif
+
+#define VIR_FROM_THIS VIR_FROM_AUDIT
+
+#if HAVE_AUDIT
+static int auditfd = -1;
+#endif
+static int auditlog = 0;
+
+int virAuditOpen(void)
+{
+#if HAVE_AUDIT
+    if ((auditfd = audit_open()) < 0) {
+        virReportSystemError(errno, "%s", _("Unable to initialize audit layer"));
+        return -1;
+    }
+
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+
+void virAuditLog(int logging)
+{
+    auditlog = logging;
+}
+
+
+#if HAVE_AUDIT
+void virAuditSend(const char *file ATTRIBUTE_UNUSED, const char *func, size_t linenr,
+                  const char *clienttty, const char *clientaddr,
+                  enum virAuditRecordType type, bool success,
+                  const char *fmt, ...)
+#else
+void virAuditSend(const char *file ATTRIBUTE_UNUSED, const char *func, size_t linenr,
+                  const char *clienttty ATTRIBUTE_UNUSED,
+                  const char *clientaddr ATTRIBUTE_UNUSED,
+                  enum virAuditRecordType type, bool success,
+                  const char *fmt, ...)
+#endif
+{
+    char *str = NULL;
+    va_list args;
+
+    /* Duplicate later checks, to short circuit & avoid printf overhead
+     * when nothing is enabled */
+#if HAVE_AUDIT
+    if (!auditlog && auditfd < 0)
+        return;
+#else
+    if (!auditlog)
+        return;
+#endif
+
+    va_start(args, fmt);
+    if (vasprintf(&str, fmt, args) < 0) {
+        VIR_WARN0("Out of memory while formatting audit message");
+        str = NULL;
+    }
+    va_end(args);
+
+    if (auditlog && str) {
+        if (success)
+            virLogMessage("audit", VIR_LOG_INFO, func, linenr, 0,
+                          "success=yes %s", str);
+        else
+            virLogMessage("audit", VIR_LOG_WARN, func, linenr, 0,
+                          "success=no %s", str);
+    }
+
+#if HAVE_AUDIT
+    if (auditfd < 0)
+        return;
+
+    if (str) {
+        static const int record_types[] = {
+            [VIR_AUDIT_RECORD_MACHINE_CONTROL] = AUDIT_VIRT_CONTROL,
+            [VIR_AUDIT_RECORD_MACHINE_ID] = AUDIT_VIRT_MACHINE_ID,
+            [VIR_AUDIT_RECORD_RESOURCE] = AUDIT_VIRT_RESOURCE,
+        };
+
+        if (type > ARRAY_CARDINALITY(record_types) || record_types[type] == 0)
+            VIR_WARN("Unknown audit record type %d", type);
+        else if (audit_log_user_message(auditfd, record_types[type], str, NULL,
+                                        clientaddr, clienttty, success) < 0) {
+            char ebuf[1024];
+            VIR_WARN("Failed to send audit message %s: %s",
+                     NULLSTR(str), virStrerror(errno, ebuf, sizeof ebuf));
+        }
+    }
+#endif
+}
+
+void virAuditClose(void)
+{
+#if HAVE_AUDIT
+    close(auditfd);
+#endif
+}
diff --git a/src/util/virtaudit.h b/src/util/virtaudit.h
new file mode 100644 (file)
index 0000000..b0cb707
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * audit.h: auditing support
+ *
+ * Copyright (C) 2010 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 __LIBVIRT_AUDIT_H__
+# define __LIBVIRT_AUDIT_H__
+
+# include "internal.h"
+# include <stdbool.h>
+
+enum virAuditRecordType {
+    VIR_AUDIT_RECORD_MACHINE_CONTROL,
+    VIR_AUDIT_RECORD_MACHINE_ID,
+    VIR_AUDIT_RECORD_RESOURCE,
+};
+
+int virAuditOpen(void);
+
+void virAuditLog(int enabled);
+
+void virAuditSend(const char *file, const char *func, size_t linenr,
+                  const char *clienttty, const char *clientaddr,
+                  enum virAuditRecordType type, bool success,
+                  const char *fmt, ...);
+
+void virAuditClose(void);
+
+# define VIR_AUDIT(type, success, ...)                         \
+    virAuditSend(__FILE__, __func__, __LINE__,                 \
+                 NULL, NULL, type, success, __VA_ARGS__);
+
+# define VIR_AUDIT_USER(type, success, clienttty, clientaddr, ...)     \
+    virAuditSend(__FILE__, __func__, __LINE__,                         \
+                 clienttty, clientaddr, type, success, __VA_ARGS__);
+
+
+#endif /* __LIBVIRT_AUDIT_H__ */
index 9f632ec245190a2fc1c43a20370fd2899bd1543c..70749a7c0bc12a2808ddb6f85d71600c1c1d3892 100644 (file)
@@ -187,6 +187,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_DOMAIN_SNAPSHOT:
             dom = "Domain Snapshot ";
             break;
+        case VIR_FROM_AUDIT:
+            dom = "Audit";
+            break;
     }
     return(dom);
 }