From owner-p4-projects@FreeBSD.ORG Sun Feb 12 17:52:43 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id D017316A423; Sun, 12 Feb 2006 17:52:42 +0000 (GMT) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8F46116A420 for ; Sun, 12 Feb 2006 17:52:42 +0000 (GMT) (envelope-from csjp@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 479ED43D46 for ; Sun, 12 Feb 2006 17:52:42 +0000 (GMT) (envelope-from csjp@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id k1CHqgXB093766 for ; Sun, 12 Feb 2006 17:52:42 GMT (envelope-from csjp@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id k1CHqf6M093763 for perforce@freebsd.org; Sun, 12 Feb 2006 17:52:41 GMT (envelope-from csjp@freebsd.org) Date: Sun, 12 Feb 2006 17:52:41 GMT Message-Id: <200602121752.k1CHqf6M093763@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to csjp@freebsd.org using -f From: "Christian S.J. Peron" To: Perforce Change Reviews Cc: Subject: PERFORCE change 91634 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Feb 2006 17:52:43 -0000 http://perforce.freebsd.org/chv.cgi?CH=91634 Change 91634 by csjp@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 ==== //depot/projects/trustedbsd/audit3/usr.bin/su/su.c#5 (text+ko) ==== @@ -81,6 +81,9 @@ #include #include +#include +#include + #include #include #include @@ -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