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