Blame src/nm-audit-manager.c

Packit Service b23acc
// SPDX-License-Identifier: GPL-2.0+
Packit Service b23acc
/*
Packit Service b23acc
 * Copyright (C) 2015 Red Hat, Inc.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
#include "nm-default.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-audit-manager.h"
Packit Service b23acc
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
#include <libaudit.h>
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
#include "nm-libnm-core-intern/nm-auth-subject.h"
Packit Service b23acc
#include "nm-config.h"
Packit Service b23acc
#include "nm-dbus-manager.h"
Packit Service b23acc
#include "settings/nm-settings-connection.h"
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
typedef enum {
Packit Service b23acc
	BACKEND_LOG    = (1 << 0),
Packit Service b23acc
	BACKEND_AUDITD = (1 << 1),
Packit Service b23acc
	_BACKEND_LAST,
Packit Service b23acc
	BACKEND_ALL    = ((_BACKEND_LAST - 1) << 1) - 1,
Packit Service b23acc
} AuditBackend;
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	const char *name;
Packit Service b23acc
	GValue value;
Packit Service b23acc
	gboolean need_encoding;
Packit Service b23acc
	AuditBackend backends;
Packit Service b23acc
} AuditField;
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	NMConfig *config;
Packit Service b23acc
	int auditd_fd;
Packit Service b23acc
} NMAuditManagerPrivate;
Packit Service b23acc
Packit Service b23acc
struct _NMAuditManager {
Packit Service b23acc
	GObject parent;
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	NMAuditManagerPrivate _priv;
Packit Service b23acc
#endif
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
struct _NMAuditManagerClass {
Packit Service b23acc
	GObjectClass parent;
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
G_DEFINE_TYPE (NMAuditManager, nm_audit_manager, G_TYPE_OBJECT)
Packit Service b23acc
Packit Service b23acc
#define NM_AUDIT_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAuditManager, NM_IS_AUDIT_MANAGER)
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
#define AUDIT_LOG_LEVEL LOGL_INFO
Packit Service b23acc
Packit Service b23acc
#define _NMLOG_PREFIX_NAME    "audit"
Packit Service b23acc
#define _NMLOG(level, domain, ...) \
Packit Service b23acc
    G_STMT_START { \
Packit Service b23acc
        nm_log ((level), (domain), NULL, NULL, \
Packit Service b23acc
                "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
Packit Service b23acc
                _NMLOG_PREFIX_NAME": " \
Packit Service b23acc
                _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
Packit Service b23acc
    } G_STMT_END
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
NM_DEFINE_SINGLETON_GETTER (NMAuditManager, nm_audit_manager_get, NM_TYPE_AUDIT_MANAGER);
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_audit_field_init_string (AuditField *field, const char *name, const char *str,
Packit Service b23acc
                          gboolean need_encoding, AuditBackend backends)
Packit Service b23acc
{
Packit Service b23acc
	field->name = name;
Packit Service b23acc
	field->need_encoding = need_encoding;
Packit Service b23acc
	field->backends = backends;
Packit Service b23acc
	g_value_init (&field->value, G_TYPE_STRING);
Packit Service b23acc
	g_value_set_static_string (&field->value, str);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_audit_field_init_uint (AuditField *field, const char *name, uint val,
Packit Service b23acc
                        AuditBackend backends)
Packit Service b23acc
{
Packit Service b23acc
	field->name = name;
Packit Service b23acc
	field->backends = backends;
Packit Service b23acc
	g_value_init (&field->value, G_TYPE_UINT);
Packit Service b23acc
	g_value_set_uint (&field->value, val);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static char *
Packit Service b23acc
build_message (GPtrArray *fields, AuditBackend backend)
Packit Service b23acc
{
Packit Service b23acc
	GString *string;
Packit Service b23acc
	AuditField *field;
Packit Service b23acc
	gboolean first = TRUE;
Packit Service b23acc
	guint i;
Packit Service b23acc
Packit Service b23acc
	string = g_string_new (NULL);
Packit Service b23acc
Packit Service b23acc
	for (i = 0; i < fields->len; i++) {
Packit Service b23acc
		field = fields->pdata[i];
Packit Service b23acc
Packit Service b23acc
		if (!NM_FLAGS_ANY (field->backends, backend))
Packit Service b23acc
			continue;
Packit Service b23acc
Packit Service b23acc
		if (first)
Packit Service b23acc
			first = FALSE;
Packit Service b23acc
		else
Packit Service b23acc
			g_string_append_c (string, ' ');
Packit Service b23acc
Packit Service b23acc
		if (G_VALUE_HOLDS_STRING (&field->value)) {
Packit Service b23acc
			const char *str = g_value_get_string (&field->value);
Packit Service b23acc
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
			if (backend == BACKEND_AUDITD) {
Packit Service b23acc
				if (field->need_encoding) {
Packit Service b23acc
					char *value;
Packit Service b23acc
Packit Service b23acc
					value = audit_encode_nv_string (field->name, str, 0);
Packit Service b23acc
					g_string_append (string, value);
Packit Service b23acc
					g_free (value);
Packit Service b23acc
				} else
Packit Service b23acc
					g_string_append_printf (string, "%s=%s", field->name, str);
Packit Service b23acc
				continue;
Packit Service b23acc
			}
Packit Service b23acc
#endif /* HAVE_LIBAUDIT */
Packit Service b23acc
			g_string_append_printf (string, "%s=\"%s\"", field->name, str);
Packit Service b23acc
		} else if (G_VALUE_HOLDS_UINT (&field->value)) {
Packit Service b23acc
			g_string_append_printf (string, "%s=%u", field->name,
Packit Service b23acc
			                        g_value_get_uint (&field->value));
Packit Service b23acc
		} else
Packit Service b23acc
			g_assert_not_reached ();
Packit Service b23acc
	}
Packit Service b23acc
	return g_string_free (string, FALSE);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_audit_log (NMAuditManager *self, GPtrArray *fields, const char *file,
Packit Service b23acc
              guint line, const char *func, gboolean success)
Packit Service b23acc
{
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	NMAuditManagerPrivate *priv;
Packit Service b23acc
#endif
Packit Service b23acc
	char *msg;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (NM_IS_AUDIT_MANAGER (self));
Packit Service b23acc
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	if (priv->auditd_fd >= 0) {
Packit Service b23acc
		msg = build_message (fields, BACKEND_AUDITD);
Packit Service b23acc
		audit_log_user_message (priv->auditd_fd, AUDIT_USYS_CONFIG, msg,
Packit Service b23acc
		                        NULL, NULL, NULL, success);
Packit Service b23acc
		g_free (msg);
Packit Service b23acc
	}
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
	if (nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT)) {
Packit Service b23acc
		msg = build_message (fields, BACKEND_LOG);
Packit Service b23acc
		_NMLOG (AUDIT_LOG_LEVEL, LOGD_AUDIT, "%s", msg);
Packit Service b23acc
		g_free (msg);
Packit Service b23acc
	}
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_audit_log_helper (NMAuditManager *self,
Packit Service b23acc
                   GPtrArray *fields,
Packit Service b23acc
                   const char *file,
Packit Service b23acc
                   guint line,
Packit Service b23acc
                   const char *func,
Packit Service b23acc
                   const char *op,
Packit Service b23acc
                   gboolean result,
Packit Service b23acc
                   gpointer subject_context,
Packit Service b23acc
                   const char *reason)
Packit Service b23acc
{
Packit Service b23acc
	AuditField op_field = { }, pid_field = { }, uid_field = { };
Packit Service b23acc
	AuditField result_field = { }, reason_field = { };
Packit Service b23acc
	gulong pid, uid;
Packit Service b23acc
	NMAuthSubject *subject = NULL;
Packit Service b23acc
	gs_unref_object NMAuthSubject *subject_free = NULL;
Packit Service b23acc
Packit Service b23acc
	_audit_field_init_string (&op_field, "op", op, FALSE, BACKEND_ALL);
Packit Service b23acc
	g_ptr_array_insert (fields, 0, &op_field);
Packit Service b23acc
Packit Service b23acc
	if (subject_context) {
Packit Service b23acc
		if (NM_IS_AUTH_SUBJECT (subject_context))
Packit Service b23acc
			subject = subject_context;
Packit Service b23acc
		else if (G_IS_DBUS_METHOD_INVOCATION (subject_context)) {
Packit Service b23acc
			GDBusMethodInvocation *context = subject_context;
Packit Service b23acc
Packit Service b23acc
			subject = subject_free = nm_dbus_manager_new_auth_subject_from_context (context);
Packit Service b23acc
		} else
Packit Service b23acc
			g_warn_if_reached ();
Packit Service b23acc
	}
Packit Service b23acc
	if (subject &&
Packit Service b23acc
	    nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) {
Packit Service b23acc
		pid = nm_auth_subject_get_unix_process_pid (subject);
Packit Service b23acc
		uid = nm_auth_subject_get_unix_process_uid (subject);
Packit Service b23acc
		if (pid != G_MAXULONG) {
Packit Service b23acc
			_audit_field_init_uint (&pid_field, "pid", pid, BACKEND_ALL);
Packit Service b23acc
			g_ptr_array_add (fields, &pid_field);
Packit Service b23acc
		}
Packit Service b23acc
		if (uid != G_MAXULONG) {
Packit Service b23acc
			_audit_field_init_uint (&uid_field, "uid", uid, BACKEND_ALL);
Packit Service b23acc
			g_ptr_array_add (fields, &uid_field);
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	_audit_field_init_string (&result_field, "result", result ? "success" : "fail",
Packit Service b23acc
	                          FALSE, BACKEND_ALL);
Packit Service b23acc
	g_ptr_array_add (fields, &result_field);
Packit Service b23acc
Packit Service b23acc
	if (reason) {
Packit Service b23acc
		_audit_field_init_string (&reason_field, "reason", reason, FALSE, BACKEND_LOG);
Packit Service b23acc
		g_ptr_array_add (fields, &reason_field);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	nm_audit_log (self, fields, file, line, func, result);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
nm_audit_manager_audit_enabled (NMAuditManager *self)
Packit Service b23acc
{
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	if (priv->auditd_fd >= 0)
Packit Service b23acc
		return TRUE;
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
	return nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
_nm_audit_manager_log_connection_op (NMAuditManager *self,
Packit Service b23acc
                                     const char *file,
Packit Service b23acc
                                     guint line,
Packit Service b23acc
                                     const char *func,
Packit Service b23acc
                                     const char *op,
Packit Service b23acc
                                     NMSettingsConnection *connection,
Packit Service b23acc
                                     gboolean result,
Packit Service b23acc
                                     const char *args,
Packit Service b23acc
                                     gpointer subject_context,
Packit Service b23acc
                                     const char *reason)
Packit Service b23acc
{
Packit Service b23acc
	gs_unref_ptrarray GPtrArray *fields = NULL;
Packit Service b23acc
	AuditField uuid_field = { }, name_field = { }, args_field = { };
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (op);
Packit Service b23acc
Packit Service b23acc
	fields = g_ptr_array_new ();
Packit Service b23acc
Packit Service b23acc
	if (connection) {
Packit Service b23acc
		_audit_field_init_string (&uuid_field, "uuid", nm_settings_connection_get_uuid (connection),
Packit Service b23acc
		                          FALSE, BACKEND_ALL);
Packit Service b23acc
		g_ptr_array_add (fields, &uuid_field);
Packit Service b23acc
Packit Service b23acc
		_audit_field_init_string (&name_field, "name", nm_settings_connection_get_id (connection),
Packit Service b23acc
		                          TRUE, BACKEND_ALL);
Packit Service b23acc
		g_ptr_array_add (fields, &name_field);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (args) {
Packit Service b23acc
		_audit_field_init_string (&args_field, "args", args, FALSE, BACKEND_ALL);
Packit Service b23acc
		g_ptr_array_add (fields, &args_field);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
_nm_audit_manager_log_generic_op (NMAuditManager *self, const char *file, guint line,
Packit Service b23acc
                                  const char *func, const char *op, const char *arg,
Packit Service b23acc
                                  gboolean result, gpointer subject_context,
Packit Service b23acc
                                  const char *reason)
Packit Service b23acc
{
Packit Service b23acc
	gs_unref_ptrarray GPtrArray *fields = NULL;
Packit Service b23acc
	AuditField arg_field = { };
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (op);
Packit Service b23acc
	g_return_if_fail (arg);
Packit Service b23acc
Packit Service b23acc
	fields = g_ptr_array_new ();
Packit Service b23acc
Packit Service b23acc
	_audit_field_init_string (&arg_field, "arg", arg, TRUE, BACKEND_ALL);
Packit Service b23acc
	g_ptr_array_add (fields, &arg_field);
Packit Service b23acc
Packit Service b23acc
	_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
_nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line,
Packit Service b23acc
                                 const char *func, const char *op, NMDevice *device,
Packit Service b23acc
                                 gboolean result, const char *args, gpointer subject_context,
Packit Service b23acc
                                 const char *reason)
Packit Service b23acc
{
Packit Service b23acc
	gs_unref_ptrarray GPtrArray *fields = NULL;
Packit Service b23acc
	AuditField interface_field = { }, ifindex_field = { }, args_field = { };
Packit Service b23acc
	int ifindex;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (op);
Packit Service b23acc
	g_return_if_fail (device);
Packit Service b23acc
Packit Service b23acc
	fields = g_ptr_array_new ();
Packit Service b23acc
Packit Service b23acc
	_audit_field_init_string (&interface_field, "interface", nm_device_get_ip_iface (device),
Packit Service b23acc
	                          TRUE, BACKEND_ALL);
Packit Service b23acc
	g_ptr_array_add (fields, &interface_field);
Packit Service b23acc
Packit Service b23acc
	ifindex = nm_device_get_ip_ifindex (device);
Packit Service b23acc
	if (ifindex > 0) {
Packit Service b23acc
		_audit_field_init_uint (&ifindex_field, "ifindex", ifindex, BACKEND_ALL);
Packit Service b23acc
		g_ptr_array_add (fields, &ifindex_field);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (args) {
Packit Service b23acc
		_audit_field_init_string (&args_field, "args", args, FALSE, BACKEND_ALL);
Packit Service b23acc
		g_ptr_array_add (fields, &args_field);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	_audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
static void
Packit Service b23acc
init_auditd (NMAuditManager *self)
Packit Service b23acc
{
Packit Service b23acc
	NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
	NMConfigData *data = nm_config_get_data (priv->config);
Packit Service b23acc
	int errsv;
Packit Service b23acc
Packit Service b23acc
	if (nm_config_data_get_value_boolean (data, NM_CONFIG_KEYFILE_GROUP_LOGGING,
Packit Service b23acc
	                                      NM_CONFIG_KEYFILE_KEY_LOGGING_AUDIT,
Packit Service b23acc
	                                      NM_CONFIG_DEFAULT_LOGGING_AUDIT_BOOL)) {
Packit Service b23acc
		if (priv->auditd_fd < 0) {
Packit Service b23acc
			priv->auditd_fd = audit_open ();
Packit Service b23acc
			if (priv->auditd_fd < 0) {
Packit Service b23acc
				errsv = errno;
Packit Service b23acc
				_LOGE (LOGD_CORE, "failed to open auditd socket: %s", nm_strerror_native (errsv));
Packit Service b23acc
			} else
Packit Service b23acc
				_LOGD (LOGD_CORE, "socket created");
Packit Service b23acc
		}
Packit Service b23acc
	} else {
Packit Service b23acc
		if (priv->auditd_fd >= 0) {
Packit Service b23acc
			audit_close (priv->auditd_fd);
Packit Service b23acc
			priv->auditd_fd = -1;
Packit Service b23acc
			_LOGD (LOGD_CORE, "socket closed");
Packit Service b23acc
		}
Packit Service b23acc
	}
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
config_changed_cb (NMConfig *config,
Packit Service b23acc
                   NMConfigData *config_data,
Packit Service b23acc
                   NMConfigChangeFlags changes,
Packit Service b23acc
                   NMConfigData *old_data,
Packit Service b23acc
                   NMAuditManager *self)
Packit Service b23acc
{
Packit Service b23acc
	if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES))
Packit Service b23acc
		init_auditd (self);
Packit Service b23acc
}
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_audit_manager_init (NMAuditManager *self)
Packit Service b23acc
{
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	priv->config = g_object_ref (nm_config_get ());
Packit Service b23acc
	g_signal_connect (G_OBJECT (priv->config),
Packit Service b23acc
	                  NM_CONFIG_SIGNAL_CONFIG_CHANGED,
Packit Service b23acc
	                  G_CALLBACK (config_changed_cb),
Packit Service b23acc
	                  self);
Packit Service b23acc
	priv->auditd_fd = -1;
Packit Service b23acc
Packit Service b23acc
	init_auditd (self);
Packit Service b23acc
#endif
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
dispose (GObject *object)
Packit Service b23acc
{
Packit Service b23acc
#if HAVE_LIBAUDIT
Packit Service b23acc
	NMAuditManager *self = NM_AUDIT_MANAGER (object);
Packit Service b23acc
	NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	if (priv->config) {
Packit Service b23acc
		g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self);
Packit Service b23acc
		g_clear_object (&priv->config);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	 if (priv->auditd_fd >= 0) {
Packit Service b23acc
		audit_close (priv->auditd_fd);
Packit Service b23acc
		priv->auditd_fd = -1;
Packit Service b23acc
	}
Packit Service b23acc
#endif
Packit Service b23acc
Packit Service b23acc
	G_OBJECT_CLASS (nm_audit_manager_parent_class)->dispose (object);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_audit_manager_class_init (NMAuditManagerClass *klass)
Packit Service b23acc
{
Packit Service b23acc
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service b23acc
Packit Service b23acc
	object_class->dispose = dispose;
Packit Service b23acc
}