Date: Sat, 20 Jan 2001 23:58:23 -0500 From: "David J. MacKenzie" <djm@web.us.uu.net> To: freebsd-security@freebsd.org Cc: djm@web.us.uu.net Subject: PAM patch, iteration 3 Message-ID: <20010121045823.59DB212686@jenkins.web.us.uu.net>
next in thread | raw e-mail | index | archive | help
After reading the RFC and considering my code some more, I've made more fixes to it, including initialization of supplementary groups and environment variables, and several other fixes. As before, this patch replaces the previous two that I sent out. It was generated against -stable. The rshd with PAM and without Kerberos won't be very useful until FreeBSD imports the pam_rhosts module from Linux-PAM. I don't think the rcmd/rsh protocol provides a way to prompt the remote user for a password. login was alone in using NO_PAM instead of USE_PAM for the #ifdef. sshd used USE_PAM and I used that in the other utilities as well, so I changed login to match. I think it's easier to understand that way. The Linux-PAM manual, the RFC example, and the Solaris man page all indicate that this patch to pam_setcred.3 is correct. --- ./contrib/libpam/doc/man/pam_setcred.3 1998/11/18 01:20:54 1.1 +++ ./contrib/libpam/doc/man/pam_setcred.3 2001/01/21 00:08:26 @@ -16,7 +16,7 @@ This function is used to establish, maintain and delete the credentials of a user. It should be called after a user has been -authenticated and before a session is opened for the user (with +authenticated and after a session is opened for the user (with .BR pam_open_session "(3))." It should be noted that credentials come in many forms. Examples --- ./libexec/rshd/Makefile 2001/01/17 00:04:57 1.1 +++ ./libexec/rshd/Makefile 2001/01/21 04:45:35 @@ -12,6 +12,12 @@ DPADD+= ${LIBUTIL} LDADD+= -lutil +.if !defined(NOPAM) +CFLAGS+= -DUSE_PAM +DPADD+= ${LIBPAM} +LDADD+= ${MINUSLPAM} +.endif + # IPv6 support CFLAGS+= -DINET6 --- ./libexec/rshd/rshd.c 2000/11/12 07:00:38 1.1 +++ ./libexec/rshd/rshd.c 2001/01/21 04:25:51 @@ -80,6 +80,20 @@ #include <login_cap.h> #endif +#ifdef USE_PAM +#include <security/pam_appl.h> +#include <sys/wait.h> +static pam_handle_t *pamh; +#define PAM_END { \ + if ((retcode = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, retcode)); \ + if ((retcode = pam_close_session(pamh,0)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, retcode)); \ + if ((retcode = pam_end(pamh, retcode)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, retcode)); \ +} +#endif /* USE_PAM */ + /* wrapper for KAME-special getnameinfo() */ #ifndef NI_WITHSCOPEID #define NI_WITHSCOPEID 0 @@ -188,6 +202,20 @@ return(0); } +#ifdef USE_PAM +/* + * We can't have a conversation with the client over the rsh connection. + * You must use auth methods that don't require one, like pam_rhosts. + */ + +int null_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + syslog(LOG_ERR, "PAM conversation is not supported\n"); + return PAM_CONV_ERR; +} +#endif /* USE_PAM */ + char username[20] = "USER="; char homedir[64] = "HOME="; char shell[64] = "SHELL="; @@ -219,6 +247,11 @@ #ifdef LOGIN_CAP login_cap_t *lc; #endif +#ifdef USE_PAM + static struct pam_conv conv = { null_conv, NULL }; + int retcode, i; + const char * const *env; +#endif /* USE_PAM */ (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); @@ -341,6 +374,36 @@ getstr(locuser, sizeof(locuser), "locuser"); getstr(cmdbuf, sizeof(cmdbuf), "command"); + +#ifdef USE_PAM + retcode = pam_start("rsh", locuser, &conv, &pamh); + if (retcode != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_start: %s\n", pam_strerror(pamh, retcode)); + exit(1); + } + pam_set_item (pamh, PAM_RUSER, remuser); + pam_set_item (pamh, PAM_RHOST, fromhost); + pam_set_item (pamh, PAM_TTY, "tty"); + + retcode = pam_authenticate(pamh, 0); + if (retcode == PAM_SUCCESS) { + if ((retcode = pam_get_item(pamh, PAM_USER, (const void **) &cp)) == PAM_SUCCESS) { + strncpy(locuser, cp, sizeof(locuser)); + locuser[sizeof(locuser) - 1] = '\0'; + } else + syslog(LOG_ERR|LOG_AUTH, "Couldn't get PAM_USER: %s", + pam_strerror(pamh, retcode)); + retcode = pam_acct_mgmt(pamh, 0); + } + if (retcode != PAM_SUCCESS) { + pam_end(pamh, retcode); + syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: permission denied (%s). cmd='%.80s'", + remuser, fromhost, locuser, pam_strerror(pamh, retcode), cmdbuf); + error("Login incorrect.\n"); + exit(1); + } +#endif /* USE_PAM */ + setpwent(); pwd = getpwnam(locuser); if (pwd == NULL) { @@ -349,11 +412,42 @@ remuser, fromhost, locuser, cmdbuf); if (errorstr == NULL) errorstr = "Login incorrect.\n"; - goto fail; + error(errorstr, fromhost); + exit(1); } -#ifdef LOGIN_CAP + +#ifndef USE_PAM + if (errorstr || + (pwd->pw_expire && time(NULL) >= pwd->pw_expire) || + iruserok_sa(fromp, fromp->su_len, pwd->pw_uid == 0, + remuser, locuser) < 0) { + if (__rcmd_errstr) + syslog(LOG_INFO|LOG_AUTH, + "%s@%s as %s: permission denied (%s). cmd='%.80s'", + remuser, fromhost, locuser, __rcmd_errstr, + cmdbuf); + else + syslog(LOG_INFO|LOG_AUTH, + "%s@%s as %s: permission denied. cmd='%.80s'", + remuser, fromhost, locuser, cmdbuf); + if (errorstr == NULL) + errorstr = "Login incorrect.\n"; + error(errorstr, fromhost); + exit(1); + } +#endif /* USE_PAM */ + +#ifdef LOGIN_CAP lc = login_getpwclass(pwd); -#endif + if (pwd->pw_uid) + auth_checknologin(lc); +#else /* !LOGIN_CAP */ + if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { + error("Logins currently disabled.\n"); + exit(1); + } +#endif /* LOGIN_CAP */ + if (chdir(pwd->pw_dir) < 0) { #ifdef LOGIN_CAP if (chdir("/") < 0 || @@ -377,30 +471,6 @@ pwd->pw_dir = "/"; } - if (errorstr || - (pwd->pw_expire && time(NULL) >= pwd->pw_expire) || - iruserok_sa(fromp, fromp->su_len, pwd->pw_uid == 0, - remuser, locuser) < 0) { - if (__rcmd_errstr) - syslog(LOG_INFO|LOG_AUTH, - "%s@%s as %s: permission denied (%s). cmd='%.80s'", - remuser, fromhost, locuser, __rcmd_errstr, - cmdbuf); - else - syslog(LOG_INFO|LOG_AUTH, - "%s@%s as %s: permission denied. cmd='%.80s'", - remuser, fromhost, locuser, cmdbuf); -fail: - if (errorstr == NULL) - errorstr = "Login incorrect.\n"; - error(errorstr, fromhost); - exit(1); - } - - if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { - error("Logins currently disabled.\n"); - exit(1); - } #ifdef LOGIN_CAP if (lc != NULL && fromp->su_family == AF_INET) { /*XXX*/ char remote_ip[MAXHOSTNAMELEN]; @@ -421,13 +491,36 @@ exit(1); } } -#endif /* !LOGIN_CAP */ +#endif /* LOGIN_CAP */ #if BSD > 43 /* before fork, while we're session leader */ if (setlogin(pwd->pw_name) < 0) syslog(LOG_ERR, "setlogin() failed: %m"); #endif + /* + * PAM modules might add supplementary groups in + * pam_setcred(), so initialize them first. + * But we need to open the session as root. + */ +#ifdef LOGIN_CAP + if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { + syslog(LOG_ERR, "setusercontext: %m"); + exit(1); + } +#else /* !LOGIN_CAP */ + (void) setgid((gid_t)pwd->pw_gid); + initgroups(pwd->pw_name, pwd->pw_gid); +#endif /* LOGIN_CAP */ + +#ifdef USE_PAM + if ((retcode = pam_open_session(pamh, 0)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, retcode)); + } else if ((retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, retcode)); + } +#endif /* USE_PAM */ + (void) write(STDERR_FILENO, "\0", 1); sent_null = 1; @@ -451,6 +544,9 @@ pid = fork(); if (pid == -1) { error("Can't fork; try again.\n"); +#ifdef USE_PAM + PAM_END; +#endif /* USE_PAM */ exit(1); } if (pid) { @@ -569,6 +665,9 @@ (doencrypt && FD_ISSET(pv1[0], &readfrom)) || #endif FD_ISSET(pv[0], &readfrom)); +#ifdef USE_PAM + PAM_END; +#endif /* USE_PAM */ exit(0); } setpgrp(0, getpid()); @@ -586,6 +685,23 @@ dup2(pv[1], 2); close(pv[1]); } +#ifdef USE_PAM + else { + pid = fork(); + if (pid == -1) { + error("Can't fork; try again.\n"); + PAM_END; + exit(1); + } + if (pid) { + /* Parent. */ + wait(NULL); + PAM_END; + exit(0); + } + } +#endif /* USE_PAM */ + if (*pwd->pw_shell == '\0') pwd->pw_shell = _PATH_BSHELL; environ = envinit; @@ -598,17 +714,24 @@ cp++; else cp = pwd->pw_shell; + #ifdef LOGIN_CAP - if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) { + if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL & ~LOGIN_SETGROUP) != 0) { syslog(LOG_ERR, "setusercontext: %m"); exit(1); } login_close(lc); #else - (void) setgid((gid_t)pwd->pw_gid); - initgroups(pwd->pw_name, pwd->pw_gid); (void) setuid((uid_t)pwd->pw_uid); #endif +#ifdef USE_PAM + env = (const char * const *)pam_getenvlist(pamh); + if (env != NULL) { + for (i=0; env[i]; i++) + putenv(env[i]); + } +#endif /* USE_PAM */ + endpwent(); if (log_success || pwd->pw_uid == 0) { syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", --- ./usr.bin/login/Makefile 2001/01/21 04:44:21 1.1 +++ ./usr.bin/login/Makefile 2001/01/21 04:44:45 @@ -11,9 +11,8 @@ DPADD= ${LIBUTIL} ${LIBCRYPT} LDADD= -lutil -lcrypt -.if defined(NOPAM) -CFLAGS+= -DNO_PAM -.else +.if !defined(NOPAM) +CFLAGS+= -DUSE_PAM DPADD+= ${LIBPAM} LDADD+= ${MINUSLPAM} .endif --- ./usr.bin/login/login.c 2000/08/08 03:12:59 1.1 +++ ./usr.bin/login/login.c 2001/01/21 04:44:15 @@ -78,10 +78,11 @@ #include <unistd.h> #include <utmp.h> -#ifndef NO_PAM +#ifdef USE_PAM #include <security/pam_appl.h> #include <security/pam_misc.h> -#endif +#include <sys/wait.h> +#endif /* USE_PAM */ #include "pathnames.h" @@ -104,9 +105,18 @@ int login_access __P((char *, char *)); void login_fbtab __P((char *, uid_t, gid_t)); -#ifndef NO_PAM +#ifdef USE_PAM static int auth_pam __P((void)); -#endif +pam_handle_t *pamh = NULL; +#define PAM_END { \ + if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \ + if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \ + if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \ + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \ +} +#endif /* USE_PAM */ static int auth_traditional __P((void)); extern void login __P((struct utmp *)); static void usage __P((void)); @@ -150,6 +160,10 @@ char tname[sizeof(_PATH_TTY) + 10]; char *shell = NULL; login_cap_t *lc = NULL; +#ifdef USE_PAM + pid_t pid; + int e; +#endif /* USE_PAM */ (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); @@ -309,19 +323,19 @@ (void)setpriority(PRIO_PROCESS, 0, -4); -#ifndef NO_PAM +#ifdef USE_PAM /* * Try to authenticate using PAM. If a PAM system error * occurs, perhaps because of a botched configuration, * then fall back to using traditional Unix authentication. */ if ((rval = auth_pam()) == -1) -#endif /* NO_PAM */ +#endif /* USE_PAM */ rval = auth_traditional(); (void)setpriority(PRIO_PROCESS, 0, 0); -#ifndef NO_PAM +#ifdef USE_PAM /* * PAM authentication may have changed "pwd" to the * entry for the template user. Check again to see if @@ -329,7 +343,7 @@ */ if (pwd != NULL && pwd->pw_uid == 0) rootlogin = 1; -#endif /* NO_PAM */ +#endif /* USE_PAM */ ttycheck: /* @@ -549,6 +563,43 @@ environ = envinit; /* + * PAM modules might add supplementary groups during pam_setcred(). + */ + if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { + syslog(LOG_ERR, "setusercontext() failed - exiting"); + exit(1); + } + +#ifdef USE_PAM + if (pamh) { + if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, e)); + } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); + } + + /* + * We must fork() before setuid() because we need to call + * pam_close_session() as root. + */ + pid = fork(); + if (pid < 0) { + err(1, "fork"); + PAM_END; + exit(0); + } else if (pid) { + /* parent - wait for child to finish, then cleanup session */ + wait(NULL); + PAM_END; + exit(0); + } else { + if ((e = pam_end(pamh, e)) != PAM_SUCCESS) + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); + } + } +#endif /* USE_PAM */ + + /* * We don't need to be root anymore, so * set the user and session context */ @@ -557,7 +608,7 @@ exit(1); } if (setusercontext(lc, pwd, pwd->pw_uid, - LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0) { + LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { syslog(LOG_ERR, "setusercontext() failed - exiting"); exit(1); } @@ -573,6 +624,17 @@ (void)setenv("USER", username, 1); (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); +#ifdef USE_PAM + if (pamh) { + const char * const *env = (const char * const *)pam_getenvlist(pamh); + int i; + if (env != NULL) { + for (i=0; env[i]; i++) + putenv(env[i]); + } + } +#endif /* USE_PAM */ + if (!quietlog) { char *cw; @@ -652,7 +714,7 @@ return rval; } -#ifndef NO_PAM +#ifdef USE_PAM /* * Attempt to authenticate the user using PAM. Returns 0 if the user is * authenticated, or 1 if not authenticated. If some sort of PAM system @@ -663,7 +725,6 @@ static int auth_pam() { - pam_handle_t *pamh = NULL; const char *tmpl_user; const void *item; int rval; @@ -724,17 +785,33 @@ break; default: - syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e)); + syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); rval = -1; break; } - if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); - rval = -1; + + if (rval != -1) { + e = pam_acct_mgmt(pamh, 0); + if (e == PAM_NEW_AUTHTOK_REQD) { + e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + if (e != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, e)); + rval = -1; + } + } else if (e != PAM_SUCCESS) { + rval = 1; + } + } + + if (rval == -1) { + if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); + } + pamh = NULL; } return rval; } -#endif /* NO_PAM */ +#endif /* USE_PAM */ static void usage() @@ -745,7 +822,7 @@ /* * Allow for authentication style and/or kerberos instance - * */ + */ #define NBUFSIZ UT_NAMESIZE + 64 --- ./usr.bin/su/Makefile 2001/01/16 21:33:47 1.1 +++ ./usr.bin/su/Makefile 2001/01/21 04:45:12 @@ -8,6 +8,12 @@ DPADD= ${LIBUTIL} ${LIBSKEY} ${LIBMD} ${LIBCRYPT} LDADD= -lutil -lskey -lmd -lcrypt +.if !defined(NOPAM) +CFLAGS+= -DUSE_PAM +DPADD+= ${LIBPAM} +LDADD+= ${MINUSLPAM} +.endif + .if defined(WHEELSU) COPTS+= -DWHEELSU .endif --- ./usr.bin/su/su.c 2000/02/24 21:06:21 1.1 +++ ./usr.bin/su/su.c 2001/01/21 04:27:04 @@ -65,6 +65,30 @@ #include <login_cap.h> #endif +#ifdef USE_PAM +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <signal.h> +#include <sys/wait.h> +#define PAM_FAIL_CHECK \ + if (retcode != PAM_SUCCESS) { \ + fprintf(stderr, "su: PAM error: %s\n", pam_strerror(pamh, retcode)); \ + syslog(LOG_ERR, "PAM error: %s", pam_strerror(pamh, retcode)); \ + pam_end(pamh, retcode); \ + exit(1); \ + } +#define PAM_END { \ + if ((retcode = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) { \ + fprintf(stderr, "su: PAM error: %s\n", pam_strerror(pamh, retcode)); \ + syslog(LOG_ERR, "PAM error: %s", pam_strerror(pamh, retcode)); \ + } \ + if ((retcode = pam_end(pamh,retcode)) != PAM_SUCCESS) { \ + fprintf(stderr, "su: PAM error: %s\n", pam_strerror(pamh, retcode)); \ + syslog(LOG_ERR, "PAM error: %s", pam_strerror(pamh, retcode)); \ + } \ +} +#endif /* USE_PAM */ + #ifdef SKEY #include <skey.h> #endif @@ -107,8 +131,7 @@ char *targetpass; int iswheelsu; #endif /* WHEELSU */ - char *p, **g, *user, *shell=NULL, *username, **cleanenv, **nargv, **np; - struct group *gr; + char *p, *user, *shell=NULL, *username, *cleanenv = NULL, **nargv, **np; uid_t ruid; gid_t gid; int asme, ch, asthem, fastlogin, prio, i; @@ -118,6 +141,18 @@ char *class=NULL; int setwhat; #endif +#ifdef USE_PAM + int retcode; + pam_handle_t *pamh = NULL; + struct pam_conv conv = { misc_conv, NULL }; + char myhost[MAXHOSTNAMELEN + 1], *mytty; + int statusp=0; + int child_pid, child_pgrp, ret_pid; + const char * const *env; +#else /* !USE_PAM */ + char **g; + struct group *gr; +#endif /* USE_PAM */ #ifdef KERBEROS char *k; #endif @@ -214,6 +249,38 @@ } } +#ifdef USE_PAM + retcode = pam_start("su", user, &conv, &pamh); + PAM_FAIL_CHECK; + + gethostname(myhost, sizeof(myhost)); + retcode = pam_set_item(pamh, PAM_RHOST, myhost); + PAM_FAIL_CHECK; + + mytty = ttyname(STDERR_FILENO); + if (!mytty) + mytty = "tty"; + retcode = pam_set_item(pamh, PAM_TTY, mytty); + PAM_FAIL_CHECK; + + if (ruid) { + retcode = pam_authenticate(pamh, 0); + PAM_FAIL_CHECK; + + if ((retcode = pam_get_item(pamh, PAM_USER, (const void **) &p)) == PAM_SUCCESS) { + user = p; + } else + syslog(LOG_ERR|LOG_AUTH, "Couldn't get PAM_USER: %s", + pam_strerror(pamh, retcode)); + + retcode = pam_acct_mgmt(pamh, 0); + if (retcode == PAM_NEW_AUTHTOK_REQD) + retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + PAM_FAIL_CHECK; + } + +#endif /* USE_PAM */ + /* get target login information, default to root */ if ((pwd = getpwnam(user)) == NULL) { errx(1, "unknown login: %s", user); @@ -230,6 +297,7 @@ } #endif +#ifndef USE_PAM #ifdef WHEELSU targetpass = strdup(pwd->pw_passwd); #endif /* WHEELSU */ @@ -280,11 +348,12 @@ #ifdef WHEELSU || (iswheelsu && !strcmp(targetpass, crypt(p,targetpass))) #endif /* WHEELSU */ - )) { -#else + )) +#else /* !SKEY */ p = getpass("Password:"); - if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { -#endif + if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) +#endif /* SKEY */ + { #ifdef KERBEROS if (!use_kerberos || (use_kerberos && kerberos(username, user, pwd->pw_uid, p))) #endif @@ -308,10 +377,11 @@ exit(1); } } +#endif /* USE_PAM */ if (asme) { /* if asme and non-standard target shell, must be root */ - if (!chshell(pwd->pw_shell) && ruid) + if (ruid && !chshell(pwd->pw_shell)) errx(1, "permission denied (shell)."); } else if (pwd->pw_shell && *pwd->pw_shell) { shell = pwd->pw_shell; @@ -334,9 +404,57 @@ (void)setpriority(PRIO_PROCESS, 0, prio); + /* + * PAM modules might add supplementary groups in + * pam_setcred(), so initialize them first. + */ +#ifdef LOGIN_CAP + if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0) + err(1, "setusercontext"); +#else + if (setgid(pwd->pw_gid) < 0) + err(1, "setgid"); + if (initgroups(user, pwd->pw_gid)) + errx(1, "initgroups failed"); +#endif + +#ifdef USE_PAM + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); + PAM_FAIL_CHECK; + + /* + * We must fork() before setuid() because we need to call + * pam_setcred(pamh, PAM_DELETE_CRED) as root. + */ + + statusp = 1; + switch ((child_pid = fork())) { + default: + while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) { + if (WIFSTOPPED(statusp)) { + child_pgrp = tcgetpgrp(1); + kill(getpid(), SIGSTOP); + tcsetpgrp(1, child_pgrp); + kill(child_pid, SIGCONT); + statusp = 1; + continue; + } + break; + } + if (ret_pid == -1) + err(1, "waitpid"); + PAM_END; + exit(statusp); + case -1: + err(1, "fork"); + PAM_END; + exit (1); + case 0: +#endif /* USE_PAM */ + #ifdef LOGIN_CAP /* Set everything now except the environment & umask */ - setwhat = LOGIN_SETUSER|LOGIN_SETGROUP|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; + setwhat = LOGIN_SETUSER|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; /* * Don't touch resource/priority settings if -m has been * used or -l and -c hasn't, and we're not su'ing to root. @@ -346,11 +464,6 @@ if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0) err(1, "setusercontext"); #else - /* set permissions */ - if (setgid(pwd->pw_gid) < 0) - err(1, "setgid"); - if (initgroups(user, pwd->pw_gid)) - errx(1, "initgroups failed"); if (setuid(pwd->pw_uid) < 0) err(1, "setuid"); #endif @@ -361,10 +474,7 @@ #ifdef KERBEROS k = getenv("KRBTKFILE"); #endif - if ((cleanenv = calloc(20, sizeof(char*))) == NULL) - errx(1, "calloc"); - cleanenv[0] = NULL; - environ = cleanenv; + environ = &cleanenv; #ifdef LOGIN_CAP /* set the su'd user's environment & umask */ setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV); @@ -385,6 +495,19 @@ (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", shell, 1); } + +#ifdef LOGIN_CAP + login_close(lc); +#endif /* LOGIN_CAP */ + +#ifdef USE_PAM + env = (const char * const *)pam_getenvlist(pamh); + if (env != NULL) { + for (i=0; env[i]; i++) + putenv(env[i]); + } +#endif /* USE_PAM */ + if (iscsh == YES) { if (fastlogin) *np-- = "-f"; @@ -399,10 +522,11 @@ syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s", username, user, ontty()); - login_close(lc); - execv(shell, np); err(1, "%s", shell); +#ifdef USE_PAM + } +#endif /* USE_PAM */ } static void To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010121045823.59DB212686>