Add full PAM support for account management and sessions.
The PAM_FAIL_CHECK and PAM_END macros in su.c came from the util-linux package's PAM patches to the BSD login.c Submitted by: "David J. MacKenzie" <djm@web.us.uu.net>
This commit is contained in:
parent
b2f6bdeeaa
commit
5bc9d93db3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=74874
97
etc/pam.conf
97
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
|
||||
|
||||
# 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
|
||||
rsh auth required pam_permit.so
|
||||
rsh account required pam_unix.so
|
||||
rsh session required pam_permit.so
|
||||
|
||||
#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
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -1041,13 +1045,22 @@ end_login()
|
||||
#ifdef LOGIN_CAP
|
||||
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 @@ pass(passwd)
|
||||
(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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 @@ doit(fromp)
|
||||
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 @@ doit(fromp)
|
||||
(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 @@ doit(fromp)
|
||||
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 @@ doit(fromp)
|
||||
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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 ,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ,
|
||||
|
272
usr.bin/su/su.c
272
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();
|
||||
|
Loading…
Reference in New Issue
Block a user