diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-08-04 09:35:29 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-08-04 09:39:07 +0200 |
commit | 7c38b784632ecc490f7440a286dc81b452dc6213 (patch) | |
tree | ffe32e4ca9d58174ba3a6da8b62aea4c2289d583 | |
parent | 1c2883c940917e558e604e7ab0eeb1275d24a939 (diff) | |
parent | 28c231d68667483a562c2ffe0d490c86d22f9528 (diff) | |
download | NetworkManager-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.ac | 46 | ||||
-rw-r--r-- | contrib/fedora/rpm/NetworkManager.conf | 1 | ||||
-rw-r--r-- | contrib/fedora/rpm/NetworkManager.spec | 2 | ||||
-rw-r--r-- | data/NetworkManager.service.in | 2 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 1 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 24 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml.in | 12 | ||||
-rw-r--r-- | src/Makefile.am | 11 | ||||
-rw-r--r-- | src/devices/nm-device.c | 8 | ||||
-rw-r--r-- | src/devices/nm-device.h | 1 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 1 | ||||
-rw-r--r-- | src/nm-audit-manager.c | 371 | ||||
-rw-r--r-- | src/nm-audit-manager.h | 112 | ||||
-rw-r--r-- | src/nm-auth-utils.c | 8 | ||||
-rw-r--r-- | src/nm-auth-utils.h | 2 | ||||
-rw-r--r-- | src/nm-config.h | 1 | ||||
-rw-r--r-- | src/nm-logging.c | 1 | ||||
-rw-r--r-- | src/nm-logging.h | 1 | ||||
-rw-r--r-- | src/nm-manager.c | 94 | ||||
-rw-r--r-- | src/nm-types.h | 1 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 78 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 14 | ||||
-rw-r--r-- | src/settings/nm-settings.h | 1 |
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, |