Blame SOURCES/shadow-4.8-selinux-perms.patch

b8f1b8
diff -up shadow-4.8/src/chgpasswd.c.selinux-perms shadow-4.8/src/chgpasswd.c
b8f1b8
--- shadow-4.8/src/chgpasswd.c.selinux-perms	2019-12-01 18:02:43.000000000 +0100
b8f1b8
+++ shadow-4.8/src/chgpasswd.c	2020-01-13 10:21:44.558107260 +0100
b8f1b8
@@ -39,6 +39,13 @@
b8f1b8
 #include <pwd.h>
b8f1b8
 #include <stdio.h>
b8f1b8
 #include <stdlib.h>
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+#include <selinux/selinux.h>
b8f1b8
+#include <selinux/avc.h>
b8f1b8
+#endif
b8f1b8
+#ifdef WITH_LIBAUDIT
b8f1b8
+#include <libaudit.h>
b8f1b8
+#endif
b8f1b8
 #ifdef ACCT_TOOLS_SETUID
b8f1b8
 #ifdef USE_PAM
b8f1b8
 #include "pam_defs.h"
b8f1b8
@@ -80,6 +87,9 @@ static bool sgr_locked = false;
b8f1b8
 #endif
b8f1b8
 static bool gr_locked = false;
b8f1b8
 
b8f1b8
+/* The name of the caller */
b8f1b8
+static char *myname = NULL;
b8f1b8
+
b8f1b8
 /* local function prototypes */
b8f1b8
 static void fail_exit (int code);
b8f1b8
 static /*@noreturn@*/void usage (int status);
b8f1b8
@@ -334,6 +344,63 @@ static void check_perms (void)
b8f1b8
 #endif				/* ACCT_TOOLS_SETUID */
b8f1b8
 }
b8f1b8
 
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+static int
b8f1b8
+log_callback (int type, const char *fmt, ...)
b8f1b8
+{
b8f1b8
+    int audit_fd;
b8f1b8
+    va_list ap;
b8f1b8
+
b8f1b8
+    va_start(ap, fmt);
b8f1b8
+#ifdef WITH_AUDIT
b8f1b8
+    audit_fd = audit_open();
b8f1b8
+
b8f1b8
+    if (audit_fd >= 0) {
b8f1b8
+	char *buf;
b8f1b8
+
b8f1b8
+	if (vasprintf (&buf, fmt, ap) < 0)
b8f1b8
+		goto ret;
b8f1b8
+	audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
b8f1b8
+				   NULL, 0);
b8f1b8
+	audit_close(audit_fd);
b8f1b8
+	free(buf);
b8f1b8
+	goto ret;
b8f1b8
+    }
b8f1b8
+
b8f1b8
+#endif
b8f1b8
+    vsyslog (LOG_USER | LOG_INFO, fmt, ap);
b8f1b8
+ret:
b8f1b8
+    va_end(ap);
b8f1b8
+    return 0;
b8f1b8
+}
b8f1b8
+
b8f1b8
+static void
b8f1b8
+selinux_check_root (void)
b8f1b8
+{
b8f1b8
+    int status = -1;
b8f1b8
+    security_context_t user_context;
b8f1b8
+    union selinux_callback old_callback;
b8f1b8
+
b8f1b8
+    if (is_selinux_enabled() < 1)
b8f1b8
+	return;
b8f1b8
+
b8f1b8
+    old_callback = selinux_get_callback(SELINUX_CB_LOG);
b8f1b8
+    /* setup callbacks */
b8f1b8
+    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback);
b8f1b8
+    if ((status = getprevcon(&user_context)) < 0) {
b8f1b8
+	selinux_set_callback(SELINUX_CB_LOG, old_callback);
b8f1b8
+	exit(1);
b8f1b8
+    }
b8f1b8
+
b8f1b8
+    status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL);
b8f1b8
+
b8f1b8
+    selinux_set_callback(SELINUX_CB_LOG, old_callback);
b8f1b8
+    freecon(user_context);
b8f1b8
+    if (status != 0 && security_getenforce() != 0)
b8f1b8
+	exit(1);
b8f1b8
+}
b8f1b8
+#endif
b8f1b8
+
b8f1b8
 /*
b8f1b8
  * open_files - lock and open the group databases
b8f1b8
  */
b8f1b8
@@ -427,6 +494,7 @@ int main (int argc, char **argv)
b8f1b8
 
b8f1b8
 	const struct group *gr;
b8f1b8
 	struct group newgr;
b8f1b8
+	struct passwd *pw = NULL;
b8f1b8
 	int errors = 0;
b8f1b8
 	int line = 0;
b8f1b8
 
b8f1b8
@@ -436,12 +504,37 @@ int main (int argc, char **argv)
b8f1b8
 	(void) bindtextdomain (PACKAGE, LOCALEDIR);
b8f1b8
 	(void) textdomain (PACKAGE);
b8f1b8
 
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+	selinux_check_root ();
b8f1b8
+#endif
b8f1b8
+
b8f1b8
 	process_root_flag ("-R", argc, argv);
b8f1b8
 
b8f1b8
 	process_flags (argc, argv);
b8f1b8
 
b8f1b8
 	OPENLOG ("chgpasswd");
b8f1b8
 
b8f1b8
+#ifdef WITH_AUDIT
b8f1b8
+	audit_help_open ();
b8f1b8
+#endif
b8f1b8
+
b8f1b8
+	/*
b8f1b8
+	 * Determine the name of the user that invoked this command. This
b8f1b8
+	 * is really hit or miss because there are so many ways that command
b8f1b8
+	 * can be executed and so many ways to trip up the routines that
b8f1b8
+	 * report the user name.
b8f1b8
+	 */
b8f1b8
+	pw = get_my_pwent ();
b8f1b8
+	if (NULL == pw) {
b8f1b8
+		fprintf (stderr, _("%s: Cannot determine your user name.\n"),
b8f1b8
+		         Prog);
b8f1b8
+		SYSLOG ((LOG_WARN,
b8f1b8
+		         "Cannot determine the user name of the caller (UID %lu)",
b8f1b8
+		         (unsigned long) getuid ()));
b8f1b8
+		exit (E_NOPERM);
b8f1b8
+	}
b8f1b8
+	myname = xstrdup (pw->pw_name);
b8f1b8
+
b8f1b8
 	check_perms ();
b8f1b8
 
b8f1b8
 #ifdef SHADOWGRP
b8f1b8
diff -up shadow-4.8/src/chpasswd.c.selinux-perms shadow-4.8/src/chpasswd.c
b8f1b8
--- shadow-4.8/src/chpasswd.c.selinux-perms	2019-12-01 18:02:43.000000000 +0100
b8f1b8
+++ shadow-4.8/src/chpasswd.c	2020-01-13 10:21:44.558107260 +0100
b8f1b8
@@ -39,6 +39,13 @@
b8f1b8
 #include <pwd.h>
b8f1b8
 #include <stdio.h>
b8f1b8
 #include <stdlib.h>
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+#include <selinux/selinux.h>
b8f1b8
+#include <selinux/avc.h>
b8f1b8
+#endif
b8f1b8
+#ifdef WITH_LIBAUDIT
b8f1b8
+#include <libaudit.h>
b8f1b8
+#endif
b8f1b8
 #ifdef USE_PAM
b8f1b8
 #include "pam_defs.h"
b8f1b8
 #endif				/* USE_PAM */
b8f1b8
@@ -332,6 +339,63 @@ static void check_perms (void)
b8f1b8
 #endif				/* USE_PAM */
b8f1b8
 }
b8f1b8
 
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+static int
b8f1b8
+log_callback (int type, const char *fmt, ...)
b8f1b8
+{
b8f1b8
+    int audit_fd;
b8f1b8
+    va_list ap;
b8f1b8
+
b8f1b8
+    va_start(ap, fmt);
b8f1b8
+#ifdef WITH_AUDIT
b8f1b8
+    audit_fd = audit_open();
b8f1b8
+
b8f1b8
+    if (audit_fd >= 0) {
b8f1b8
+	char *buf;
b8f1b8
+
b8f1b8
+	if (vasprintf (&buf, fmt, ap) < 0)
b8f1b8
+		goto ret;
b8f1b8
+	audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
b8f1b8
+				   NULL, 0);
b8f1b8
+	audit_close(audit_fd);
b8f1b8
+	free(buf);
b8f1b8
+	goto ret;
b8f1b8
+    }
b8f1b8
+
b8f1b8
+#endif
b8f1b8
+    vsyslog (LOG_USER | LOG_INFO, fmt, ap);
b8f1b8
+ret:
b8f1b8
+    va_end(ap);
b8f1b8
+    return 0;
b8f1b8
+}
b8f1b8
+
b8f1b8
+static void
b8f1b8
+selinux_check_root (void)
b8f1b8
+{
b8f1b8
+    int status = -1;
b8f1b8
+    security_context_t user_context;
b8f1b8
+    union selinux_callback old_callback;
b8f1b8
+
b8f1b8
+    if (is_selinux_enabled() < 1)
b8f1b8
+	return;
b8f1b8
+
b8f1b8
+    old_callback = selinux_get_callback(SELINUX_CB_LOG);
b8f1b8
+    /* setup callbacks */
b8f1b8
+    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback);
b8f1b8
+    if ((status = getprevcon(&user_context)) < 0) {
b8f1b8
+	selinux_set_callback(SELINUX_CB_LOG, old_callback);
b8f1b8
+	exit(1);
b8f1b8
+    }
b8f1b8
+
b8f1b8
+    status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL);
b8f1b8
+
b8f1b8
+    selinux_set_callback(SELINUX_CB_LOG, old_callback);
b8f1b8
+    freecon(user_context);
b8f1b8
+    if (status != 0 && security_getenforce() != 0)
b8f1b8
+	exit(1);
b8f1b8
+}
b8f1b8
+#endif
b8f1b8
+
b8f1b8
 /*
b8f1b8
  * open_files - lock and open the password databases
b8f1b8
  */
b8f1b8
@@ -428,6 +492,10 @@ int main (int argc, char **argv)
b8f1b8
 	(void) bindtextdomain (PACKAGE, LOCALEDIR);
b8f1b8
 	(void) textdomain (PACKAGE);
b8f1b8
 
b8f1b8
+#ifdef WITH_SELINUX
b8f1b8
+	selinux_check_root ();
b8f1b8
+#endif
b8f1b8
+
b8f1b8
 	process_root_flag ("-R", argc, argv);
b8f1b8
 
b8f1b8
 	process_flags (argc, argv);
b8f1b8
@@ -440,6 +508,10 @@ int main (int argc, char **argv)
b8f1b8
 
b8f1b8
 	OPENLOG ("chpasswd");
b8f1b8
 
b8f1b8
+#ifdef WITH_AUDIT
b8f1b8
+	audit_help_open ();
b8f1b8
+#endif
b8f1b8
+
b8f1b8
 	check_perms ();
b8f1b8
 
b8f1b8
 #ifdef USE_PAM