From 11dcecc60b03c6c6c4f9d4ecffe383bace912fd2 Mon Sep 17 00:00:00 2001
From: Dan Walsh <dwalsh@redhat.com>
Date: Wed, 9 Oct 2013 16:47:24 -0400
Subject: [PATCH 22/74] Pull auditing into libsemanage.

In the past we wrote audit into the semanage tool chain.  But if a tool like useradd
called dirreclty into libsemanage we did not get auditing.  Now useradd calls directly,
so we need this patch.

Another fix in this patch is to default the login mappings MLS to the selected SELinux User.
If a caller just specified the name staff_u, then the code will look up the range of staff_u
and apply it to the mapping.
---
 libsemanage/src/Makefile        |   2 +-
 libsemanage/src/seusers_local.c | 158 +++++++++++++++++++++++++++++++++++++++-
 libsemanage/src/users_local.c   |  39 ++++++++++
 3 files changed, 194 insertions(+), 5 deletions(-)

diff --git a/libsemanage/src/Makefile b/libsemanage/src/Makefile
index c63bb22..edb84cc 100644
--- a/libsemanage/src/Makefile
+++ b/libsemanage/src/Makefile
@@ -92,7 +92,7 @@ $(LIBA): $(OBJS)
 	$(RANLIB) $@
 
 $(LIBSO): $(LOBJS)
-	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -lsepol -lselinux -lbz2 -lustr -L$(LIBDIR) -Wl,-soname,$(LIBSO),--version-script=libsemanage.map,-z,defs
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -lsepol -laudit -lselinux -lbz2 -lustr -L$(LIBDIR) -Wl,-soname,$(LIBSO),--version-script=libsemanage.map,-z,defs
 	ln -sf $@ $(TARGET)
 
 $(LIBPC): $(LIBPC).in ../VERSION
diff --git a/libsemanage/src/seusers_local.c b/libsemanage/src/seusers_local.c
index e7cf12c..f379211 100644
--- a/libsemanage/src/seusers_local.c
+++ b/libsemanage/src/seusers_local.c
@@ -8,27 +8,177 @@ typedef struct semanage_seuser record_t;
 
 #include <sepol/policydb.h>
 #include <sepol/context.h>
+#include <libaudit.h>
+#include <errno.h>
 #include "user_internal.h"
 #include "seuser_internal.h"
 #include "handle.h"
 #include "database.h"
 #include "debug.h"
+#include "string.h"
+#include <stdlib.h>
+
+static char *semanage_user_roles(semanage_handle_t * handle, const char *sename) {
+	char *roles = NULL;
+	unsigned int num_roles;
+	size_t i;
+	size_t size = 0;
+	const char **roles_arr;
+	semanage_user_key_t *key = NULL;
+	semanage_user_t * user;
+	if (semanage_user_key_create(handle, sename, &key) >= 0) {
+		if (semanage_user_query(handle, key, &user) >= 0) {
+			if (semanage_user_get_roles(handle, 
+						    user, 
+						    &roles_arr, 
+						    &num_roles) >= 0) {
+				for (i = 0; i<num_roles; i++) {
+					size += (strlen(roles_arr[i]) + 1);
+				}
+				roles = malloc(size);
+				if (roles) {
+					strcpy(roles,roles_arr[0]);
+					for (i = 1; i<num_roles; i++) {
+						strcat(roles,",");
+						strcat(roles,roles_arr[i]);
+					}
+				}
+			}
+			semanage_user_free(user);
+		}
+		semanage_user_key_free(key);
+	}
+	return roles;
+}
+
+static int semanage_seuser_audit(semanage_handle_t * handle,
+			  const semanage_seuser_t * seuser, 
+			  const semanage_seuser_t * previous,
+			  int audit_type, 
+			  int success) {
+	const char *name = NULL;
+	const char *sename = NULL;
+	char *roles = NULL;
+	const char *mls = NULL;
+	const char *psename = NULL;
+	const char *pmls = NULL;
+	char *proles = NULL;
+	char msg[1024];
+	const char *sep = "-";
+	int rc = -1;
+	strcpy(msg, "login");
+	if (seuser) {
+		name = semanage_seuser_get_name(seuser);
+		sename = semanage_seuser_get_sename(seuser);
+		mls = semanage_seuser_get_mlsrange(seuser);
+		roles = semanage_user_roles(handle, sename);
+	}
+	if (previous) {
+		psename = semanage_seuser_get_sename(previous);
+		pmls = semanage_seuser_get_mlsrange(previous);
+		proles = semanage_user_roles(handle, psename);
+	}
+	if (audit_type != AUDIT_ROLE_REMOVE) {
+		if (sename && (!psename || strcmp(psename, sename) != 0)) {
+			strcat(msg,sep);
+			strcat(msg,"sename");
+			sep = ",";
+		}
+		if (roles && (!proles || strcmp(proles, roles) != 0)) {
+			strcat(msg,sep);
+			strcat(msg,"role");
+			sep = ",";
+		}
+		if (mls && (!pmls || strcmp(pmls, mls) != 0)) {
+			strcat(msg,sep);
+			strcat(msg,"range");
+		}
+	}
+
+	int fd = audit_open();
+	if (fd < 0)
+	{
+		/* If kernel doesn't support audit, bail out */
+		if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
+			rc = 0;
+			goto err;
+		}
+		rc = fd;
+		goto err;
+	}
+	audit_log_semanage_message(fd, audit_type, NULL, msg, name, 0, sename, roles, mls, psename, proles, pmls, NULL, NULL,NULL, success);
+	rc = 0;
+err:
+	audit_close(fd);
+	free(roles);
+	free(proles);
+	return rc;
+}
 
 int semanage_seuser_modify_local(semanage_handle_t * handle,
 				 const semanage_seuser_key_t * key,
 				 const semanage_seuser_t * data)
 {
-
+	int rc;
+	void *callback = (void *) handle->msg_callback;
 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
-	return dbase_modify(handle, dconfig, key, data);
+	const char *sename = semanage_seuser_get_sename(data);
+	const char *mls_range = semanage_seuser_get_mlsrange(data);
+	semanage_seuser_t *previous = NULL;
+	semanage_seuser_t *new = NULL;
+
+	if (!sename) {
+		errno=EINVAL;
+		return -1;
+	}
+	if (semanage_seuser_clone(handle, data, &new) < 0) {
+		goto err;
+	}
+		
+	if (!mls_range && semanage_mls_enabled(handle)) {
+		semanage_user_key_t *ukey = NULL;
+		semanage_user_t *u = NULL;
+		rc = semanage_user_key_create(handle, sename, &ukey);
+		if (rc < 0)
+			goto err;
+
+		rc = semanage_user_query(handle, ukey, &u);
+		semanage_user_key_free(ukey);
+		if (rc >= 0 ) {
+			mls_range = semanage_user_get_mlsrange(u);
+			rc = semanage_seuser_set_mlsrange(handle, new, mls_range);
+			semanage_user_free(u);
+		}
+		if (rc < 0)
+			goto err;
+	}
+
+	handle->msg_callback = NULL;
+	(void) semanage_seuser_query(handle, key, &previous);
+	handle->msg_callback = callback;
+	rc = dbase_modify(handle, dconfig, key, new);
+	if (semanage_seuser_audit(handle, new, previous, AUDIT_ROLE_ASSIGN, rc == 0) < 0) 
+		rc = -1;
+err:
+	if (previous)
+		semanage_seuser_free(previous);
+	semanage_seuser_free(new);
+	return rc;
 }
 
 int semanage_seuser_del_local(semanage_handle_t * handle,
 			      const semanage_seuser_key_t * key)
 {
-
+	int rc;
+	semanage_seuser_t *seuser = NULL;
 	dbase_config_t *dconfig = semanage_seuser_dbase_local(handle);
-	return dbase_del(handle, dconfig, key);
+	rc = dbase_del(handle, dconfig, key);
+	semanage_seuser_query(handle, key, &seuser);
+	if (semanage_seuser_audit(handle, NULL, seuser, AUDIT_ROLE_REMOVE, rc == 0) < 0) 
+		rc = -1;
+	if (seuser)
+		semanage_seuser_free(seuser);
+	return rc;
 }
 
 int semanage_seuser_query_local(semanage_handle_t * handle,
diff --git a/libsemanage/src/users_local.c b/libsemanage/src/users_local.c
index 8742ca1..b78ad0e 100644
--- a/libsemanage/src/users_local.c
+++ b/libsemanage/src/users_local.c
@@ -6,9 +6,14 @@ typedef struct semanage_user_key record_key_t;
 typedef struct semanage_user record_t;
 #define DBASE_RECORD_DEFINED
 
+#include <string.h>
+#include <stdlib.h>
 #include "user_internal.h"
+#include "seuser_internal.h"
 #include "handle.h"
 #include "database.h"
+#include "errno.h"
+#include "debug.h"
 
 int semanage_user_modify_local(semanage_handle_t * handle,
 			       const semanage_user_key_t * key,
@@ -19,9 +24,43 @@ int semanage_user_modify_local(semanage_handle_t * handle,
 	return dbase_modify(handle, dconfig, key, data);
 }
 
+static int lookup_seuser(semanage_handle_t * handle, const semanage_user_key_t *k) {
+	semanage_user_t *user;
+	semanage_seuser_t **records;
+	const char *name;
+	const char *sename;
+	unsigned int count;
+	size_t i;
+	int rc = 0;
+	if (semanage_user_query(handle, k, &user) < 0)
+		return 0;
+	name = semanage_user_get_name(user);
+	semanage_seuser_list_local(handle,
+				   &records,
+				   &count);
+	for(i=0; i<count; i++) {
+		sename = semanage_seuser_get_sename(records[i]);
+		if (strcmp(name, sename) == 0) {
+			errno = EINVAL;
+			ERR(handle, "%s is being used by %s login record", 
+			    sename, semanage_seuser_get_name(records[i]));
+			rc = -1;
+		}
+	}
+	for(i=0; i<count; i++)
+		semanage_seuser_free(records[i]);
+	free(records);
+	semanage_user_free(user);
+	if (rc)
+		errno = EINVAL;
+	return rc;
+}
+
 int semanage_user_del_local(semanage_handle_t * handle,
 			    const semanage_user_key_t * key)
 {
+	if (lookup_seuser(handle, key))
+		return -1;
 
 	dbase_config_t *dconfig = semanage_user_dbase_local(handle);
 	return dbase_del(handle, dconfig, key);
-- 
1.8.3.1

