Basic framework for auditing integration

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
This commit is contained in:
Daniel P. Berrange 2010-09-15 14:44:11 +01:00
parent ba5c9afffa
commit 8f680ad3b8
14 changed files with 327 additions and 6 deletions

View File

@ -85,6 +85,7 @@ if [ -x /usr/bin/i686-pc-mingw32-gcc ]; then
--without-one \
--without-phyp \
--without-netcf \
--without-audit \
--without-libvirtd
make

View 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

View 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 ]

View 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;

View File

@ -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

View 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" }

View 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;

View 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}
@ -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 \

View File

@ -57,6 +57,7 @@ MinGW Windows libvirt virtualization library.
--without-one \
--without-phyp \
--without-netcf \
--without-audit \
--without-libvirtd
make

View 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

View 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

144
src/util/virtaudit.c Normal file
View File

@ -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
}

55
src/util/virtaudit.h Normal file
View File

@ -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__ */

View 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);
}