fa2969
diff -up shadow-4.1.5.1/src/chgpasswd.c.selinux-perms shadow-4.1.5.1/src/chgpasswd.c
fa2969
--- shadow-4.1.5.1/src/chgpasswd.c.selinux-perms	2016-05-04 13:44:55.633787764 +0200
fa2969
+++ shadow-4.1.5.1/src/chgpasswd.c	2016-05-30 12:01:30.421587253 +0200
fa2969
@@ -39,6 +39,13 @@
fa2969
 #include <pwd.h>
fa2969
 #include <stdio.h>
fa2969
 #include <stdlib.h>
fa2969
+#ifdef WITH_SELINUX
fa2969
+#include <selinux/selinux.h>
fa2969
+#include <selinux/avc.h>
fa2969
+#endif
fa2969
+#ifdef WITH_LIBAUDIT
fa2969
+#include <libaudit.h>
fa2969
+#endif
fa2969
 #ifdef ACCT_TOOLS_SETUID
fa2969
 #ifdef USE_PAM
fa2969
 #include "pam_defs.h"
fa2969
@@ -76,6 +83,9 @@ static bool sgr_locked = false;
fa2969
 #endif
fa2969
 static bool gr_locked = false;
fa2969
 
fa2969
+/* The name of the caller */
fa2969
+static char *myname = NULL;
fa2969
+
fa2969
 /* local function prototypes */
fa2969
 static void fail_exit (int code);
fa2969
 static /*@noreturn@*/void usage (int status);
fa2969
@@ -300,6 +310,63 @@ static void check_perms (void)
fa2969
 #endif				/* ACCT_TOOLS_SETUID */
fa2969
 }
fa2969
 
fa2969
+#ifdef WITH_SELINUX
fa2969
+static int
fa2969
+log_callback (int type, const char *fmt, ...)
fa2969
+{
fa2969
+    int audit_fd;
fa2969
+    va_list ap;
fa2969
+
fa2969
+    va_start(ap, fmt);
fa2969
+#ifdef WITH_AUDIT
fa2969
+    audit_fd = audit_open();
fa2969
+
fa2969
+    if (audit_fd >= 0) {
fa2969
+	char *buf;
fa2969
+
fa2969
+	if (vasprintf (&buf, fmt, ap) < 0)
fa2969
+		goto ret;
fa2969
+	audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
fa2969
+				   NULL, 0);
fa2969
+	audit_close(audit_fd);
fa2969
+	free(buf);
fa2969
+	goto ret;
fa2969
+    }
fa2969
+
fa2969
+#endif
fa2969
+    vsyslog (LOG_USER | LOG_INFO, fmt, ap);
fa2969
+ret:
fa2969
+    va_end(ap);
fa2969
+    return 0;
fa2969
+}
fa2969
+
fa2969
+static void
fa2969
+selinux_check_root (void)
fa2969
+{
fa2969
+    int status = -1;
fa2969
+    security_context_t user_context;
fa2969
+    union selinux_callback old_callback;
fa2969
+
fa2969
+    if (is_selinux_enabled() < 1)
fa2969
+	return;
fa2969
+
fa2969
+    old_callback = selinux_get_callback(SELINUX_CB_LOG);
fa2969
+    /* setup callbacks */
fa2969
+    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback);
fa2969
+    if ((status = getprevcon(&user_context)) < 0) {
fa2969
+	selinux_set_callback(SELINUX_CB_LOG, old_callback);
fa2969
+	exit(1);
fa2969
+    }
fa2969
+
fa2969
+    status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL);
fa2969
+
fa2969
+    selinux_set_callback(SELINUX_CB_LOG, old_callback);
fa2969
+    freecon(user_context);
fa2969
+    if (status != 0 && security_getenforce() != 0)
fa2969
+	exit(1);
fa2969
+}
fa2969
+#endif
fa2969
+
fa2969
 /*
fa2969
  * open_files - lock and open the group databases
fa2969
  */
fa2969
@@ -393,6 +460,7 @@ int main (int argc, char **argv)
fa2969
 
fa2969
 	const struct group *gr;
fa2969
 	struct group newgr;
fa2969
+	struct passwd *pw = NULL;
fa2969
 	int errors = 0;
fa2969
 	int line = 0;
fa2969
 
fa2969
@@ -408,8 +476,33 @@ int main (int argc, char **argv)
fa2969
 
fa2969
 	OPENLOG ("chgpasswd");
fa2969
 
fa2969
+#ifdef WITH_AUDIT
fa2969
+	audit_help_open ();
fa2969
+#endif
fa2969
+
fa2969
+	/*
fa2969
+	 * Determine the name of the user that invoked this command. This
fa2969
+	 * is really hit or miss because there are so many ways that command
fa2969
+	 * can be executed and so many ways to trip up the routines that
fa2969
+	 * report the user name.
fa2969
+	 */
fa2969
+	pw = get_my_pwent ();
fa2969
+	if (NULL == pw) {
fa2969
+		fprintf (stderr, _("%s: Cannot determine your user name.\n"),
fa2969
+		         Prog);
fa2969
+		SYSLOG ((LOG_WARN,
fa2969
+		         "Cannot determine the user name of the caller (UID %lu)",
fa2969
+		         (unsigned long) getuid ()));
fa2969
+		exit (E_NOPERM);
fa2969
+	}
fa2969
+	myname = xstrdup (pw->pw_name);
fa2969
+
fa2969
 	check_perms ();
fa2969
 
fa2969
+#ifdef WITH_SELINUX
fa2969
+	selinux_check_root ();
fa2969
+#endif
fa2969
+
fa2969
 #ifdef SHADOWGRP
fa2969
 	is_shadow_grp = sgr_file_present ();
fa2969
 #endif
fa2969
@@ -533,6 +626,15 @@ int main (int argc, char **argv)
fa2969
 			newgr.gr_passwd = cp;
fa2969
 		}
fa2969
 
fa2969
+#ifdef WITH_AUDIT
fa2969
+		{
fa2969
+
fa2969
+			audit_logger_with_group (AUDIT_GRP_CHAUTHTOK, Prog,
fa2969
+		              "change-password",
fa2969
+		              myname, AUDIT_NO_ID, gr->gr_name,
fa2969
+		              SHADOW_AUDIT_SUCCESS);
fa2969
+		}
fa2969
+#endif
fa2969
 		/* 
fa2969
 		 * The updated group file entry is then put back and will
fa2969
 		 * be written to the group file later, after all the
fa2969
diff -up shadow-4.1.5.1/src/chpasswd.c.selinux-perms shadow-4.1.5.1/src/chpasswd.c
fa2969
--- shadow-4.1.5.1/src/chpasswd.c.selinux-perms	2016-05-04 13:44:55.633787764 +0200
fa2969
+++ shadow-4.1.5.1/src/chpasswd.c	2016-05-30 12:01:42.877859957 +0200
fa2969
@@ -39,6 +39,13 @@
fa2969
 #include <pwd.h>
fa2969
 #include <stdio.h>
fa2969
 #include <stdlib.h>
fa2969
+#ifdef WITH_SELINUX
fa2969
+#include <selinux/selinux.h>
fa2969
+#include <selinux/avc.h>
fa2969
+#endif
fa2969
+#ifdef WITH_LIBAUDIT
fa2969
+#include <libaudit.h>
fa2969
+#endif
fa2969
 #ifdef USE_PAM
fa2969
 #include "pam_defs.h"
fa2969
 #endif				/* USE_PAM */
fa2969
@@ -297,6 +304,63 @@ static void check_perms (void)
fa2969
 #endif				/* USE_PAM */
fa2969
 }
fa2969
 
fa2969
+#ifdef WITH_SELINUX
fa2969
+static int
fa2969
+log_callback (int type, const char *fmt, ...)
fa2969
+{
fa2969
+    int audit_fd;
fa2969
+    va_list ap;
fa2969
+
fa2969
+    va_start(ap, fmt);
fa2969
+#ifdef WITH_AUDIT
fa2969
+    audit_fd = audit_open();
fa2969
+
fa2969
+    if (audit_fd >= 0) {
fa2969
+	char *buf;
fa2969
+
fa2969
+	if (vasprintf (&buf, fmt, ap) < 0)
fa2969
+		goto ret;
fa2969
+	audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
fa2969
+				   NULL, 0);
fa2969
+	audit_close(audit_fd);
fa2969
+	free(buf);
fa2969
+	goto ret;
fa2969
+    }
fa2969
+
fa2969
+#endif
fa2969
+    vsyslog (LOG_USER | LOG_INFO, fmt, ap);
fa2969
+ret:
fa2969
+    va_end(ap);
fa2969
+    return 0;
fa2969
+}
fa2969
+
fa2969
+static void
fa2969
+selinux_check_root (void)
fa2969
+{
fa2969
+    int status = -1;
fa2969
+    security_context_t user_context;
fa2969
+    union selinux_callback old_callback;
fa2969
+
fa2969
+    if (is_selinux_enabled() < 1)
fa2969
+	return;
fa2969
+
fa2969
+    old_callback = selinux_get_callback(SELINUX_CB_LOG);
fa2969
+    /* setup callbacks */
fa2969
+    selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback);
fa2969
+    if ((status = getprevcon(&user_context)) < 0) {
fa2969
+	selinux_set_callback(SELINUX_CB_LOG, old_callback);
fa2969
+	exit(1);
fa2969
+    }
fa2969
+
fa2969
+    status = selinux_check_access(user_context, user_context, "passwd", "passwd", NULL);
fa2969
+
fa2969
+    selinux_set_callback(SELINUX_CB_LOG, old_callback);
fa2969
+    freecon(user_context);
fa2969
+    if (status != 0 && security_getenforce() != 0)
fa2969
+	exit(1);
fa2969
+}
fa2969
+#endif
fa2969
+
fa2969
 /*
fa2969
  * open_files - lock and open the password databases
fa2969
  */
fa2969
@@ -405,8 +469,16 @@ int main (int argc, char **argv)
fa2969
 
fa2969
 	OPENLOG ("chpasswd");
fa2969
 
fa2969
+#ifdef WITH_AUDIT
fa2969
+	audit_help_open ();
fa2969
+#endif
fa2969
+
fa2969
 	check_perms ();
fa2969
 
fa2969
+#ifdef WITH_SELINUX
fa2969
+	selinux_check_root ();
fa2969
+#endif
fa2969
+
fa2969
 #ifdef USE_PAM
fa2969
 	if (!use_pam)
fa2969
 #endif				/* USE_PAM */
fa2969
@@ -563,6 +635,11 @@ int main (int argc, char **argv)
fa2969
 			newpw.pw_passwd = cp;
fa2969
 		}
fa2969
 
fa2969
+#ifdef WITH_AUDIT
fa2969
+		audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
fa2969
+		              "updating-password",
fa2969
+		              pw->pw_name, (unsigned int) pw->pw_uid, 1);
fa2969
+#endif
fa2969
 		/* 
fa2969
 		 * The updated password file entry is then put back and will
fa2969
 		 * be written to the password file later, after all the
fa2969
diff -up shadow-4.1.5.1/src/Makefile.am.selinux-perms shadow-4.1.5.1/src/Makefile.am
fa2969
--- shadow-4.1.5.1/src/Makefile.am.selinux-perms	2016-05-04 13:44:55.647788082 +0200
fa2969
+++ shadow-4.1.5.1/src/Makefile.am	2016-05-27 16:04:49.446582632 +0200
fa2969
@@ -79,9 +79,9 @@ endif
fa2969
 
fa2969
 chage_LDADD    = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
fa2969
 chfn_LDADD     = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
fa2969
-chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT)
fa2969
+chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT)
fa2969
 chsh_LDADD     = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
fa2969
-chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT)
fa2969
+chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT)
fa2969
 gpasswd_LDADD  = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT)
fa2969
 groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
fa2969
 groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
fa2969
diff -up shadow-4.1.5.1/src/Makefile.in.selinux-perms shadow-4.1.5.1/src/Makefile.in
fa2969
--- shadow-4.1.5.1/src/Makefile.in.selinux-perms	2016-05-04 13:44:55.647788082 +0200
fa2969
+++ shadow-4.1.5.1/src/Makefile.in	2016-05-27 16:04:49.447582654 +0200
fa2969
@@ -437,9 +437,9 @@ AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/l
fa2969
 @USE_PAM_TRUE@LIBCRYPT_NOPAM = 
fa2969
 chage_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
fa2969
 chfn_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
fa2969
-chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT)
fa2969
+chgpasswd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT)
fa2969
 chsh_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
fa2969
-chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT)
fa2969
+chpasswd_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBAUDIT) $(LIBCRYPT)
fa2969
 gpasswd_LDADD = $(LDADD) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT)
fa2969
 groupadd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)
fa2969
 groupdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX)