diff --git a/autobuild.sh b/autobuild.sh index c52747938ad45f17f259d18ee5f0a73cfd7b456d..844ce539944f26e4962254b77f50961bc75ff8e8 100755 --- a/autobuild.sh +++ b/autobuild.sh @@ -85,6 +85,7 @@ if [ -x /usr/bin/i686-pc-mingw32-gcc ]; then --without-one \ --without-phyp \ --without-netcf \ + --without-audit \ --without-libvirtd make diff --git a/configure.ac b/configure.ac index 2803aa35ccf91f74ce324ca075163c2e14a131a8..d8c4d0d39c94dc9bac1758dfe7f5a19d98eaeccd 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/daemon/libvirtd.aug b/daemon/libvirtd.aug index 7406d238f81743b871f57c2f2ab15a3a877cbe78..0e061425daa448977c7d20ba9fc5832b3c55245c 100644 --- a/daemon/libvirtd.aug +++ b/daemon/libvirtd.aug @@ -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 ] diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 1543481b07827b31bc95605244a037d790f449b4..88e85ec1ba49556859d2ffb4894a13b6cc5bd007 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -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; diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf index d11c0fb083cf233d887d233427641a437f60ca3d..163a80fb03dc932f85e19e4b7dc230382ea8894e 100644 --- a/daemon/libvirtd.conf +++ b/daemon/libvirtd.conf @@ -313,6 +313,25 @@ # 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 diff --git a/daemon/test_libvirtd.aug b/daemon/test_libvirtd.aug index b8da28e0122c143ba131777c1ce2e97c21115638..5f8b6446760af456c9494affdd53cf1c026a3c17 100644 --- a/daemon/test_libvirtd.aug +++ b/daemon/test_libvirtd.aug @@ -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" } diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 3bbb293136ee99955b8f7fcf977178fdf9093fc7..94d686ce13014eca583242a689838fc0391b183b 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -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; diff --git a/libvirt.spec.in b/libvirt.spec.in index 55e368e6c22c3b1be06d945c73a1520a895f78df..93386fbe9e47f12f97f8bdaa59dc2d9e199561b6 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -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} @@ -165,6 +166,10 @@ %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 \ diff --git a/mingw32-libvirt.spec.in b/mingw32-libvirt.spec.in index 4bbbc3b1e418ffead6ab853dc2ddc546115c8543..e762c774cfd68c2c13fa07d4200c91df7f3d1966 100644 --- a/mingw32-libvirt.spec.in +++ b/mingw32-libvirt.spec.in @@ -57,6 +57,7 @@ MinGW Windows libvirt virtualization library. --without-one \ --without-phyp \ --without-netcf \ + --without-audit \ --without-libvirtd make diff --git a/po/POTFILES.in b/po/POTFILES.in index 8a148f3949421178b5a2cb3a5a71a908c7e74319..e30fea02696f43f52f49d796e8b44e12897e1677 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index e386bfafaa9c066dd871250ec6289bc3abd9eca6..a10a33c588ca07181a6198b4152c6e74b799b8d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000000000000000000000000000000000000..036a8b9f41c169b161f2338bfd51659c327491de --- /dev/null +++ b/src/util/virtaudit.c @@ -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 + +#ifdef HAVE_AUDIT +# include +#endif +#include +#include + +#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 index 0000000000000000000000000000000000000000..b0cb707815e3a4c6f197a5911d818c94f0b6d0b1 --- /dev/null +++ b/src/util/virtaudit.h @@ -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 + +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__ */ diff --git a/src/util/virterror.c b/src/util/virterror.c index 9f632ec245190a2fc1c43a20370fd2899bd1543c..70749a7c0bc12a2808ddb6f85d71600c1c1d3892 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -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); }