summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-08-04 09:35:29 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-08-04 09:39:07 +0200
commit7c38b784632ecc490f7440a286dc81b452dc6213 (patch)
treeffe32e4ca9d58174ba3a6da8b62aea4c2289d583
parent1c2883c940917e558e604e7ab0eeb1275d24a939 (diff)
parent28c231d68667483a562c2ffe0d490c86d22f9528 (diff)
downloadNetworkManager-7c38b784632ecc490f7440a286dc81b452dc6213.tar.gz
core: merge branch bg/audit-bgo749364
Log all the relevant changes to system configuration and state to the Linux audit subsystem through libaudit (if enabled at build time) and to the logging system. https://bugzilla.gnome.org/show_bug.cgi?id=749364
-rw-r--r--configure.ac46
-rw-r--r--contrib/fedora/rpm/NetworkManager.conf1
-rw-r--r--contrib/fedora/rpm/NetworkManager.spec2
-rw-r--r--data/NetworkManager.service.in2
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-utils.c24
-rw-r--r--man/NetworkManager.conf.xml.in12
-rw-r--r--src/Makefile.am11
-rw-r--r--src/devices/nm-device.c8
-rw-r--r--src/devices/nm-device.h1
-rw-r--r--src/devices/wifi/nm-device-wifi.c1
-rw-r--r--src/nm-audit-manager.c371
-rw-r--r--src/nm-audit-manager.h112
-rw-r--r--src/nm-auth-utils.c8
-rw-r--r--src/nm-auth-utils.h2
-rw-r--r--src/nm-config.h1
-rw-r--r--src/nm-logging.c1
-rw-r--r--src/nm-logging.h1
-rw-r--r--src/nm-manager.c94
-rw-r--r--src/nm-types.h1
-rw-r--r--src/settings/nm-settings-connection.c78
-rw-r--r--src/settings/nm-settings.c14
-rw-r--r--src/settings/nm-settings.h1
23 files changed, 725 insertions, 68 deletions
diff --git a/configure.ac b/configure.ac
index c0df38ee56..ed973998e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -272,8 +272,6 @@ dnl
dnl Checks for dbus-glib
dnl
PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1 dbus-glib-1 >= 0.94)
-AC_SUBST(DBUS_CFLAGS)
-AC_SUBST(DBUS_LIBS)
AC_CHECK_LIB([dbus-glib-1], [dbus_g_method_invocation_get_g_connection], ac_have_gmi_get_con="1", ac_have_gmi_get_con="0")
AC_DEFINE_UNQUOTED(HAVE_DBUS_GLIB_GMI_GET_CONNECTION, $ac_have_gmi_get_con, [Define if you have a dbus-glib with dbus_g_method_invocation_get_g_connection()])
@@ -305,8 +303,6 @@ AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
PKG_CHECK_MODULES(GUDEV, gudev-1.0 >= 165)
-AC_SUBST(GUDEV_CFLAGS)
-AC_SUBST(GUDEV_LIBS)
GOBJECT_INTROSPECTION_CHECK([0.9.6])
@@ -318,8 +314,6 @@ if (test "${enable_qt}" = "yes"); then
if test x"$have_qt" = x"no"; then
AC_MSG_ERROR(Qt development headers are required)
fi
- AC_SUBST(QT_CFLAGS)
- AC_SUBST(QT_LIBS)
# Check for moc-qt4 and if not found then moc
QT4_BINDIR=`$PKG_CONFIG QtCore --variable moc_location`
AC_CHECK_PROGS(MOC, [moc-qt4 moc],, [$QT4_BINDIR:$PATH])
@@ -393,8 +387,6 @@ if test "$with_systemd_journal" != "no"; then
fi
fi
if test "$have_systemd_journal" = "yes"; then
- AC_SUBST(SYSTEMD_JOURNAL_CFLAGS)
- AC_SUBST(SYSTEMD_JOURNAL_LIBS)
AC_DEFINE([SYSTEMD_JOURNAL], 1, [Define to 1 if libsystemd-journald is available])
else
AC_DEFINE([SYSTEMD_JOURNAL], 0, [Define to 1 if libsystemd-journald is available])
@@ -450,8 +442,6 @@ if test "$use_systemd_logind" = "yes" -a "$have_systemd_logind" = "no"; then
AC_MSG_ERROR([You must have libsystemd installed to build with systemd-logind support.])
fi
if test "$have_systemd_logind" = "yes"; then
- AC_SUBST(SYSTEMD_LOGIN_CFLAGS)
- AC_SUBST(SYSTEMD_LOGIN_LIBS)
AC_DEFINE([SESSION_TRACKING_SYSTEMD], 1, [Define to 1 if libsystemd-login is available])
session_tracking="$session_tracking, systemd-logind"
fi
@@ -503,12 +493,25 @@ if test "$have_selinux" = "yes"; then
else
AC_DEFINE(HAVE_SELINUX, 0, [Define if you have SELinux support])
fi
-AM_CONDITIONAL(HAVE_SELINUX, test "${have_selinux}" = "yes")
+
+# libaudit support
+AC_ARG_WITH(libaudit, AS_HELP_STRING([--with-libaudit=yes|no|auto], [Build with audit daemon support (default: auto)]),,[with_libaudit=auto])
+if test "$with_libaudit" = "yes" -o "$with_libaudit" = "auto"; then
+ PKG_CHECK_MODULES(LIBAUDIT, audit, [have_libaudit=yes], [have_libaudit=no])
+else
+ have_libaudit=no
+fi
+if test "$with_libaudit" = "yes" -a "$have_libaudit" = "no"; then
+ AC_MSG_ERROR([You must have libaudit installed to build --with-libaudit=yes.])
+fi
+if test "$have_libaudit" = "yes"; then
+ AC_DEFINE(HAVE_LIBAUDIT, 1, [Define if you have libaudit support])
+else
+ AC_DEFINE(HAVE_LIBAUDIT, 0, [Define if you have libaudit support])
+fi
# libnl support for the linux platform
PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8 libnl-route-3.0 libnl-genl-3.0)
-AC_SUBST(LIBNL_CFLAGS)
-AC_SUBST(LIBNL_LIBS)
AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_addr_gen_mode],
ac_have_addr_gen_mode="1",
@@ -542,8 +545,6 @@ AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_TOKEN,
# uuid library
PKG_CHECK_MODULES(UUID, uuid)
-AC_SUBST(UUID_CFLAGS)
-AC_SUBST(UUID_LIBS)
dnl Checks for readline library - used by nmcli
AX_LIB_READLINE
@@ -556,9 +557,6 @@ if (test "${enable_teamdctl}" = "yes"); then
if test x"$have_teamdctl" = x"no"; then
AC_MSG_ERROR(Teamd control is required)
fi
-
- AC_SUBST(LIBTEAMDCTL_CFLAGS)
- AC_SUBST(LIBTEAMDCTL_LIBS)
# temporary bug workaround
LIBTEAMDCTL_CFLAGS=`echo $LIBTEAMDCTL_CFLAGS | sed -e 's:/teamdctl.h::'`
AC_DEFINE(WITH_TEAMDCTL, 1, [Define if you have Teamd control support])
@@ -596,9 +594,6 @@ if (test "${enable_polkit_agent}" = "yes"); then
if test x"$have_pk_agent" = x"no"; then
AC_MSG_ERROR(Polkit agent is required)
fi
-
- AC_SUBST(POLKIT_CFLAGS)
- AC_SUBST(POLKIT_LIBS)
AC_DEFINE(WITH_POLKIT_AGENT, 1, [Define if you have polkit agent])
else
AC_DEFINE(WITH_POLKIT_AGENT, 0, [Define if you have polkit agent])
@@ -627,15 +622,11 @@ if test x"$ac_crypto" = xnss; then
AC_MSG_ERROR([No usable NSS found])
fi
- AC_SUBST(NSS_CFLAGS)
- AC_SUBST(NSS_LIBS)
AC_DEFINE(HAVE_NSS, 1, [Define if you have NSS])
with_nss=yes
elif test x"$ac_crypto" = xgnutls; then
PKG_CHECK_MODULES(GNUTLS, [gnutls >= 2.12])
AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have libgnutls])
- AC_SUBST(GNUTLS_CFLAGS)
- AC_SUBST(GNUTLS_LIBS)
with_gnutls=yes
else
AC_MSG_ERROR([Please choose either 'nss' or 'gnutls' for certificate and crypto operations])
@@ -702,8 +693,6 @@ if (test "${with_modem_manager_1}" != "no"); then
[mm-glib >= 0.7.991],
[have_libmm_glib=yes],
[have_libmm_glib=no])
- AC_SUBST(MM_GLIB_CFLAGS)
- AC_SUBST(MM_GLIB_LIBS)
if (test "${have_libmm_glib}" = "no"); then
if (test "${with_modem_manager_1}" = "yes"); then
@@ -868,8 +857,6 @@ if (test "${enable_concheck}" = "yes"); then
if test x"$with_libsoup" = x"no"; then
AC_MSG_ERROR(Connectivity checking requires libsoup)
fi
- AC_SUBST(LIBSOUP_CFLAGS)
- AC_SUBST(LIBSOUP_LIBS)
AC_DEFINE(WITH_CONCHECK, 1, [Define if you want connectivity checking support])
else
AC_DEFINE(WITH_CONCHECK, 0, [Define if you want connectivity checking support])
@@ -1137,6 +1124,7 @@ echo " polkit agent: ${enable_polkit_agent}"
echo " selinux: $have_selinux"
echo " systemd-journald: $have_systemd_journal (logging.backend: ${nm_config_logging_backend_default})"
echo " hostname persist: ${hostname_persist}"
+echo " libaudit: $have_libaudit"
echo
echo "Features:"
diff --git a/contrib/fedora/rpm/NetworkManager.conf b/contrib/fedora/rpm/NetworkManager.conf
index 0352aa1087..6efa736d92 100644
--- a/contrib/fedora/rpm/NetworkManager.conf
+++ b/contrib/fedora/rpm/NetworkManager.conf
@@ -23,3 +23,4 @@
[logging]
#level=DEBUG
+#audit=yes
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
index 048cedae1f..2d9618dfdb 100644
--- a/contrib/fedora/rpm/NetworkManager.spec
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -138,6 +138,7 @@ BuildRequires: ppp-devel >= 2.4.5
BuildRequires: nss-devel >= 3.11.7
BuildRequires: dhclient
BuildRequires: readline-devel
+BuildRequires: audit-libs-devel
%if %{regen_docs}
BuildRequires: gtk-doc
%endif
@@ -379,6 +380,7 @@ by nm-connection-editor and nm-applet in a non-graphical environment.
--with-crypto=nss \
--enable-more-warnings=error \
--enable-ppp=yes \
+ --with-libaudit=yes \
%if 0%{?with_modem_manager_1}
--with-modem-manager-1=yes \
%else
diff --git a/data/NetworkManager.service.in b/data/NetworkManager.service.in
index 42b43e381b..fbaf77d855 100644
--- a/data/NetworkManager.service.in
+++ b/data/NetworkManager.service.in
@@ -11,7 +11,7 @@ ExecStart=@sbindir@/NetworkManager --no-daemon
Restart=on-failure
# NM doesn't want systemd to kill its children for it
KillMode=process
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_MODULE
+CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_MODULE CAP_AUDIT_WRITE
ProtectSystem=true
ProtectHome=read-only
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index ea095a6510..4081a32990 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -135,6 +135,7 @@ char ** _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy);
GPtrArray * _nm_utils_strv_to_ptrarray (char **strv);
char ** _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray);
+gboolean _nm_utils_strv_equal (char **strv1, char **strv2);
gboolean _nm_utils_check_file (const char *filename,
gint64 check_owner,
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 89fa812d73..0ed4814619 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -846,6 +846,30 @@ _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray)
}
/**
+ * _nm_utils_strv_equal:
+ * @strv1: a string array
+ * @strv2: a string array
+ *
+ * Compare NULL-terminated string arrays for equality.
+ *
+ * Returns: %TRUE if the arrays are equal, %FALSE otherwise.
+ **/
+gboolean
+_nm_utils_strv_equal (char **strv1, char **strv2)
+{
+ if (strv1 == strv2)
+ return TRUE;
+
+ if (!strv1 || !strv2)
+ return FALSE;
+
+ for ( ; *strv1 && *strv2 && !strcmp (*strv1, *strv2); strv1++, strv2++)
+ ;
+
+ return !*strv1 && !*strv2;
+}
+
+/**
* _nm_utils_strsplit_set:
* @str: string to split
* @delimiters: string of delimiter characters
diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in
index 16a1ad996a..850e772fc1 100644
--- a/man/NetworkManager.conf.xml.in
+++ b/man/NetworkManager.conf.xml.in
@@ -414,7 +414,7 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT,
AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX,
INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS,
- TEAM, CONCHECK, DCB, DISPATCH.</para>
+ TEAM, CONCHECK, DCB, DISPATCH, AUDIT.</para>
<para>In addition, these special domains can be used: NONE,
ALL, DEFAULT, DHCP, IP.</para>
<para>You can specify per-domain log level overrides by
@@ -459,6 +459,7 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
<member>CONCHECK : Connectivity check</member>
<member>DCB : Data Center Bridging (DCB) operations</member>
<member>DISPATCH : Dispatcher scripts</member>
+ <member>AUDIT : Audit records</member>
<member> </member>
<member>NONE : when given by itself logging is disabled</member>
<member>ALL : all log domains</member>
@@ -484,6 +485,15 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
Otherwise, the default is "<literal>@NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@</literal>".
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>audit</varname></term>
+ <listitem><para>Whether the audit records are delivered to
+ auditd, the audit daemon. If <literal>false</literal>, audit
+ records will be sent only to the NetworkManager logging
+ system. If set to <literal>true</literal>, they will be also
+ sent to auditd. The default value is <literal>false</literal>.
+ </para></listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
diff --git a/src/Makefile.am b/src/Makefile.am
index e457cbc3dd..a5d7973a77 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -300,6 +300,8 @@ nm_sources = \
nm-activation-request.h \
nm-active-connection.c \
nm-active-connection.h \
+ nm-audit-manager.c \
+ nm-audit-manager.h \
nm-bus-manager.c \
nm-bus-manager.h \
nm-config.c \
@@ -418,6 +420,7 @@ AM_CPPFLAGS += \
$(LIBNDP_CFLAGS) \
$(LIBSOUP_CFLAGS) \
$(SELINUX_CFLAGS) \
+ $(LIBAUDIT_CFLAGS) \
$(SYSTEMD_LOGIN_CFLAGS) \
$(SYSTEMD_JOURNAL_CFLAGS) \
$(SYSTEMD_NM_CFLAGS) \
@@ -459,16 +462,14 @@ libNetworkManager_la_LIBADD = \
$(SYSTEMD_JOURNAL_LIBS) \
$(LIBNDP_LIBS) \
$(LIBDL) \
- $(LIBM)
+ $(LIBM) \
+ $(SELINUX_LIBS) \
+ $(LIBAUDIT_LIBS)
if WITH_LIBSOUP
libNetworkManager_la_LIBADD += $(LIBSOUP_LIBS)
endif
-if HAVE_SELINUX
-libNetworkManager_la_LIBADD += $(SELINUX_LIBS)
-endif
-
NetworkManager_LDFLAGS = -rdynamic
######################
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 2f21d6f409..d983d7a5ed 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -66,6 +66,7 @@
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "sd-ipv4ll.h"
+#include "nm-audit-manager.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
@@ -6177,6 +6178,7 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex)
static void
disconnect_cb (NMDevice *self,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
GError *error,
gpointer user_data)
{
@@ -6185,6 +6187,7 @@ disconnect_cb (NMDevice *self,
if (error) {
dbus_g_method_return_error (context, error);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, error->message);
return;
}
@@ -6194,6 +6197,7 @@ disconnect_cb (NMDevice *self,
NM_DEVICE_ERROR_NOT_ACTIVE,
"Device is not active");
dbus_g_method_return_error (context, local);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, local->message);
g_error_free (local);
} else {
nm_device_set_autoconnect (self, FALSE);
@@ -6202,6 +6206,7 @@ disconnect_cb (NMDevice *self,
NM_DEVICE_STATE_DEACTIVATING,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
dbus_g_method_return (context);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, subject, NULL);
}
}
@@ -6245,17 +6250,20 @@ impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context)
static void
delete_cb (NMDevice *self,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
GError *error,
gpointer user_data)
{
if (error) {
dbus_g_method_return_error (context, error);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, subject, error->message);
return;
}
/* Authorized */
nm_platform_link_delete (NM_PLATFORM_GET, nm_device_get_ifindex (self));
dbus_g_method_return (context);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, subject, NULL);
}
static void
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index d849f6682f..9e0dcac717 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -311,6 +311,7 @@ typedef struct {
typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
GError *error,
gpointer user_data);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 58da7cc065..ed7a402463 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -1057,6 +1057,7 @@ impl_device_get_all_access_points (NMDeviceWifi *self,
static void
request_scan_cb (NMDevice *device,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
GError *error,
gpointer user_data)
{
diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c
new file mode 100644
index 0000000000..22ebf3b054
--- /dev/null
+++ b/src/nm-audit-manager.c
@@ -0,0 +1,371 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager audit support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#if HAVE_LIBAUDIT
+#include <libaudit.h>
+#endif
+
+#include "gsystem-local-alloc.h"
+#include "nm-audit-manager.h"
+#include "nm-glib.h"
+#include "nm-auth-subject.h"
+#include "nm-config.h"
+#include "nm-logging.h"
+#include "nm-macros-internal.h"
+
+#define AUDIT_LOG_LEVEL LOGL_INFO
+
+typedef enum {
+ BACKEND_LOG = (1 << 0),
+ BACKEND_AUDITD = (1 << 1),
+ _BACKEND_LAST,
+ BACKEND_ALL = ((_BACKEND_LAST - 1) << 1) - 1,
+} AuditBackend;
+
+typedef struct {
+ const char *name;
+ GValue value;
+ gboolean need_encoding;
+ AuditBackend backends;
+} AuditField;
+
+typedef struct {
+#if HAVE_LIBAUDIT
+ NMConfig *config;
+ int auditd_fd;
+#endif
+} NMAuditManagerPrivate;
+
+#define NM_AUDIT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUDIT_MANAGER, NMAuditManagerPrivate))
+
+G_DEFINE_TYPE (NMAuditManager, nm_audit_manager, G_TYPE_OBJECT)
+
+NM_DEFINE_SINGLETON_GETTER (NMAuditManager, nm_audit_manager_get, NM_TYPE_AUDIT_MANAGER);
+
+static void
+_audit_field_init_string (AuditField *field, const char *name, const char *str,
+ gboolean need_encoding, AuditBackend backends)
+{
+ field->name = name;
+ field->need_encoding = need_encoding;
+ field->backends = backends;
+ g_value_init (&field->value, G_TYPE_STRING);
+ g_value_set_static_string (&field->value, str);
+}
+
+static void
+_audit_field_init_uint (AuditField *field, const char *name, uint val,
+ AuditBackend backends)
+{
+ field->name = name;
+ field->backends = backends;
+ g_value_init (&field->value, G_TYPE_UINT);
+ g_value_set_uint (&field->value, val);
+}
+
+static char *
+build_message (GPtrArray *fields, AuditBackend backend)
+{
+ GString *string;
+ AuditField *field;
+ gboolean first = TRUE;
+ guint i;
+
+ string = g_string_new (NULL);
+
+ for (i = 0; i < fields->len; i++) {
+ field = fields->pdata[i];
+
+ if (!NM_FLAGS_HAS (field->backends, backend))
+ continue;
+
+ if (first)
+ first = FALSE;
+ else
+ g_string_append_c (string, ' ');
+
+ if (G_VALUE_HOLDS_STRING (&field->value)) {
+ const char *str = g_value_get_string (&field->value);
+
+#if HAVE_LIBAUDIT
+ if (backend == BACKEND_AUDITD) {
+ if (field->need_encoding) {
+ char *value;
+
+ value = audit_encode_nv_string (field->name, str, 0);
+ g_string_append (string, value);
+ g_free (value);
+ } else
+ g_string_append_printf (string, "%s=%s", field->name, str);
+ continue;
+ }
+#endif /* HAVE_LIBAUDIT */
+ g_string_append_printf (string, "%s=\"%s\"", field->name, str);
+ } else if (G_VALUE_HOLDS_UINT (&field->value)) {
+ g_string_append_printf (string, "%s=%u", field->name,
+ g_value_get_uint (&field->value));
+ } else
+ g_assert_not_reached ();
+ }
+ return g_string_free (string, FALSE);
+}
+
+
+static void
+nm_audit_log (NMAuditManager *self, GPtrArray *fields, const char *file,
+ guint line, const char *func, gboolean success)
+{
+ NMAuditManagerPrivate *priv;
+ char *msg;
+
+ g_return_if_fail (NM_IS_AUDIT_MANAGER (self));
+ priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
+
+#if HAVE_LIBAUDIT
+ if (priv->auditd_fd >= 0) {
+ msg = build_message (fields, BACKEND_AUDITD);
+ audit_log_user_message (priv->auditd_fd, AUDIT_USYS_CONFIG, msg,
+ NULL, NULL, NULL, success);
+ g_free (msg);
+ }
+#endif
+
+ if (nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT)) {
+ msg = build_message (fields, BACKEND_LOG);
+ _nm_log_impl (file, line, func, AUDIT_LOG_LEVEL, LOGD_AUDIT, 0, "%s", msg);
+ g_free (msg);
+ }
+}
+
+static void
+_audit_log_helper (NMAuditManager *self, GPtrArray *fields, const char *file,
+ guint line, const char *func, const char *op, gboolean result,
+ NMAuthSubject *subject, const char *reason)
+{
+ AuditField op_field = { }, pid_field = { }, uid_field = { };
+ AuditField result_field = { }, reason_field = { };
+ gulong pid, uid;
+
+ _audit_field_init_string (&op_field, "op", op, FALSE, BACKEND_ALL);
+ g_ptr_array_insert (fields, 0, &op_field);
+
+ if (subject && nm_auth_subject_is_unix_process (subject)) {
+ pid = nm_auth_subject_get_unix_process_pid (subject);
+ uid = nm_auth_subject_get_unix_process_uid (subject);
+ if (pid != G_MAXULONG) {
+ _audit_field_init_uint (&pid_field, "pid", pid, BACKEND_ALL);
+ g_ptr_array_add (fields, &pid_field);
+ }
+ if (uid != G_MAXULONG) {
+ _audit_field_init_uint (&uid_field, "uid", uid, BACKEND_ALL);
+ g_ptr_array_add (fields, &uid_field);
+ }
+ }
+
+ _audit_field_init_string (&result_field, "result", result ? "success" : "fail",
+ FALSE, BACKEND_ALL);
+ g_ptr_array_add (fields, &result_field);
+
+ if (reason) {
+ _audit_field_init_string (&reason_field, "reason", reason, FALSE, BACKEND_LOG);
+ g_ptr_array_add (fields, &reason_field);
+ }
+
+ nm_audit_log (self, fields, file, line, func, result);
+}
+
+gboolean
+nm_audit_manager_audit_enabled (NMAuditManager *self)
+{
+#if HAVE_LIBAUDIT
+ NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
+
+ if (priv->auditd_fd >= 0)
+ return TRUE;
+#endif
+
+ return nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT);
+}
+
+void
+_nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, NMConnection *connection,
+ gboolean result, NMAuthSubject *subject, const char *reason)
+{
+ gs_unref_ptrarray GPtrArray *fields = NULL;
+ AuditField uuid_field = { }, name_field = { };
+
+ g_return_if_fail (op);
+ g_return_if_fail (connection || !strcmp (op, NM_AUDIT_OP_CONN_ADD));
+
+ fields = g_ptr_array_new ();
+
+ if (connection) {
+ _audit_field_init_string (&uuid_field, "uuid", nm_connection_get_uuid (connection),
+ FALSE, BACKEND_ALL);
+ g_ptr_array_add (fields, &uuid_field);
+
+ _audit_field_init_string (&name_field, "name", nm_connection_get_id (connection),
+ TRUE, BACKEND_ALL);
+ g_ptr_array_add (fields, &name_field);
+ }
+
+ _audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
+}
+
+void
+_nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, const char *arg,
+ gboolean result, NMAuthSubject *subject,
+ const char *reason)
+{
+ gs_unref_ptrarray GPtrArray *fields = NULL;
+ AuditField arg_field = { };
+
+ g_return_if_fail (op);
+ g_return_if_fail (arg);
+
+ fields = g_ptr_array_new ();
+
+ _audit_field_init_string (&arg_field, "arg", arg, TRUE, BACKEND_ALL);
+ g_ptr_array_add (fields, &arg_field);
+
+ _audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
+}
+
+void
+_nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, NMDevice *device,
+ gboolean result, NMAuthSubject *subject,
+ const char *reason)
+{
+ gs_unref_ptrarray GPtrArray *fields = NULL;
+ AuditField interface_field = { }, ifindex_field = { };
+ int ifindex;
+
+ g_return_if_fail (op);
+ g_return_if_fail (device);
+
+ fields = g_ptr_array_new ();
+
+ _audit_field_init_string (&interface_field, "interface", nm_device_get_ip_iface (device),
+ TRUE, BACKEND_ALL);
+ g_ptr_array_add (fields, &interface_field);
+
+ ifindex = nm_device_get_ip_ifindex (device);
+ if (ifindex > 0) {
+ _audit_field_init_uint (&ifindex_field, "ifindex", ifindex, BACKEND_ALL);
+ g_ptr_array_add (fields, &ifindex_field);
+ }
+
+ _audit_log_helper (self, fields, file, line, func, op, result, subject, reason);
+}
+
+#if HAVE_LIBAUDIT
+static void
+init_auditd (NMAuditManager *self)
+{
+ NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
+ NMConfigData *data = nm_config_get_data (priv->config);
+
+ if (nm_config_data_get_value_boolean (data, NM_CONFIG_KEYFILE_GROUP_LOGGING,
+ NM_CONFIG_KEYFILE_KEY_AUDIT, FALSE)) {
+ if (priv->auditd_fd < 0) {
+ priv->auditd_fd = audit_open ();
+ if (priv->auditd_fd < 0) {
+ nm_log_err (LOGD_CORE, "failed to open auditd socket: %s",
+ strerror (errno));
+ } else
+ nm_log_dbg (LOGD_CORE, "audit socket created");
+ }
+ } else {
+ if (priv->auditd_fd >= 0) {
+ audit_close (priv->auditd_fd);
+ priv->auditd_fd = -1;
+ nm_log_dbg (LOGD_CORE, "audit socket closed");
+ }
+ }
+}
+
+static void
+config_changed_cb (NMConfig *config,
+ NMConfigData *config_data,
+ NMConfigChangeFlags changes,
+ NMConfigData *old_data,
+ NMAuditManager *self)
+{
+ if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES))
+ init_auditd (self);
+}
+#endif
+
+static void
+nm_audit_manager_init (NMAuditManager *self)
+{
+#if HAVE_LIBAUDIT
+ NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
+
+ priv->config = g_object_ref (nm_config_get ());
+ g_signal_connect (G_OBJECT (priv->config),
+ NM_CONFIG_SIGNAL_CONFIG_CHANGED,
+ G_CALLBACK (config_changed_cb),
+ self);
+ priv->auditd_fd = -1;
+
+ init_auditd (self);
+#endif
+}
+
+static void
+dispose (GObject *object)
+{
+#if HAVE_LIBAUDIT
+ NMAuditManager *self = NM_AUDIT_MANAGER (object);
+ NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
+
+ if (priv->config) {
+ g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self);
+ g_clear_object (&priv->config);
+ }
+
+ if (priv->auditd_fd >= 0) {
+ audit_close (priv->auditd_fd);
+ priv->auditd_fd = -1;
+ }
+#endif
+
+ G_OBJECT_CLASS (nm_audit_manager_parent_class)->dispose (object);
+}
+
+static void
+nm_audit_manager_class_init (NMAuditManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (NMAuditManagerPrivate));
+
+ /* virtual methods */
+ object_class->dispose = dispose;
+}
+
diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h
new file mode 100644
index 0000000000..83d969c864
--- /dev/null
+++ b/src/nm-audit-manager.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager audit support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_AUDIT_MANAGER_H__
+#define __NM_AUDIT_MANAGER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "nm-connection.h"
+#include "nm-device.h"
+#include "nm-types.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_AUDIT_MANAGER (nm_audit_manager_get_type ())
+#define NM_AUDIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManager))
+#define NM_AUDIT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUDIT_MANAGER, NMAuditManagerClass))
+#define NM_IS_AUDIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUDIT_MANAGER))
+#define NM_IS_AUDIT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUDIT_MANAGER))
+#define NM_AUDIT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManagerClass))
+
+struct _NMAuditManager {
+ GObject parent;
+};
+
+typedef struct {
+ GObjectClass parent;
+} NMAuditManagerClass;
+
+#define NM_AUDIT_OP_CONN_ADD "connection-add"
+#define NM_AUDIT_OP_CONN_DELETE "connection-delete"
+#define NM_AUDIT_OP_CONN_UPDATE "connection-update"
+#define NM_AUDIT_OP_CONN_ACTIVATE "connection-activate"
+#define NM_AUDIT_OP_CONN_ADD_ACTIVATE "connection-add-activate"
+#define NM_AUDIT_OP_CONN_DEACTIVATE "connection-deactivate"
+#define NM_AUDIT_OP_CONN_CLEAR_SECRETS "connection-clear-secrets"
+
+#define NM_AUDIT_OP_SLEEP_CONTROL "sleep-control"
+#define NM_AUDIT_OP_NET_CONTROL "networking-control"
+#define NM_AUDIT_OP_RADIO_CONTROL "radio-control"
+
+#define NM_AUDIT_OP_DEVICE_AUTOCONNECT "device-autoconnect"
+#define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect"
+#define NM_AUDIT_OP_DEVICE_DELETE "device-delete"
+
+GType nm_audit_manager_get_type (void);
+NMAuditManager *nm_audit_manager_get (void);
+gboolean nm_audit_manager_audit_enabled (NMAuditManager *self);
+
+#define nm_audit_log_connection_op(op, connection, result, subject, reason) \
+ G_STMT_START { \
+ NMAuditManager *_audit = nm_audit_manager_get (); \
+ \
+ if (nm_audit_manager_audit_enabled (_audit)) { \
+ _nm_audit_manager_log_connection_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
+ (op), (connection), (result), (subject), \
+ (reason)); \
+ } \
+ } G_STMT_END
+
+#define nm_audit_log_control_op(op, arg, result, subject, reason) \
+ G_STMT_START { \
+ NMAuditManager *_audit = nm_audit_manager_get (); \
+ \
+ if (nm_audit_manager_audit_enabled (_audit)) { \
+ _nm_audit_manager_log_control_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
+ (op), (arg), (result), (subject), (reason)); \
+ } \
+ } G_STMT_END
+
+#define nm_audit_log_device_op(op, device, result, subject, reason) \
+ G_STMT_START { \
+ NMAuditManager *_audit = nm_audit_manager_get (); \
+ \
+ if (nm_audit_manager_audit_enabled (_audit)) { \
+ _nm_audit_manager_log_device_op (_audit, __FILE__, __LINE__, G_STRFUNC, \
+ (op), (device), (result), (subject), (reason)); \
+ } \
+ } G_STMT_END
+
+void _nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, NMConnection *connection,
+ gboolean result, NMAuthSubject *subject, const char *reason);
+
+void _nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, const char *arg,
+ gboolean result, NMAuthSubject *subject, const char *reason);
+
+void _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line,
+ const char *func, const char *op, NMDevice *device,
+ gboolean result, NMAuthSubject *subject, const char *reason);
+G_END_DECLS
+
+#endif /* __NM_AUDIT_MANAGER_H__ */
diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c
index 606f86c1ab..e0f770e712 100644
--- a/src/nm-auth-utils.c
+++ b/src/nm-auth-utils.c
@@ -223,6 +223,14 @@ nm_auth_chain_set_data_ulong (NMAuthChain *self,
nm_auth_chain_set_data (self, tag, ptr, g_free);
}
+NMAuthSubject *
+nm_auth_chain_get_subject (NMAuthChain *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return self->subject;
+}
+
NMAuthCallResult
nm_auth_chain_get_result (NMAuthChain *self, const char *permission)
{
diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h
index bf571ac4b0..f96fbeabe6 100644
--- a/src/nm-auth-utils.h
+++ b/src/nm-auth-utils.h
@@ -92,5 +92,7 @@ gboolean nm_auth_is_subject_in_acl (NMConnection *connection,
NMAuthSubject *subect,
char **out_error_desc);
+NMAuthSubject *nm_auth_chain_get_subject (NMAuthChain *self);
+
#endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */
diff --git a/src/nm-config.h b/src/nm-config.h
index 2eece45a15..e492999f99 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -65,6 +65,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh"
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
+#define NM_CONFIG_KEYFILE_KEY_AUDIT "audit"
#define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was."
#define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set."
diff --git a/src/nm-logging.c b/src/nm-logging.c
index 90598775fa..d7b85c1d4a 100644
--- a/src/nm-logging.c
+++ b/src/nm-logging.c
@@ -120,6 +120,7 @@ static const LogDesc domain_descs[] = {
{ LOGD_CONCHECK, "CONCHECK" },
{ LOGD_DCB, "DCB" },
{ LOGD_DISPATCH, "DISPATCH" },
+ { LOGD_AUDIT, "AUDIT" },
{ 0, NULL }
};
diff --git a/src/nm-logging.h b/src/nm-logging.h
index 668125927b..6af672844d 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -67,6 +67,7 @@ typedef enum { /*< skip >*/
LOGD_CONCHECK = (1LL << 31),
LOGD_DCB = (1LL << 32), /* Data Center Bridging */
LOGD_DISPATCH = (1LL << 33),
+ LOGD_AUDIT = (1LL << 34),
__LOGD_MAX,
LOGD_ALL = ((__LOGD_MAX - 1LL) << 1) - 1LL,
diff --git a/src/nm-manager.c b/src/nm-manager.c
index c2188b9ce0..b14c26267f 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -57,6 +57,7 @@
#include "nm-activation-request.h"
#include "nm-core-internal.h"
#include "nm-config.h"
+#include "nm-audit-manager.h"
static gboolean impl_manager_get_devices (NMManager *manager,
GPtrArray **devices,
@@ -1357,6 +1358,7 @@ device_auth_done_cb (NMAuthChain *chain,
NMDevice *device;
const char *permission;
NMDeviceAuthRequestFunc callback;
+ NMAuthSubject *subject;
g_assert (context);
@@ -1370,6 +1372,7 @@ device_auth_done_cb (NMAuthChain *chain,
g_assert (device);
result = nm_auth_chain_get_result (chain, permission);
+ subject = nm_auth_chain_get_subject (chain);
if (auth_error) {
/* translate the auth error into a manager permission denied error */
@@ -1390,6 +1393,7 @@ device_auth_done_cb (NMAuthChain *chain,
callback (device,
context,
+ subject,
error,
nm_auth_chain_get_data (chain, "user-data"));
@@ -1450,9 +1454,10 @@ device_auth_request_cb (NMDevice *device,
nm_auth_chain_add_call (chain, permission, allow_interaction);
done:
- g_clear_object (&subject);
if (error)
- callback (device, context, error, user_data);
+ callback (device, context, subject, error, user_data);
+
+ g_clear_object (&subject);
g_clear_error (&error);
}
@@ -3089,10 +3094,17 @@ _activation_auth_done (NMActiveConnection *active,
NMManager *self = user_data1;
DBusGMethodInvocation *context = user_data2;
GError *error = NULL;
+ NMAuthSubject *subject;
+ NMConnection *connection;
+
+ subject = nm_active_connection_get_subject (active);
+ connection = nm_active_connection_get_connection (active);
if (success) {
if (_internal_activate_generic (self, active, &error)) {
dbus_g_method_return (context, nm_exported_object_get_path (NM_EXPORTED_OBJECT (active)));
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE,
+ subject, NULL);
g_object_unref (active);
return;
}
@@ -3104,7 +3116,10 @@ _activation_auth_done (NMActiveConnection *active,
g_assert (error);
dbus_g_method_return_error (context, error);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE,
+ subject, error->message);
_internal_activation_failed (self, active, error->message);
+
g_object_unref (active);
g_error_free (error);
}
@@ -3119,7 +3134,7 @@ impl_manager_activate_connection (NMManager *self,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMActiveConnection *active = NULL;
NMAuthSubject *subject = NULL;
- NMConnection *connection;
+ NMConnection *connection = NULL;
NMDevice *device = NULL;
gboolean is_vpn = FALSE;
GError *error = NULL;
@@ -3211,6 +3226,10 @@ impl_manager_activate_connection (NMManager *self,
return;
error:
+ if (connection) {
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE,
+ subject, error->message);
+ }
g_clear_object (&active);
g_clear_object (&subject);
@@ -3231,6 +3250,7 @@ activation_add_done (NMSettings *self,
NMSettingsConnection *new_connection,
GError *error,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
gpointer user_data)
{
AddAndActivateInfo *info = user_data;
@@ -3246,6 +3266,11 @@ activation_add_done (NMSettings *self,
dbus_g_method_return (context,
nm_connection_get_path (NM_CONNECTION (new_connection)),
nm_exported_object_get_path (NM_EXPORTED_OBJECT (info->active)));
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE,
+ nm_active_connection_get_connection (info->active),
+ TRUE,
+ nm_active_connection_get_subject (info->active),
+ NULL);
goto done;
}
error = local;
@@ -3255,6 +3280,11 @@ activation_add_done (NMSettings *self,
_internal_activation_failed (info->manager, info->active, error->message);
nm_settings_connection_delete (new_connection, NULL, NULL);
dbus_g_method_return_error (context, error);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE,
+ nm_active_connection_get_connection (info->active),
+ FALSE,
+ nm_active_connection_get_subject (info->active),
+ error->message);
g_clear_error (&local);
done:
@@ -3293,6 +3323,11 @@ _add_and_activate_auth_done (NMActiveConnection *active,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
dbus_g_method_return_error (context, error);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE,
+ nm_active_connection_get_connection (active),
+ FALSE,
+ nm_active_connection_get_subject (active),
+ error->message);
g_error_free (error);
}
@@ -3399,6 +3434,7 @@ impl_manager_add_and_activate_connection (NMManager *self,
return;
error:
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, connection, FALSE, subject, error->message);
g_clear_object (&connection);
g_slist_free (all_connections);
g_clear_object (&subject);
@@ -3462,12 +3498,16 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
NMAuthCallResult result;
+ NMActiveConnection *active;
+ char *path;
g_assert (context);
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+ path = nm_auth_chain_get_data (chain, "path");
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
+ active = active_connection_get_by_path (self, path);
if (auth_error) {
nm_log_dbg (LOGD_CORE, "Disconnect request failed: %s", auth_error->message);
@@ -3482,7 +3522,7 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
} else {
/* success; deactivation allowed */
if (!nm_manager_deactivate_connection (self,
- nm_auth_chain_get_data (chain, "path"),
+ path,
NM_DEVICE_STATE_REASON_USER_REQUESTED,
&error))
g_assert (error);
@@ -3493,6 +3533,14 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
else
dbus_g_method_return (context);
+ if (active) {
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE,
+ nm_active_connection_get_connection (active),
+ !error,
+ nm_auth_chain_get_subject (chain),
+ error ? error->message : NULL);
+ }
+
g_clear_error (&error);
nm_auth_chain_unref (chain);
}
@@ -3561,9 +3609,14 @@ impl_manager_deactivate_connection (NMManager *self,
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
done:
- g_clear_object (&subject);
- if (error)
+ if (error) {
dbus_g_method_return_error (context, error);
+ if (connection) {
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE,
+ subject, error->message);
+ }
+ }
+ g_clear_object (&subject);
g_clear_error (&error);
}
@@ -3725,6 +3778,7 @@ impl_manager_sleep (NMManager *self,
{
NMManagerPrivate *priv;
GError *error = NULL;
+ gs_unref_object NMAuthSubject *subject = NULL;
#if 0
NMAuthChain *chain;
const char *error_desc = NULL;
@@ -3733,12 +3787,15 @@ impl_manager_sleep (NMManager *self,
g_return_if_fail (NM_IS_MANAGER (self));
priv = NM_MANAGER_GET_PRIVATE (self);
+ subject = nm_auth_subject_new_unix_process_from_context (context);
if (priv->sleeping == do_sleep) {
error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
"Already %s", do_sleep ? "asleep" : "awake");
dbus_g_method_return_error (context, error);
+ nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", FALSE, subject,
+ error->message);
g_error_free (error);
return;
}
@@ -3752,6 +3809,7 @@ impl_manager_sleep (NMManager *self,
* D-Bus permissions to restrict the call to root.
*/
_internal_sleep (self, do_sleep);
+ nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", TRUE, subject, NULL);
dbus_g_method_return (context);
return;
@@ -3828,10 +3886,13 @@ enable_net_done_cb (NMAuthChain *chain,
GError *ret_error = NULL;
NMAuthCallResult result;
gboolean enable;
+ NMAuthSubject *subject;
g_assert (context);
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+ enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable"));
+ subject = nm_auth_chain_get_subject (chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
if (error) {
@@ -3846,13 +3907,16 @@ enable_net_done_cb (NMAuthChain *chain,
"Not authorized to enable/disable networking");
} else {
/* Auth success */
- enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable"));
_internal_enable (self, enable);
dbus_g_method_return (context);
+ nm_audit_log_control_op (NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", TRUE,
+ subject, NULL);
}
if (ret_error) {
dbus_g_method_return_error (context, ret_error);
+ nm_audit_log_control_op (NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", FALSE,
+ subject, ret_error->message);
g_error_free (ret_error);
}
@@ -4360,9 +4424,11 @@ prop_set_auth_done_cb (NMAuthChain *chain,
DBusConnection *connection;
NMAuthCallResult result;
DBusMessage *reply = NULL, *message;
- const char *permission, *prop;
+ const char *permission, *prop, *audit_op;
GObject *obj;
gboolean set_enabled = TRUE;
+ NMAuthSubject *subject;
+ gs_free char *prop_value = NULL;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
@@ -4371,15 +4437,21 @@ prop_set_auth_done_cb (NMAuthChain *chain,
prop = nm_auth_chain_get_data (chain, "prop");
set_enabled = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enabled"));
obj = nm_auth_chain_get_data (chain, "object");
+ audit_op = nm_auth_chain_get_data (chain, "audit-op");
+
+ prop_value = g_strdup_printf ("%s:%d", prop, set_enabled);
result = nm_auth_chain_get_result (chain, permission);
+ subject = nm_auth_chain_get_subject (chain);
if (error || (result != NM_AUTH_CALL_RESULT_YES)) {
reply = dbus_message_new_error (message,
NM_IS_DEVICE (obj) ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR,
"Not authorized to perform this operation");
+ nm_audit_log_control_op (audit_op, prop_value, FALSE, subject, error ? error->message : NULL);
} else {
g_object_set (obj, prop, set_enabled, NULL);
reply = dbus_message_new_method_return (message);
+ nm_audit_log_control_op (audit_op, prop_value, TRUE, subject, NULL);
}
g_assert (reply);
@@ -4408,6 +4480,7 @@ prop_filter (DBusConnection *connection,
NMAuthSubject *subject = NULL;
NMAuthChain *chain;
GObject *obj;
+ const char *audit_op = NULL;
/* The sole purpose of this function is to validate property accesses
* on the NMManager object since dbus-glib doesn't yet give us this
@@ -4436,15 +4509,19 @@ prop_filter (DBusConnection *connection,
if (!strcmp (propname, "WirelessEnabled")) {
glib_propname = NM_MANAGER_WIRELESS_ENABLED;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI;
+ audit_op = NM_AUDIT_OP_RADIO_CONTROL;
} else if (!strcmp (propname, "WwanEnabled")) {
glib_propname = NM_MANAGER_WWAN_ENABLED;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN;
+ audit_op = NM_AUDIT_OP_RADIO_CONTROL;
} else if (!strcmp (propname, "WimaxEnabled")) {
glib_propname = NM_MANAGER_WIMAX_ENABLED;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX;
+ audit_op = NM_AUDIT_OP_RADIO_CONTROL;
} else if (!strcmp (propname, "Autoconnect")) {
glib_propname = NM_DEVICE_AUTOCONNECT;
permission = NM_AUTH_PERMISSION_NETWORK_CONTROL;
+ audit_op = NM_AUDIT_OP_DEVICE_AUTOCONNECT;
} else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -4487,6 +4564,7 @@ prop_filter (DBusConnection *connection,
nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref);
nm_auth_chain_set_data (chain, "connection", dbus_connection_ref (connection), (GDestroyNotify) dbus_connection_unref);
nm_auth_chain_set_data (chain, "object", g_object_ref (obj), (GDestroyNotify) g_object_unref);
+ nm_auth_chain_set_data (chain, "audit-op", (char *) audit_op, NULL);
nm_auth_chain_add_call (chain, permission, TRUE);
out:
diff --git a/src/nm-types.h b/src/nm-types.h
index 7d3cf48129..7e9d488a18 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -27,6 +27,7 @@
/* core */
typedef struct _NMActiveConnection NMActiveConnection;
+typedef struct _NMAuditManager NMAuditManager;
typedef struct _NMVpnConnection NMVpnConnection;
typedef struct _NMActRequest NMActRequest;
typedef struct _NMAuthSubject NMAuthSubject;
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index c56a340835..ec0d6c230e 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -36,6 +36,7 @@
#include "nm-agent-manager.h"
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
+#include "nm-audit-manager.h"
#include "gsystem-local-alloc.h"
#define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps"
@@ -1320,6 +1321,11 @@ typedef struct {
gboolean save_to_disk;
} UpdateInfo;
+typedef struct {
+ DBusGMethodInvocation *context;
+ NMAuthSubject *subject;
+} CallbackInfo;
+
static void
has_some_secrets_cb (NMSetting *setting,
const char *key,
@@ -1384,6 +1390,9 @@ update_complete (NMSettingsConnection *self,
else
dbus_g_method_return (info->context);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, NM_CONNECTION (self), !error,
+ info->subject, error ? error->message : NULL);
+
g_clear_object (&info->subject);
g_clear_object (&info->agent_mgr);
g_clear_object (&info->new_settings);
@@ -1549,6 +1558,9 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
return;
error:
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, NM_CONNECTION (self), FALSE, subject,
+ error->message);
+
g_clear_object (&tmp);
g_clear_object (&subject);
@@ -1590,12 +1602,16 @@ con_delete_cb (NMSettingsConnection *self,
GError *error,
gpointer user_data)
{
- DBusGMethodInvocation *context = user_data;
+ CallbackInfo *info = user_data;
if (error)
- dbus_g_method_return_error (context, error);
+ dbus_g_method_return_error (info->context, error);
else
- dbus_g_method_return (context);
+ dbus_g_method_return (info->context);
+
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self),
+ !error, info->subject, error ? error->message : NULL);
+ g_free (info);
}
static void
@@ -1605,12 +1621,20 @@ delete_auth_cb (NMSettingsConnection *self,
GError *error,
gpointer data)
{
+ CallbackInfo *info;
+
if (error) {
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self), FALSE, subject,
+ error->message);
dbus_g_method_return_error (context, error);
return;
}
- nm_settings_connection_delete (self, con_delete_cb, context);
+ info = g_malloc0 (sizeof (*info));
+ info->context = context;
+ info->subject = subject;
+
+ nm_settings_connection_delete (self, con_delete_cb, info);
}
static const char *
@@ -1634,23 +1658,24 @@ static void
impl_settings_connection_delete (NMSettingsConnection *self,
DBusGMethodInvocation *context)
{
- NMAuthSubject *subject;
+ NMAuthSubject *subject = NULL;
GError *error = NULL;
- if (!check_writable (NM_CONNECTION (self), &error)) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
+ if (!check_writable (NM_CONNECTION (self), &error))
+ goto out_err;
subject = _new_auth_subject (context, &error);
if (subject) {
auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL);
g_object_unref (subject);
- } else {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- }
+ } else
+ goto out_err;
+
+ return;
+out_err:
+ dbus_g_method_return_error (context, error);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self), FALSE, subject, error->message);
+ g_error_free (error);
}
/**************************************************************/
@@ -1754,12 +1779,16 @@ clear_secrets_cb (NMSettingsConnection *self,
GError *error,
gpointer user_data)
{
- DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+ CallbackInfo *info = user_data;
if (error)
- dbus_g_method_return_error (context, error);
+ dbus_g_method_return_error (info->context, error);
else
- dbus_g_method_return (context);
+ dbus_g_method_return (info->context);
+
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ !error, info->subject, error ? error->message : NULL);
+ g_free (info);
}
static void
@@ -1770,10 +1799,13 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self,
gpointer user_data)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+ CallbackInfo *info;
- if (error)
+ if (error) {
dbus_g_method_return_error (context, error);
- else {
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ FALSE, subject, error->message);
+ } else {
/* Clear secrets in connection and caches */
nm_connection_clear_secrets (NM_CONNECTION (self));
if (priv->system_secrets)
@@ -1784,7 +1816,11 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self,
/* Tell agents to remove secrets for this connection */
nm_agent_manager_delete_secrets (priv->agent_mgr, NM_CONNECTION (self));
- nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, clear_secrets_cb, context);
+ info = g_malloc0 (sizeof (*info));
+ info->context = context;
+ info->subject = subject;
+
+ nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, clear_secrets_cb, info);
}
}
@@ -1806,6 +1842,8 @@ impl_settings_connection_clear_secrets (NMSettingsConnection *self,
g_object_unref (subject);
} else {
dbus_g_method_return_error (context, error);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ FALSE, NULL, error->message);
g_error_free (error);
}
}
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index ba5035a513..e0e3af64ce 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -75,6 +75,7 @@
#include "nm-agent-manager.h"
#include "nm-connection-provider.h"
#include "nm-config.h"
+#include "nm-audit-manager.h"
#include "NetworkManagerUtils.h"
#include "nm-dispatcher.h"
@@ -1229,7 +1230,7 @@ pk_add_cb (NMAuthChain *chain,
callback_data = nm_auth_chain_get_data (chain, "callback-data");
subject = nm_auth_chain_get_data (chain, "subject");
- callback (self, added, error, context, callback_data);
+ callback (self, added, error, context, subject, callback_data);
/* Send agent-owned secrets to the agents */
if (!error && added && nm_settings_has_connection (self, (NMConnection *) added))
@@ -1371,7 +1372,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
done:
if (error)
- callback (self, NULL, error, context, user_data);
+ callback (self, NULL, error, context, subject, user_data);
g_clear_error (&error);
g_clear_object (&subject);
@@ -1382,12 +1383,17 @@ impl_settings_add_connection_add_cb (NMSettings *self,
NMSettingsConnection *connection,
GError *error,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
gpointer user_data)
{
- if (error)
+ if (error) {
dbus_g_method_return_error (context, error);
- else
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message);
+ } else {
dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection)));
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NM_CONNECTION (connection), TRUE,
+ subject, NULL);
+ }
}
static void
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index f28d010bdf..4afa4dc250 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -87,6 +87,7 @@ typedef void (*NMSettingsAddCallback) (NMSettings *settings,
NMSettingsConnection *connection,
GError *error,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
gpointer user_data);
void nm_settings_add_connection_dbus (NMSettings *self,