summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/pam.conf97
-rw-r--r--libexec/ftpd/Makefile5
-rw-r--r--libexec/ftpd/ftpd.c59
-rw-r--r--libexec/rshd/Makefile9
-rw-r--r--libexec/rshd/rshd.810
-rw-r--r--libexec/rshd/rshd.c262
-rw-r--r--usr.bin/login/Makefile5
-rw-r--r--usr.bin/login/login.17
-rw-r--r--usr.bin/login/login.c122
-rw-r--r--usr.bin/su/Makefile15
-rw-r--r--usr.bin/su/su.17
-rw-r--r--usr.bin/su/su.c272
12 files changed, 686 insertions, 184 deletions
diff --git a/etc/pam.conf b/etc/pam.conf
index 4bc2f08..6df6844 100644
--- a/etc/pam.conf
+++ b/etc/pam.conf
@@ -3,30 +3,84 @@
# This file controls the authentication methods that login and other
# utilities use. See pam(8) for a description of its format.
#
-# Note: the final entry must say "required" -- otherwise, things don't
-# work quite right. If you delete the final entry, be sure to change
-# "sufficient" to "required" in the entry before it.
-#
# $FreeBSD$
+#
+# service-name module-type control-flag module-path arguments
+#
+# module-type:
+# auth: prompt for a password to authenticate that the user is
+# who they say they are, and set any credentials.
+# account: non-authentication based authorization, based on time,
+# resources, etc.
+# session: housekeeping before and/or after login.
+# password: update authentication tokens.
+#
+# control-flag: How libpam handles success or failure of the module.
+# required: success is required, and on failure all remaining
+# modules are run.
+# requisite: success is required, and on failure no remaining
+# modules are run.
+# sufficient: success is sufficient, and if no previous required
+# module failed, no remaining modules are run.
+# optional: ignored unless the other modules return PAM_IGNORE.
+#
+# arguments:
+# Passed to the module; module-specific plus some generic ones:
+# debug: syslog debug info.
+# no_warn: return no warning messages to the application.
+# use_first_pass: try authentication using password from the
+# preceding auth module.
+# try_first_pass: first try authentication using password from
+# the preceding auth module, and if that fails
+# prompt for a new password.
+# use_mapped_pass: convert cleartext password to a crypto key.
+# expose_account: allow printing more info about the user when
+# prompting.
+#
+# Each final entry must say "required" -- otherwise, things don't
+# work quite right. If you delete a final entry, be sure to change
+# "sufficient" to "required" in the entry before it.
-# If the user can authenticate with S/Key, that's sufficient; allow clear
-# password. Try kerberos, then try plain unix password.
-login auth sufficient pam_skey.so
-login auth requisite pam_cleartext_pass_ok.so
-#login auth sufficient pam_kerberosIV.so try_first_pass
+#login auth sufficient pam_krb5.so
login auth required pam_unix.so try_first_pass
+#login account required pam_krb5.so
+login account required pam_unix.so
+#login session required pam_krb5.so
+login password required pam_permit.so
+login session required pam_permit.so
+
+rsh auth required pam_permit.so
+rsh account required pam_unix.so
+rsh session required pam_permit.so
-# Same requirement for ftpd as login
-ftpd auth sufficient pam_skey.so
-ftpd auth requisite pam_cleartext_pass_ok.so
-#ftpd auth sufficient pam_kerberosIV.so try_first_pass
+#su auth sufficient pam_krb5.so
+su auth required pam_unix.so try_first_pass
+#su account required pam_krb5.so
+su account required pam_unix.so
+#su session required pam_krb5.so
+su password required pam_permit.so
+su session required pam_permit.so
+
+# Native ftpd.
+#ftpd auth sufficient pam_krb5.so
ftpd auth required pam_unix.so try_first_pass
+#ftpd account required pam_krb5.so
+ftpd account required pam_unix.so
+#ftpd session required pam_krb5.so
+
+# PROftpd.
+#ftp auth sufficient pam_krb5.so
+ftp auth required pam_unix.so try_first_pass
+#ftp account required pam_krb5.so
+ftp account required pam_unix.so
+#ftp session required pam_krb5.so
-# OpenSSH with PAM support requires similar modules. The session one is
-# a bit strange, though...
-sshd auth sufficient pam_skey.so
-#sshd auth sufficient pam_kerberosIV.so try_first_pass
+#sshd auth sufficient pam_krb5.so
sshd auth required pam_unix.so try_first_pass
+#sshd account required pam_krb5.so
+sshd account required pam_unix.so
+sshd password required pam_permit.so
+#sshd session required pam_krb5.so
sshd session required pam_permit.so
# Don't break startx
@@ -35,15 +89,14 @@ xserver auth required pam_permit.so
# XDM is difficult; it fails or moans unless there are modules for each
# of the four management groups; auth, account, session and password.
xdm auth required pam_unix.so
-#xdm auth sufficient pam_kerberosIV.so try_first_pass
-xdm account required pam_unix.so try_first_pass
+xdm account required pam_unix.so
xdm session required pam_deny.so
xdm password required pam_deny.so
# Mail services
-imap auth required pam_unix.so try_first_pass
-pop3 auth required pam_unix.so try_first_pass
+#imap auth required pam_unix.so try_first_pass
+#pop3 auth required pam_unix.so try_first_pass
# If we don't match anything else, default to using getpwnam().
other auth required pam_unix.so try_first_pass
-other account required pam_unix.so try_first_pass
+other account required pam_unix.so
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index a1c2547..6d81aee 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -18,9 +18,8 @@ LSDIR= ../../bin/ls
SRCS+= ls.c cmp.c print.c util.c
CFLAGS+=-Dmain=ls_main -I${.CURDIR}/${LSDIR}
-.if defined(NOPAM)
-CFLAGS+=-DNOPAM
-.else
+.if !defined(NOPAM)
+CFLAGS+=-DUSE_PAM
DPADD+= ${LIBPAM}
LDADD+= ${MINUSLPAM}
.endif
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index b5b6136..c7a74ee 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -95,7 +95,7 @@ static const char rcsid[] =
#include <skey.h>
#endif
-#if !defined(NOPAM)
+#ifdef USE_PAM
#include <security/pam_appl.h>
#endif
@@ -182,8 +182,9 @@ char *ident = NULL;
static char ttyline[20];
char *tty = ttyline; /* for klogin */
-#if !defined(NOPAM)
+#ifdef USE_PAM
static int auth_pam __P((struct passwd**, const char*));
+pam_handle_t *pamh = NULL;
#endif
char *pid_file = NULL;
@@ -1033,6 +1034,9 @@ checkuser(fname, name, pwset)
static void
end_login()
{
+#ifdef USE_PAM
+ int e;
+#endif
(void) seteuid((uid_t)0);
if (logged_in)
@@ -1042,12 +1046,21 @@ end_login()
setusercontext(NULL, getpwuid(0), (uid_t)0,
LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
#endif
+#ifdef USE_PAM
+ 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));
+ pamh = NULL;
+#endif
logged_in = 0;
guest = 0;
dochroot = 0;
}
-#if !defined(NOPAM)
+#ifdef USE_PAM
/*
* the following code is stolen from imap-uw PAM authentication module and
@@ -1166,19 +1179,34 @@ auth_pam(struct passwd **ppw, const char *pass)
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 == 0) {
+ 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 != 0) {
+ if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
+ }
+ pamh = NULL;
}
return rval;
}
-#endif /* !defined(NOPAM) */
+#endif /* USE_PAM */
void
pass(passwd)
@@ -1189,6 +1217,9 @@ pass(passwd)
#ifdef LOGIN_CAP
login_cap_t *lc = NULL;
#endif
+#ifdef USE_PAM
+ int e;
+#endif
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
@@ -1200,7 +1231,7 @@ pass(passwd)
rval = 1; /* failure below */
goto skip;
}
-#if !defined(NOPAM)
+#ifdef USE_PAM
rval = auth_pam(&pw, passwd);
if (rval >= 0)
goto skip;
@@ -1281,6 +1312,16 @@ skip:
(void) initgroups(pw->pw_name, pw->pw_gid);
#endif
+#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));
+ }
+ }
+#endif
+
/* open wtmp before chroot */
ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
logged_in = 1;
diff --git a/libexec/rshd/Makefile b/libexec/rshd/Makefile
index 54e254b..735c00d 100644
--- a/libexec/rshd/Makefile
+++ b/libexec/rshd/Makefile
@@ -7,11 +7,16 @@ MAN= rshd.8
#CFLAGS+= -DCRYPT
-# For login_cap handling
-CFLAGS+=-DLOGIN_CAP -Wall
+CFLAGS+= -Wall
DPADD+= ${LIBUTIL}
LDADD+= -lutil
+.if !defined(NOPAM)
+CFLAGS+= -DUSE_PAM
+DPADD+= ${LIBPAM}
+LDADD+= ${MINUSLPAM}
+.endif
+
# IPv6 support
CFLAGS+= -DINET6
diff --git a/libexec/rshd/rshd.8 b/libexec/rshd/rshd.8
index bf18b20..52245da 100644
--- a/libexec/rshd/rshd.8
+++ b/libexec/rshd/rshd.8
@@ -241,6 +241,16 @@ and is not preceded by a flag byte.
.It Pa /etc/login.conf
.It Ev $HOME Ns Pa /.rhosts
.It Pa /var/run/nologin
+.It Pa /etc/pam.conf
+if
+.Nm
+is configured with PAM support, it uses
+.Pa /etc/pam.conf
+entries with service name
+.Dq rsh .
+authentication modules requiring passwords (such as
+.Nm pam_unix )
+are not supported
.El
.Sh BUGS
The authentication procedure used here assumes the integrity
diff --git a/libexec/rshd/rshd.c b/libexec/rshd/rshd.c
index 20f794a..efe5beb1 100644
--- a/libexec/rshd/rshd.c
+++ b/libexec/rshd/rshd.c
@@ -76,9 +76,27 @@ static const char rcsid[] =
#include <string.h>
#include <syslog.h>
#include <unistd.h>
-#ifdef LOGIN_CAP
#include <login_cap.h>
-#endif
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <sys/wait.h>
+
+static int export_pam_environment __P((void));
+static int ok_to_export __P((const char *));
+
+static pam_handle_t *pamh;
+static char **environ_pam;
+
+#define PAM_END { \
+ if ((retcode = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
+ syslog(LOG_ERR|LOG_AUTH, "pam_setcred: %s", pam_strerror(pamh, retcode)); \
+ if ((retcode = pam_close_session(pamh,0)) != PAM_SUCCESS) \
+ syslog(LOG_ERR|LOG_AUTH, "pam_close_session: %s", pam_strerror(pamh, retcode)); \
+ if ((retcode = pam_end(pamh, retcode)) != PAM_SUCCESS) \
+ syslog(LOG_ERR|LOG_AUTH, "pam_end: %s", pam_strerror(pamh, retcode)); \
+}
+#endif /* USE_PAM */
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
@@ -188,6 +206,20 @@ main(argc, argv)
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");
+ return PAM_CONV_ERR;
+}
+#endif /* USE_PAM */
+
char username[20] = "USER=";
char homedir[64] = "HOME=";
char shell[64] = "SHELL=";
@@ -216,9 +248,11 @@ doit(fromp)
int rc;
int pv1[2], pv2[2];
#endif
-#ifdef LOGIN_CAP
login_cap_t *lc;
-#endif
+#ifdef USE_PAM
+ static struct pam_conv conv = { null_conv, NULL };
+ int retcode;
+#endif /* USE_PAM */
(void) signal(SIGINT, SIG_DFL);
(void) signal(SIGQUIT, SIG_DFL);
@@ -229,7 +263,7 @@ doit(fromp)
&& af != AF_INET6
#endif
) {
- syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
+ syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
exit(1);
}
err = getnameinfo((struct sockaddr *)fromp, fromp->su_len, numericname,
@@ -341,6 +375,52 @@ doit(fromp)
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|LOG_AUTH, "pam_start: %s", pam_strerror(pamh, retcode));
+ error("Login incorrect.\n");
+ exit(1);
+ }
+
+ retcode = pam_set_item (pamh, PAM_RUSER, remuser);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR|LOG_AUTH, "pam_set_item(PAM_RUSER): %s", pam_strerror(pamh, retcode));
+ error("Login incorrect.\n");
+ exit(1);
+ }
+ retcode = pam_set_item (pamh, PAM_RHOST, fromhost);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR|LOG_AUTH, "pam_set_item(PAM_RHOST): %s", pam_strerror(pamh, retcode));
+ error("Login incorrect.\n");
+ exit(1);
+ }
+ retcode = pam_set_item (pamh, PAM_TTY, "tty");
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR|LOG_AUTH, "pam_set_item(PAM_TTY): %s", pam_strerror(pamh, retcode));
+ error("Login incorrect.\n");
+ exit(1);
+ }
+
+ 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, "pam_get_item(PAM_USER): %s",
+ pam_strerror(pamh, retcode));
+ retcode = pam_acct_mgmt(pamh, 0);
+ }
+ if (retcode != PAM_SUCCESS) {
+ 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,13 +429,36 @@ doit(fromp)
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 */
+
lc = login_getpwclass(pwd);
-#endif
+ if (pwd->pw_uid)
+ auth_checknologin(lc);
+
if (chdir(pwd->pw_dir) < 0) {
-#ifdef LOGIN_CAP
if (chdir("/") < 0 ||
login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
syslog(LOG_INFO|LOG_AUTH,
@@ -364,44 +467,9 @@ doit(fromp)
error("No remote home directory.\n");
exit(0);
}
-#else
- (void) chdir("/");
-#ifdef notdef
- syslog(LOG_INFO|LOG_AUTH,
- "%s@%s as %s: no home directory. cmd='%.80s'",
- remuser, fromhost, locuser, cmdbuf);
- error("No remote directory.\n");
- exit(1);
-#endif
-#endif
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 +489,30 @@ fail:
exit(1);
}
}
-#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.
+ */
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
+ syslog(LOG_ERR, "setusercontext: %m");
+ exit(1);
+ }
+
+#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;
@@ -569,6 +654,9 @@ fail:
(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,9 +674,38 @@ fail:
dup2(pv[1], 2);
close(pv[1]);
}
+#ifdef USE_PAM
+ else {
+ pid = fork();
+ if (pid == -1) {
+ error("Can't fork; try again.\n");
+ 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;
+
+#ifdef USE_PAM
+ /*
+ * Add any environmental variables that the
+ * PAM modules may have set.
+ */
+ environ_pam = pam_getenvlist(pamh);
+ if (environ_pam)
+ export_pam_environment();
+ if ((retcode = pam_end(pamh, PAM_DATA_SILENT)) != PAM_SUCCESS)
+ syslog(LOG_ERR|LOG_AUTH, "pam_end: %s", pam_strerror(pamh, retcode));
+#endif /* USE_PAM */
+
strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
strcat(path, _PATH_DEFPATH);
strncat(shell, pwd->pw_shell, sizeof(shell)-7);
@@ -598,17 +715,13 @@ fail:
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
+
endpwent();
if (log_success || pwd->pw_uid == 0) {
syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
@@ -717,6 +830,51 @@ topdomain(h)
return (maybe);
}
+#ifdef USE_PAM
+static int
+export_pam_environment()
+{
+ char **pp;
+
+ for (pp = environ_pam; *pp != NULL; pp++) {
+ if (ok_to_export(*pp))
+ (void) putenv(*pp);
+ free(*pp);
+ }
+ return PAM_SUCCESS;
+}
+
+/*
+ * Sanity checks on PAM environmental variables:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ */
+static int
+ok_to_export(s)
+ const char *s;
+{
+ static const char *noexport[] = {
+ "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+ return 0;
+ if (strncmp(s, "LD_", 3) == 0)
+ return 0;
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return 0;
+ }
+ return 1;
+}
+#endif /* USE_PAM */
+
void
usage()
{
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
index a9a42bc..970e591 100644
--- a/usr.bin/login/Makefile
+++ b/usr.bin/login/Makefile
@@ -10,9 +10,8 @@ CFLAGS+=-Wall -DLOGIN_ACCESS -DLOGALL
DPADD= ${LIBUTIL} ${LIBCRYPT}
LDADD= -lutil -lcrypt
-.if defined(NOPAM)
-CFLAGS+= -DNO_PAM
-.else
+.if !defined(NOPAM)
+CFLAGS+= -DUSE_PAM
DPADD+= ${LIBPAM}
LDADD+= ${MINUSLPAM}
.endif
diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1
index 492b983..4b1b66c 100644
--- a/usr.bin/login/login.1
+++ b/usr.bin/login/login.1
@@ -177,6 +177,13 @@ system mailboxes
makes login quieter
.It Pa /etc/auth.conf
configure authentication services
+.It Pa /etc/pam.conf
+if
+.Nm
+is configured with PAM support, it uses
+.Pa /etc/pam.conf
+entries with service name
+.Dq login
.El
.Sh SEE ALSO
.Xr builtin 1 ,
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
index 7f7a09b..7ddc948 100644
--- a/usr.bin/login/login.c
+++ b/usr.bin/login/login.c
@@ -78,10 +78,11 @@ static const char rcsid[] =
#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,11 +105,23 @@ void timedout __P((int));
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));
static int export_pam_environment __P((void));
static int ok_to_export __P((const char *));
-#endif
+
+static pam_handle_t *pamh = NULL;
+static char **environ_pam;
+
+#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));
@@ -130,9 +143,6 @@ struct passwd *pwd;
int failures;
char *term, *envinit[1], *hostname, *username, *tty;
char full_hostname[MAXHOSTNAMELEN];
-#ifndef NO_PAM
-static char **environ_pam;
-#endif
int
main(argc, argv)
@@ -155,6 +165,10 @@ main(argc, argv)
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);
@@ -314,19 +328,19 @@ main(argc, argv)
(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
@@ -334,7 +348,7 @@ main(argc, argv)
*/
if (pwd != NULL && pwd->pw_uid == 0)
rootlogin = 1;
-#endif /* NO_PAM */
+#endif /* USE_PAM */
ttycheck:
/*
@@ -553,14 +567,54 @@ main(argc, argv)
if (!pflag)
environ = envinit;
-#ifndef NO_PAM
+#ifdef USE_PAM
/*
* Add any environmental variables that the
* PAM modules may have set.
*/
- if (environ_pam)
- export_pam_environment();
-#endif
+ if (pamh) {
+ environ_pam = pam_getenvlist(pamh);
+ if (environ_pam)
+ export_pam_environment();
+ }
+#endif /* USE_PAM */
+
+ /*
+ * 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, PAM_DATA_SILENT)) != PAM_SUCCESS)
+ syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
+ }
+ }
+#endif /* USE_PAM */
/*
* We don't need to be root anymore, so
@@ -571,7 +625,7 @@ main(argc, argv)
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);
}
@@ -666,7 +720,7 @@ auth_traditional()
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
@@ -677,7 +731,6 @@ auth_traditional()
static int
auth_pam()
{
- pam_handle_t *pamh = NULL;
const char *tmpl_user;
const void *item;
int rval;
@@ -728,11 +781,6 @@ auth_pam()
} else
syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
pam_strerror(pamh, e));
- if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
- PAM_SUCCESS)
- syslog(LOG_ERR, "Couldn't establish credentials: %s",
- pam_strerror(pamh, e));
- environ_pam = pam_getenvlist(pamh);
rval = 0;
break;
@@ -743,13 +791,29 @@ auth_pam()
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 == 0) {
+ 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 != 0) {
+ if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
+ }
+ pamh = NULL;
}
return rval;
}
@@ -796,7 +860,7 @@ ok_to_export(s)
}
return 1;
}
-#endif /* NO_PAM */
+#endif /* USE_PAM */
static void
usage()
@@ -807,7 +871,7 @@ usage()
/*
* Allow for authentication style and/or kerberos instance
- * */
+ */
#define NBUFSIZ UT_NAMESIZE + 64
diff --git a/usr.bin/su/Makefile b/usr.bin/su/Makefile
index 99b44fb..c20800d 100644
--- a/usr.bin/su/Makefile
+++ b/usr.bin/su/Makefile
@@ -4,9 +4,18 @@
PROG= su
SRCS= su.c
-COPTS+= -DLOGIN_CAP -DSKEY
-DPADD= ${LIBUTIL} ${LIBSKEY} ${LIBMD} ${LIBCRYPT}
-LDADD= -lutil -lskey -lmd -lcrypt
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+.if !defined(NOPAM)
+CFLAGS+= -DUSE_PAM
+DPADD+= ${LIBPAM}
+LDADD+= ${MINUSLPAM}
+.else
+COPTS+= -DSKEY
+DPADD+= ${LIBSKEY} ${LIBMD} ${LIBCRYPT}
+LDADD+= -lskey -lmd -lcrypt
+.endif
.if defined(WHEELSU)
COPTS+= -DWHEELSU
diff --git a/usr.bin/su/su.1 b/usr.bin/su/su.1
index 2be4385..5024849 100644
--- a/usr.bin/su/su.1
+++ b/usr.bin/su/su.1
@@ -173,6 +173,13 @@ to remind one of its awesome power.
.Bl -tag -width /etc/auth.conf -compact
.It Pa /etc/auth.conf
configure authentication services
+.It Pa /etc/pam.conf
+if
+.Nm
+is configured with PAM support, it uses
+.Pa /etc/pam.conf
+entries with service name
+.Dq su
.El
.Sh SEE ALSO
.Xr csh 1 ,
diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c
index 3edacb4..efd46b8 100644
--- a/usr.bin/su/su.c
+++ b/usr.bin/su/su.c
@@ -60,36 +60,47 @@ static const char rcsid[] =
#include <syslog.h>
#include <unistd.h>
#include <libutil.h>
-
-#ifdef LOGIN_CAP
#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>
+
+static int export_pam_environment __P((void));
+static int ok_to_export __P((const char *));
+
+static pam_handle_t *pamh = NULL;
+static char **environ_pam;
+
+#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_end(pamh,retcode)) != PAM_SUCCESS) { \
+ syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, retcode)); \
+ } \
+}
+#else /* !USE_PAM */
#ifdef SKEY
#include <skey.h>
#endif
+#endif /* USE_PAM */
#ifdef KERBEROS
#include <openssl/des.h>
#include <krb.h>
#include <netdb.h>
-#ifdef LOGIN_CAP
#define ARGSTR "-Kflmc:"
-#else
-#define ARGSTR "-Kflm"
-#endif
static int kerberos(char *username, char *user, int uid, char *pword);
static int koktologin(char *name, char *toname);
int use_kerberos = 1;
#else /* !KERBEROS */
-#ifdef LOGIN_CAP
#define ARGSTR "-flmc:"
-#else
-#define ARGSTR "-flm"
-#endif
#endif /* KERBEROS */
char *ontty __P((void));
@@ -107,17 +118,24 @@ main(argc, argv)
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;
enum { UNSET, YES, NO } iscsh = UNSET;
-#ifdef LOGIN_CAP
login_cap_t *lc;
char *class=NULL;
int setwhat;
-#endif
+#ifdef USE_PAM
+ int retcode;
+ struct pam_conv conv = { misc_conv, NULL };
+ char myhost[MAXHOSTNAMELEN + 1], *mytty;
+ int statusp=0;
+ int child_pid, child_pgrp, ret_pid;
+#else /* !USE_PAM */
+ char **g;
+ struct group *gr;
+#endif /* USE_PAM */
#ifdef KERBEROS
char *k;
#endif
@@ -147,11 +165,9 @@ main(argc, argv)
asme = 1;
asthem = 0;
break;
-#ifdef LOGIN_CAP
case 'c':
class = optarg;
break;
-#endif
case '?':
default:
usage();
@@ -161,8 +177,7 @@ main(argc, argv)
user = argv[optind++];
if (strlen(user) > MAXLOGNAME - 1) {
- (void)fprintf(stderr, "su: username too long.\n");
- exit(1);
+ errx(1, "username too long");
}
if (user == NULL)
@@ -189,7 +204,7 @@ main(argc, argv)
if (errno)
prio = 0;
(void)setpriority(PRIO_PROCESS, 0, -2);
- openlog("su", LOG_CONS, 0);
+ openlog("su", LOG_CONS, LOG_AUTH);
/* get current login name and shell */
ruid = getuid();
@@ -214,11 +229,61 @@ main(argc, argv)
}
}
+#ifdef USE_PAM
+ retcode = pam_start("su", user, &conv, &pamh);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode));
+ errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
+ }
+
+ gethostname(myhost, sizeof(myhost));
+ retcode = pam_set_item(pamh, PAM_RHOST, myhost);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", pam_strerror(pamh, retcode));
+ errx(1, "pam_set_item(PAM_RHOST): %s", pam_strerror(pamh, retcode));
+ }
+
+ mytty = ttyname(STDERR_FILENO);
+ if (!mytty)
+ mytty = "tty";
+ retcode = pam_set_item(pamh, PAM_TTY, mytty);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", pam_strerror(pamh, retcode));
+ errx(1, "pam_set_item(PAM_TTY): %s", pam_strerror(pamh, retcode));
+ }
+
+ if (ruid) {
+ retcode = pam_authenticate(pamh, 0);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+
+ if ((retcode = pam_get_item(pamh, PAM_USER, (const void **) &p)) == PAM_SUCCESS) {
+ user = p;
+ } else
+ syslog(LOG_ERR, "pam_get_item(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);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+ }
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_acct_mgmt: %s", pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+ }
+#endif /* USE_PAM */
+
/* get target login information, default to root */
if ((pwd = getpwnam(user)) == NULL) {
errx(1, "unknown login: %s", user);
}
-#ifdef LOGIN_CAP
if (class==NULL) {
lc = login_getpwclass(pwd);
} else {
@@ -228,8 +293,8 @@ main(argc, argv)
if (lc == NULL)
errx(1, "unknown class: %s", class);
}
-#endif
+#ifndef USE_PAM
#ifdef WHEELSU
targetpass = strdup(pwd->pw_passwd);
#endif /* WHEELSU */
@@ -280,18 +345,18 @@ main(argc, argv)
#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
- {
- fprintf(stderr, "Sorry\n");
+ {
syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty());
- exit(1);
+ errx(1, "Sorry");
}
}
#ifdef WHEELSU
@@ -301,17 +366,17 @@ main(argc, argv)
#endif /* WHEELSU */
}
if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) {
- fprintf(stderr, "Sorry - account expired\n");
syslog(LOG_AUTH|LOG_WARNING,
"BAD SU %s to %s%s", username,
user, ontty());
- exit(1);
+ errx(1, "Sorry - account expired");
}
}
+#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,7 +399,49 @@ main(argc, argv)
(void)setpriority(PRIO_PROCESS, 0, prio);
-#ifdef LOGIN_CAP
+ /*
+ * PAM modules might add supplementary groups in
+ * pam_setcred(), so initialize them first.
+ */
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)
+ err(1, "setusercontext");
+
+#ifdef USE_PAM
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, retcode));
+ }
+
+ /*
+ * 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 */
+
/*
* Set all user context except for:
* Environmental variables
@@ -343,7 +450,7 @@ main(argc, argv)
* Path
*/
setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
- LOGIN_SETLOGIN | LOGIN_SETPATH);
+ LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP);
/*
* Don't touch resource/priority settings if -m has been
@@ -353,15 +460,6 @@ main(argc, argv)
setwhat &= ~(LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
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
if (!asme) {
if (asthem) {
@@ -369,16 +467,20 @@ main(argc, argv)
#ifdef KERBEROS
k = getenv("KRBTKFILE");
#endif
- if ((cleanenv = calloc(20, sizeof(char*))) == NULL)
- errx(1, "calloc");
- cleanenv[0] = NULL;
- environ = cleanenv;
-#ifdef LOGIN_CAP
+ environ = &cleanenv;
+
+#ifdef USE_PAM
+ /*
+ * Add any environmental variables that the
+ * PAM modules may have set.
+ */
+ environ_pam = pam_getenvlist(pamh);
+ if (environ_pam)
+ export_pam_environment();
+#endif /* USE_PAM */
+
/* set the su'd user's environment & umask */
setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
-#else
- (void)setenv("PATH", _PATH_DEFPATH, 1);
-#endif
if (p)
(void)setenv("TERM", p, 1);
#ifdef KERBEROS
@@ -393,6 +495,9 @@ main(argc, argv)
(void)setenv("HOME", pwd->pw_dir, 1);
(void)setenv("SHELL", shell, 1);
}
+
+ login_close(lc);
+
if (iscsh == YES) {
if (fastlogin)
*np-- = "-f";
@@ -404,20 +509,65 @@ main(argc, argv)
*np = asthem ? "-su" : iscsh == YES ? "_su" : "su";
if (ruid != 0)
- syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s",
+ syslog(LOG_NOTICE, "%s to %s%s",
username, user, ontty());
- login_close(lc);
-
execv(shell, np);
err(1, "%s", shell);
+#ifdef USE_PAM
+ }
+#endif /* USE_PAM */
+}
+
+#ifdef USE_PAM
+static int
+export_pam_environment()
+{
+ char **pp;
+
+ for (pp = environ_pam; *pp != NULL; pp++) {
+ if (ok_to_export(*pp))
+ (void) putenv(*pp);
+ free(*pp);
+ }
+ return PAM_SUCCESS;
+}
+
+/*
+ * Sanity checks on PAM environmental variables:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ */
+static int
+ok_to_export(s)
+ const char *s;
+{
+ static const char *noexport[] = {
+ "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+ return 0;
+ if (strncmp(s, "LD_", 3) == 0)
+ return 0;
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return 0;
+ }
+ return 1;
}
+#endif /* USE_PAM */
static void
usage()
{
- (void)fprintf(stderr, "usage: su [%s] [login [args]]\n", ARGSTR);
- exit(1);
+ errx(1, "usage: su [%s] [login [args]]", ARGSTR);
}
int
@@ -501,7 +651,7 @@ kerberos(username, user, uid, pword)
return (1);
}
warnx("kerberos: unable to su: %s", krb_err_txt[kerno]);
- syslog(LOG_NOTICE|LOG_AUTH,
+ syslog(LOG_NOTICE,
"BAD Kerberos SU: %s to %s%s: %s",
username, user, ontty(), krb_err_txt[kerno]);
return (1);
@@ -528,13 +678,13 @@ kerberos(username, user, uid, pword)
if (kerno == KDC_PR_UNKNOWN) {
warnx("Warning: TGT not verified.");
- syslog(LOG_NOTICE|LOG_AUTH,
+ syslog(LOG_NOTICE,
"%s to %s%s, TGT not verified (%s); %s.%s not registered?",
username, user, ontty(), krb_err_txt[kerno],
"rcmd", savehost);
} else if (kerno != KSUCCESS) {
warnx("Unable to use TGT: %s", krb_err_txt[kerno]);
- syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s",
+ syslog(LOG_NOTICE, "failed su: %s to %s%s: %s",
username, user, ontty(), krb_err_txt[kerno]);
dest_tkt();
return (1);
@@ -548,9 +698,9 @@ kerberos(username, user, uid, pword)
if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
&authdata, "")) != KSUCCESS) {
- warnx("kerberos: unable to verify rcmd ticket: %s\n",
+ warnx("kerberos: unable to verify rcmd ticket: %s",
krb_err_txt[kerno]);
- syslog(LOG_NOTICE|LOG_AUTH,
+ syslog(LOG_NOTICE,
"failed su: %s to %s%s: %s", username,
user, ontty(), krb_err_txt[kerno]);
dest_tkt();
OpenPOWER on IntegriCloud