PERFORCE change 91634 for review

Christian S.J. Peron csjp at FreeBSD.org
Sun Feb 12 09:52:45 PST 2006


http://perforce.freebsd.org/chv.cgi?CH=91634

Change 91634 by csjp at csjp_xor on 2006/02/12 17:51:52

	
	Take the first stab at adding audit support into su(1). This will create a
	failure token for any error which will result in err{x}(3) being called.
	
	Here is a sample audit trail of a failed, then successful audit trail:
	
	 header,68,1,su(1),0,Sun Feb 12 11:48:01 2006, + 877 msec
	 subject,csjp,root,1001,csjp,1001,863,863,0,0.0.0.0
	 return,failure : Operation not permitted,1
	 trailer,68
	 header,68,1,su(1),0,Sun Feb 12 11:48:03 2006, + 655 msec
	 subject,csjp,root,wheel,root,wheel,865,865,0,0.0.0.0
	 return,success,0
	 trailer,68
	
	This code will conditionally be compiled into su(1) based on the status
	of the NO_AUDIT boolean make flag.

Affected files ...

.. //depot/projects/trustedbsd/audit3/usr.bin/su/Makefile#3 edit
.. //depot/projects/trustedbsd/audit3/usr.bin/su/su.c#5 edit

Differences ...

==== //depot/projects/trustedbsd/audit3/usr.bin/su/Makefile#3 (text+ko) ====

@@ -10,4 +10,10 @@
 BINMODE=4555
 PRECIOUSPROG=
 
+.if !defined(NO_AUDIT)
+CFLAGS+= -DUSE_BSM_AUDIT
+DPADD+= ${LIBBSM}
+LDADD+= -lbsm
+.endif
+
 .include <bsd.prog.mk>

==== //depot/projects/trustedbsd/audit3/usr.bin/su/su.c#5 (text+ko) ====

@@ -81,6 +81,9 @@
 #include <sys/resource.h>
 #include <sys/wait.h>
 
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+
 #include <err.h>
 #include <errno.h>
 #include <grp.h>
@@ -131,6 +134,7 @@
 } while (0)
 
 enum tristate { UNSET, YES, NO };
+enum auditevents { AUDIT_SU_FAILURE, AUDIT_SU_SUCCESS };
 
 static pam_handle_t *pamh = NULL;
 static char	**environ_pam;
@@ -140,6 +144,7 @@
 static void	usage(void) __dead2;
 static void	export_pam_environment(void);
 static int	ok_to_export(const char *);
+static void	audit_su(au_id_t, int);
 
 extern char	**environ;
 
@@ -204,19 +209,31 @@
 		usage();
 	/* NOTREACHED */
 
-	if (strlen(user) > MAXLOGNAME - 1)
+	if (strlen(user) > MAXLOGNAME - 1) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		errx(1, "username too long");
+	}
 
 	/*
 	 * Try to provide more helpful debugging output if su(1) is running
 	 * non-setuid, or was run from a file system not mounted setuid.
 	 */
-	if (geteuid() != 0)
+	if (geteuid() != 0) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		errx(1, "not running setuid");
+	}
 
 	nargv = malloc(sizeof(char *) * (size_t)(argc + 4));
-	if (nargv == NULL)
+	if (nargv == NULL) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		errx(1, "malloc failure");
+	}
 
 	nargv[argc + 3] = NULL;
 	for (i = argc; i >= optind; i--)
@@ -239,12 +256,20 @@
 	pwd = getpwnam(username);
 	if (username == NULL || pwd == NULL || pwd->pw_uid != ruid)
 		pwd = getpwuid(ruid);
-	if (pwd == NULL)
+	if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		errx(1, "who are you?");
+	}
 
 	username = strdup(pwd->pw_name);
-	if (username == NULL)
+	if (username == NULL) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		err(1, "strdup failure");
+	}
 
 	if (asme) {
 		if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
@@ -262,6 +287,9 @@
 	/* Do the whole PAM startup thing */
 	retcode = pam_start("su", user, &conv, &pamh);
 	if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode));
 		errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
 	}
@@ -275,6 +303,9 @@
 
 	retcode = pam_authenticate(pamh, 0);
 	if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+		audit_su(ruid, AUDIT_SU_FAILURE);
+#endif
 		syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s",
 		    username, user, mytty);
 		errx(1, "Sorry");
@@ -286,8 +317,12 @@
 		syslog(LOG_ERR, "pam_get_item(PAM_USER): %s",
 		    pam_strerror(pamh, retcode));
 	pwd = getpwnam(user);
-	if (pwd == NULL)
+	if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		errx(1, "unknown login: %s", user);
+	}
 
 	retcode = pam_acct_mgmt(pamh, 0);
 	if (retcode == PAM_NEW_AUTHTOK_REQD) {
@@ -296,10 +331,16 @@
 		if (retcode != PAM_SUCCESS) {
 			syslog(LOG_ERR, "pam_chauthtok: %s",
 			    pam_strerror(pamh, retcode));
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			errx(1, "Sorry");
 		}
 	}
 	if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		syslog(LOG_ERR, "pam_acct_mgmt: %s",
 			pam_strerror(pamh, retcode));
 		errx(1, "Sorry");
@@ -309,17 +350,29 @@
 	if (class == NULL)
 		lc = login_getpwclass(pwd);
 	else {
-		if (ruid != 0)
+		if (ruid != 0) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			errx(1, "only root may use -c");
+		}
 		lc = login_getclass(class);
-		if (lc == NULL)
+		if (lc == NULL) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			errx(1, "unknown class: %s", class);
+		}
 	}
 
 	/* if asme and non-standard target shell, must be root */
 	if (asme) {
-		if (ruid != 0 && !chshell(pwd->pw_shell))
+		if (ruid != 0 && !chshell(pwd->pw_shell)) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			errx(1, "permission denied (shell)");
+		}
 	}
 	else if (pwd->pw_shell && *pwd->pw_shell) {
 		shell = pwd->pw_shell;
@@ -343,19 +396,30 @@
 
 	/* Switch to home directory */
 	if (asthem) {
-		if (chdir(pwd->pw_dir) < 0)
+		if (chdir(pwd->pw_dir) < 0) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			errx(1, "no directory");
+		}
 	}
 
 	/*
 	 * PAM modules might add supplementary groups in pam_setcred(), so
 	 * initialize them first.
 	 */
-	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)
+	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		err(1, "setusercontext");
+	}
 
 	retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
 	if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		syslog(LOG_ERR, "pam_setcred: %s",
 		    pam_strerror(pamh, retcode));
 		errx(1, "failed to establish credentials.");
@@ -363,6 +427,9 @@
 	if (asthem) {
 		retcode = pam_open_session(pamh, 0);
 		if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			syslog(LOG_ERR, "pam_open_session: %s",
 			    pam_strerror(pamh, retcode));
 			errx(1, "failed to open session.");
@@ -384,6 +451,9 @@
 	statusp = 1;
 	if (pipe(fds) == -1) {
 		PAM_END();
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		err(1, "pipe");
 	}
 	child_pid = fork();
@@ -416,12 +486,19 @@
 		child_pgrp = getpgid(child_pid);
 		if (tcgetpgrp(STDERR_FILENO) == child_pgrp)
 			tcsetpgrp(STDERR_FILENO, getpgrp());
-		if (pid == -1)
+		if (pid == -1) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			err(1, "waitpid");
+		}
 		PAM_END();
 		exit(WEXITSTATUS(statusp));
 	case -1:
 		PAM_END();
+#ifdef USE_BSM_AUDIT
+		audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 		err(1, "fork");
 	case 0:
 		close(fds[1]);
@@ -449,8 +526,12 @@
 		 */
 		if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
 			setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
-		if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
+		if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) {
+#ifdef USE_BSM_AUDIT
+			audit_su(getuid(), AUDIT_SU_FAILURE);
+#endif
 			err(1, "setusercontext");
+		}
 
 		if (!asme) {
 			if (asthem) {
@@ -491,7 +572,10 @@
 		/* csh strips the first character... */
 		*np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su";
 
-		if (ruid != 0)
+#ifdef USE_BSM_AUDIT
+		audit_su(ruid, AUDIT_SU_SUCCESS);
+#endif
+		if (ruid != 0) 
 			syslog(LOG_NOTICE, "%s to %s%s", username, user,
 			    ontty());
 
@@ -578,3 +662,50 @@
 		snprintf(buf, sizeof(buf), " on %s", p);
 	return buf;
 }
+
+#ifdef USE_BSM_AUDIT
+static void
+audit_su(au_id_t au_ctx, int what)
+{
+	token_t *token;
+	long acond;
+	int afd;
+	au_tid_t termid;
+	pid_t pid;
+
+	if (auditon(A_GETCOND, &acond, sizeof(long)) < 0) {
+		/*
+		 * If auditon(2) returns ENOSYS, then audit has not been
+		 * compiled into the kernel, so just return.
+		 */
+		if (errno == ENOSYS)
+			return;
+		err(1, "auditon failed");
+	}
+	afd = au_open();
+	if (afd < 0)
+		err(1, "au_open failed");
+	/* XXX what should we do for termid? */
+	bzero(&termid, sizeof(termid));
+	pid = getpid();
+	token = au_to_subject32(au_ctx, geteuid(), getegid(),
+	    getuid(), getgid(), pid, pid, &termid);
+	if (token == NULL)
+		errx(1, "audit: unable to build subject token");
+	/* XXX what if au_fails? */
+	(void) au_write(afd, token);
+	switch (what) {
+	case AUDIT_SU_FAILURE:
+		token = au_to_return32(1, EPERM);
+		break;
+	case AUDIT_SU_SUCCESS:
+		token = au_to_return32(0, 0);
+		break;
+	}
+	if (token == NULL)
+		errx(1, "audit: unable to build return32 token");
+	(void) au_write(afd, token);
+	if (au_close(afd, 1, AUE_su) < 0)
+		errx(1, "audit: record not committed");
+}
+#endif


More information about the trustedbsd-cvs mailing list