import NetBSD su
This commit is contained in:
parent
4f78dfcabc
commit
4de51eedad
12 changed files with 1703 additions and 216 deletions
|
@ -26,7 +26,7 @@ SUBDIR= add_route arp ash at awk \
|
|||
reboot remsync rev rget rlogin \
|
||||
rotate rsh rshd sed service setup shar acksize \
|
||||
sleep slip sort spell split srccrc \
|
||||
stty su sum svclog swifi sync synctree sysenv \
|
||||
stty sum svclog swifi sync synctree sysenv \
|
||||
syslogd tail tar tcpd tcpdp tcpstat tee telnet \
|
||||
telnetd term termcap tget time touch tr \
|
||||
truncate tsort tty udpstat umount uname unexpand \
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
PROG= su
|
||||
BINMODE= 4755
|
||||
MAN=
|
||||
LDADD+= -lcrypt
|
||||
|
||||
|
||||
.include <bsd.prog.mk>
|
149
commands/su/su.c
149
commands/su/su.c
|
@ -1,149 +0,0 @@
|
|||
/* su - become super-user Author: Patrick van Kleef */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if __minix_vmd
|
||||
#include <sys/syslog.h>
|
||||
#endif
|
||||
#include <minix/minlib.h>
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register char *name, *password;
|
||||
char *shell, sh0[100];
|
||||
char from_user[8+1], from_shell[100];
|
||||
register struct passwd *pwd;
|
||||
char USER[20], LOGNAME[25], HOME[100], SHELL[100];
|
||||
char *envv[20], **envp;
|
||||
int smallenv;
|
||||
char *p;
|
||||
int super;
|
||||
int loginshell;
|
||||
gid_t groups[NGROUPS_MAX];
|
||||
int ngroups;
|
||||
int g;
|
||||
|
||||
smallenv = 0;
|
||||
loginshell = 0;
|
||||
if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-e") == 0)) {
|
||||
if (argv[1][1] == 0)
|
||||
loginshell= 1; /* 'su -' reads .profile */
|
||||
argv[1] = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
smallenv = 1; /* Use small environment. */
|
||||
}
|
||||
if (argc > 1) {
|
||||
if (argv[1][0] == '-') {
|
||||
fprintf(stderr,
|
||||
"Usage: su [-[e]] [user [shell-arguments ...]]\n");
|
||||
exit(1);
|
||||
}
|
||||
name = argv[1];
|
||||
argv[1] = argv[0];
|
||||
argv++;
|
||||
} else {
|
||||
name = "root";
|
||||
}
|
||||
|
||||
if ((pwd = getpwuid(getuid())) == 0) {
|
||||
fprintf(stderr, "You do not exist\n");
|
||||
exit(1);
|
||||
}
|
||||
strncpy(from_user, pwd->pw_name, 8);
|
||||
from_user[8]= 0;
|
||||
strncpy(from_shell, pwd->pw_shell[0] == '\0' ? "/bin/sh" : pwd->pw_shell,
|
||||
sizeof(from_shell)-1);
|
||||
from_shell[sizeof(from_shell)-1]= 0;
|
||||
|
||||
if ((pwd = getpwnam(name)) == 0) {
|
||||
fprintf(stderr, "Unknown id: %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
super = 0;
|
||||
if (getgid() == 0) super = 1;
|
||||
ngroups = getgroups(NGROUPS_MAX, groups);
|
||||
for (g = 0; g < ngroups; g++) if (groups[g] == 0) super = 1;
|
||||
|
||||
if (!super && strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)) != 0) {
|
||||
#if __minix_vmd
|
||||
openlog("su", 0, LOG_AUTH);
|
||||
#endif
|
||||
password = getpass("Password:");
|
||||
if (password == 0
|
||||
|| strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) {
|
||||
if (password != 0 && *password != 0) {
|
||||
#if __minix_vmd
|
||||
syslog(LOG_WARNING, "su %s failed for %s",
|
||||
name, from_user);
|
||||
#endif
|
||||
}
|
||||
fprintf(stderr, "Sorry\n");
|
||||
exit(2);
|
||||
}
|
||||
#if __minix_vmd
|
||||
syslog(LOG_NOTICE, "su %s succeeded for %s", name, from_user);
|
||||
closelog();
|
||||
#endif
|
||||
}
|
||||
|
||||
initgroups(pwd->pw_name, pwd->pw_gid);
|
||||
setgid(pwd->pw_gid);
|
||||
setuid(pwd->pw_uid);
|
||||
if (loginshell) {
|
||||
shell = pwd->pw_shell[0] == '\0' ? "/bin/sh" : pwd->pw_shell;
|
||||
} else {
|
||||
if ((shell = getenv("SHELL")) == NULL) shell = from_shell;
|
||||
}
|
||||
if ((p= strrchr(shell, '/')) == 0) p= shell; else p++;
|
||||
sh0[0]= '-';
|
||||
strcpy(loginshell ? sh0+1 : sh0, p);
|
||||
argv[0]= sh0;
|
||||
|
||||
if (smallenv) {
|
||||
envp = envv;
|
||||
*envp++ = "PATH=:/bin:/usr/bin",
|
||||
strcpy(USER, "USER=");
|
||||
strcpy(USER + 5, name);
|
||||
*envp++ = USER;
|
||||
strcpy(LOGNAME, "LOGNAME=");
|
||||
strcpy(LOGNAME + 8, name);
|
||||
*envp++ = LOGNAME;
|
||||
strcpy(SHELL, "SHELL=");
|
||||
strcpy(SHELL + 6, shell);
|
||||
*envp++ = SHELL;
|
||||
strcpy(HOME, "HOME=");
|
||||
strcpy(HOME + 5, pwd->pw_dir);
|
||||
*envp++ = HOME;
|
||||
if ((p = getenv("TERM")) != NULL) {
|
||||
*envp++ = p - 5;
|
||||
}
|
||||
if ((p = getenv("TERMCAP")) != NULL) {
|
||||
*envp++ = p - 8;
|
||||
}
|
||||
if ((p = getenv("TZ")) != NULL) {
|
||||
*envp++ = p - 3;
|
||||
}
|
||||
*envp = NULL;
|
||||
(void) chdir(pwd->pw_dir);
|
||||
execve(shell, argv, envv);
|
||||
perror(shell);
|
||||
} else {
|
||||
execv(shell, argv);
|
||||
perror(shell);
|
||||
}
|
||||
fprintf(stderr, "No shell\n");
|
||||
return(3);
|
||||
}
|
|
@ -16,7 +16,7 @@ MAN= ash.1 at.1 banner.1 basename.1 \
|
|||
profile.1 ps.1 pwd.1 rcp.1 readall.1 recwave.1 \
|
||||
ref.1 remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
|
||||
shar.1 acksize.1 sleep.1 sort.1 spell.1 \
|
||||
split.1 stty.1 su.1 sum.1 svc.1 \
|
||||
split.1 stty.1 sum.1 svc.1 \
|
||||
synctree.1 sysenv.1 sz.1 tail.1 tee.1 telnet.1 template.1 \
|
||||
term.1 termcap.1 tget.1 time.1 tr.1 true.1 \
|
||||
truncate.1 tsort.1 tty.1 umount.1 uname.1 unexpand.1 \
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
.TH SU 1
|
||||
.SH NAME
|
||||
su \- temporary become superuser or another user
|
||||
.SH SYNOPSIS
|
||||
.B su
|
||||
.RB [ \- [ e ]]
|
||||
.RI [ user
|
||||
.RI [ shell-arguments " ...]]"
|
||||
.SH DESCRIPTION
|
||||
.de SP
|
||||
.if t .sp 0.4
|
||||
.if n .sp
|
||||
..
|
||||
.B Su
|
||||
can be used to temporarily run a shell under the identity of the superuser
|
||||
or another user. Unless the caller is a member of the operator group, one
|
||||
is prompted for the password of the user-to-be. Calls that need a password
|
||||
are logged, whether they succeed or not. The default user is
|
||||
.BR root .
|
||||
Further arguments are handed to the shell. By default the shell started is
|
||||
the shell of the invoker, and the environment is passed on as is.
|
||||
.PP
|
||||
The activities of
|
||||
.B su
|
||||
are logged through
|
||||
.BR syslog (3)
|
||||
under Minix-vmd.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-
|
||||
Constructs a new environment consisting of the
|
||||
.BR PATH ,
|
||||
.BR USER ,
|
||||
.BR LOGNAME ,
|
||||
.BR HOME ,
|
||||
.BR SHELL ,
|
||||
.BR TERM ,
|
||||
.BR TERMCAP ,
|
||||
and
|
||||
.BR TZ
|
||||
variables. The environment is the same as on a normal login, except that
|
||||
.BR TERM ,
|
||||
.B TERMCAP
|
||||
and
|
||||
.B TZ
|
||||
are copied from the current environment if set. The current working
|
||||
directory is changed to the user home directory, the shell of the user-to-be
|
||||
is run, and it is started as a login shell, with the first character a minus
|
||||
sign.
|
||||
.TP
|
||||
.B \-e
|
||||
Like above, but the shell is started normally, not as a login shell.
|
||||
.SH "SEE ALSO"
|
||||
.BR sh (1),
|
||||
.BR login (1),
|
||||
.BR syslog (3).
|
||||
.SH AUTHOR
|
||||
Kees J. Bot <kjb@cs.vu.nl>
|
|
@ -2,6 +2,7 @@
|
|||
# Timestamp in UTC,minixpath,netbsdpath
|
||||
# minixpath: path in Minix source tree (starting from /usr/src/)
|
||||
# netbsdpath: path in BSD source tree (starting from src/)
|
||||
2012/02/10 16:16:12,usr.bin/su
|
||||
2011/12/25 06:09:09,sys/arch/i386/stand
|
||||
2012/02/10 16:16:12,share/zoneinfo
|
||||
2012/02/10 16:16:12,share/misc
|
||||
|
|
71
usr.bin/su/Makefile
Normal file
71
usr.bin/su/Makefile
Normal file
|
@ -0,0 +1,71 @@
|
|||
# $NetBSD: Makefile,v 1.50 2011/04/24 21:42:06 elric Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
USE_PAM=no
|
||||
USE_KERBEROS=no
|
||||
|
||||
USE_FORT?= yes # setuid
|
||||
PROG= su
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
.PATH.c: ${.CURDIR}/../newgrp
|
||||
CPPFLAGS+=-I${.CURDIR}/../newgrp
|
||||
CPPFLAGS+=-DLOGIN_CAP
|
||||
CPPFLAGS+=-DALLOW_GROUP_CHANGE
|
||||
CPPFLAGS+=-DALLOW_EMPTY_USER
|
||||
CPPFLAGS+=-DGRUTIL_SETGROUPS_MAKESPACE
|
||||
|
||||
.if ${USE_PAM} != "no"
|
||||
|
||||
CPPFLAGS+=-DUSE_PAM
|
||||
# XXX: Need libcrypt here, because libcrypto defines it too.
|
||||
DPADD+= ${LIBPAM} ${LIBCRYPT} ${LIBUTIL} ${PAM_STATIC_DPADD}
|
||||
LDADD+= -lpam -lcrypt -lutil ${PAM_STATIC_LDADD}
|
||||
SRCS=su_pam.c grutil.c suutil.c
|
||||
|
||||
.else # USE_PAM == no
|
||||
|
||||
SRCS=su.c grutil.c suutil.c
|
||||
|
||||
DPADD+= ${LIBCRYPT} ${LIBUTIL}
|
||||
LDADD+= -lcrypt -lutil
|
||||
|
||||
# Uncomment the following line to change the group that may su root to "sugroup"
|
||||
#
|
||||
#CPPFLAGS+=-DSU_GROUP=\"sugroup\"
|
||||
|
||||
# Uncomment the following line to make su
|
||||
# treat group wheel (SUGROUP) and/or ROOTAUTH as an indirect
|
||||
# list of groups.
|
||||
#CPPFLAGS+=-DSU_INDIRECT_GROUP
|
||||
|
||||
.if (${USE_KERBEROS} != "no")
|
||||
.ifdef AFS
|
||||
DPADD+= ${LIBKAFS}
|
||||
LDADD+= -lkafs
|
||||
.endif
|
||||
|
||||
CPPFLAGS+=-DKERBEROS5
|
||||
DPADD+= ${LIBKRB5} ${LIBASN1}
|
||||
LDADD+= -lkrb5 -lasn1
|
||||
|
||||
DPADD+= ${LIBCRYPTO} ${LIBROKEN} ${LIBCOM_ERR}
|
||||
LDADD+= -lcrypto -lroken -lcom_err
|
||||
.endif
|
||||
|
||||
.if (${USE_SKEY} != "no")
|
||||
CPPFLAGS+=-DSKEY
|
||||
DPADD+= ${LIBSKEY}
|
||||
LDADD+= -lskey
|
||||
.endif
|
||||
|
||||
.ifdef SU_ROOTAUTH
|
||||
CPPFLAGS+=-DSU_ROOTAUTH=\"${SU_ROOTAUTH}\"
|
||||
.endif
|
||||
|
||||
.endif # USE_PAM == no
|
||||
|
||||
.include <bsd.prog.mk>
|
386
usr.bin/su/su.1
Normal file
386
usr.bin/su/su.1
Normal file
|
@ -0,0 +1,386 @@
|
|||
.\" Copyright (c) 1988, 1990, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)su.1 8.2 (Berkeley) 4/18/94
|
||||
.\" $NetBSD: su.1,v 1.49 2009/05/18 09:37:44 wiz Exp $
|
||||
.\"
|
||||
.Dd October 27, 2007
|
||||
.Dt SU 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm su
|
||||
.Nd substitute user identity
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dfKlm
|
||||
.Op Fl c Ar login-class
|
||||
.Oo
|
||||
.Ar login Ns Op : Ns Ar group
|
||||
.Op Ar "shell arguments"
|
||||
.Oc
|
||||
.Nm
|
||||
.Op Fl dfKlm
|
||||
.Op Fl c Ar login-class
|
||||
.Oo
|
||||
.Ns : Ns Ar group
|
||||
.Op Ar "shell arguments"
|
||||
.Oc
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
allows one user to become another user
|
||||
.Ar login
|
||||
without logging out and in as
|
||||
the new user.
|
||||
If a
|
||||
.Ar group
|
||||
is specified and
|
||||
.Ar login
|
||||
is a member of
|
||||
.Ar group ,
|
||||
then the group is changed to
|
||||
.Ar group
|
||||
rather than to
|
||||
.Ar login Ns 's
|
||||
primary group.
|
||||
If
|
||||
.Ar login
|
||||
is omitted and
|
||||
.Ar group
|
||||
is provided (form two above), then
|
||||
.Ar login
|
||||
is assumed to be the current username.
|
||||
.Pp
|
||||
When executed by a user, the
|
||||
.Ar login
|
||||
user's password is requested.
|
||||
When using Kerberos, the password for
|
||||
.Ar login
|
||||
(or for
|
||||
.Dq Ar login Ns .root ,
|
||||
if no login is provided) is requested, and
|
||||
.Nm
|
||||
switches to that user and group ID after obtaining a Kerberos ticket
|
||||
granting ticket.
|
||||
A shell is then executed, and any additional
|
||||
.Ar "shell arguments"
|
||||
after the login name are passed to the shell.
|
||||
.Nm
|
||||
will resort to the local password file to find the password for
|
||||
.Ar login
|
||||
if there is a Kerberos error.
|
||||
If
|
||||
.Nm
|
||||
is executed by root, no password is requested and a shell
|
||||
with the appropriate user ID is executed; no additional Kerberos tickets
|
||||
are obtained.
|
||||
.Pp
|
||||
Alternatively, if the user enters the password "s/key", authentication
|
||||
will use the S/Key one-time password system as described in
|
||||
.Xr skey 1 .
|
||||
S/Key is a Trademark of Bellcore.
|
||||
.Pp
|
||||
By default, the environment is unmodified with the exception of
|
||||
.Ev LOGNAME ,
|
||||
.Ev USER ,
|
||||
.Ev HOME ,
|
||||
.Ev SHELL ,
|
||||
and
|
||||
.Ev SU_FROM .
|
||||
.Ev HOME
|
||||
and
|
||||
.Ev SHELL
|
||||
are set to the target login's default values.
|
||||
.Ev LOGNAME
|
||||
and
|
||||
.Ev USER
|
||||
are set to the target login, unless the target login has a user ID of 0,
|
||||
in which case they are unmodified.
|
||||
.Ev SU_FROM
|
||||
is set to the caller's login.
|
||||
The invoked shell is the target login's.
|
||||
With the exception of
|
||||
.Ev SU_FROM
|
||||
this is the traditional behavior of
|
||||
.Nm .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl c
|
||||
Specify a login class.
|
||||
You may only override the default class if you're already root.
|
||||
See
|
||||
.Xr login.conf 5
|
||||
for details.
|
||||
.It Fl d
|
||||
Same as
|
||||
.Fl l ,
|
||||
but does not change the current directory.
|
||||
.It Fl f
|
||||
If the invoked shell is
|
||||
.Xr csh 1 ,
|
||||
this option prevents it from reading the
|
||||
.Dq Pa .cshrc
|
||||
file.
|
||||
If the invoked shell is
|
||||
.Xr sh 1 ,
|
||||
or
|
||||
.Xr ksh 1 ,
|
||||
this option unsets
|
||||
.Ev ENV ,
|
||||
thus preventing the shell from executing the startup file pointed to by
|
||||
this variable.
|
||||
.It Fl K
|
||||
Do not attempt to use Kerberos to authenticate the user.
|
||||
.It Fl l
|
||||
Simulate a full login.
|
||||
The environment is discarded except for
|
||||
.Ev HOME ,
|
||||
.Ev SHELL ,
|
||||
.Ev PATH ,
|
||||
.Ev TERM ,
|
||||
.Ev LOGNAME ,
|
||||
.Ev USER ,
|
||||
and
|
||||
.Ev SU_FROM .
|
||||
.Ev HOME ,
|
||||
.Ev SHELL ,
|
||||
and
|
||||
.Ev SU_FROM
|
||||
are modified as above.
|
||||
.Ev LOGNAME
|
||||
and
|
||||
.Ev USER
|
||||
are set to the target login.
|
||||
.Ev PATH
|
||||
is set to the path specified in the
|
||||
.Pa /etc/login.conf
|
||||
file (or to the default of
|
||||
.Dq Pa /usr/bin:/bin:/usr/pkg/bin:/usr/local/bin
|
||||
).
|
||||
.Ev TERM
|
||||
is imported from your current environment.
|
||||
The invoked shell is the target login's, and
|
||||
.Nm
|
||||
will change directory to the target login's home directory.
|
||||
.It Fl
|
||||
Same as
|
||||
.Fl l .
|
||||
.It Fl m
|
||||
Leave the environment unmodified.
|
||||
The invoked shell is your login shell, and no directory changes are made.
|
||||
As a security precaution, if the target user's shell is a non-standard
|
||||
shell (as defined by
|
||||
.Xr getusershell 3 )
|
||||
and the caller's real uid is
|
||||
non-zero,
|
||||
.Nm
|
||||
will fail.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fl l
|
||||
and
|
||||
.Fl m
|
||||
options are mutually exclusive; the last one specified
|
||||
overrides any previous ones.
|
||||
.Pp
|
||||
Only users in group
|
||||
.Dq wheel
|
||||
(normally gid 0),
|
||||
as listed in
|
||||
.Pa /etc/group ,
|
||||
can
|
||||
.Nm
|
||||
to
|
||||
.Dq root ,
|
||||
unless group wheel does not exist or has no members.
|
||||
(If you do not want anybody to be able to
|
||||
.Nm
|
||||
to
|
||||
.Dq root ,
|
||||
make
|
||||
.Dq root
|
||||
the only member of group
|
||||
.Dq wheel ,
|
||||
which is the default.)
|
||||
.Pp
|
||||
For sites with very large user populations, group
|
||||
.Dq wheel
|
||||
can contain the names of other groups that will be considered authorized
|
||||
to
|
||||
.Nm
|
||||
to
|
||||
.Dq root .
|
||||
.Pp
|
||||
By default (unless the prompt is reset by a startup file) the super-user
|
||||
prompt is set to
|
||||
.Dq Sy \&#
|
||||
to remind one of its awesome power.
|
||||
.Sh CUSTOMIZATION
|
||||
.Bl -tag -width ""
|
||||
.It Changing required group
|
||||
For the
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm
|
||||
the name of the required group can be changed by setting
|
||||
.Ar gname
|
||||
in
|
||||
.Xr pam.conf 5 :
|
||||
.Bd -literal
|
||||
auth requisite pam_group.so no_warn group=gname root_only fail_safe
|
||||
.Ed
|
||||
.Pp
|
||||
For the non
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm
|
||||
the same can be achieved by compiling with
|
||||
.Dv SU_GROUP
|
||||
set to the desired group name.
|
||||
.It Supplying own password
|
||||
.Nm
|
||||
can be configured so that users in a particular group can supply their
|
||||
own password to become
|
||||
.Dq root .
|
||||
For the
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm
|
||||
this can be done by adding a line to
|
||||
.Xr pam.conf 5
|
||||
such as:
|
||||
.Bd -literal
|
||||
auth sufficient pam_group.so no_warn group=gname root_only authenticate
|
||||
.Ed
|
||||
.Pp
|
||||
where
|
||||
.Ar gname
|
||||
is the name of the desired group.
|
||||
For the non
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm
|
||||
the same can be achieved by compiling with
|
||||
.Dv SU_ROOTAUTH
|
||||
set to the desired group name.
|
||||
.It Indirect groups
|
||||
This option is not available with the
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm .
|
||||
For the non
|
||||
.Xr pam 8
|
||||
version of
|
||||
.Nm ,
|
||||
if
|
||||
.Dv SU_INDIRECT_GROUP
|
||||
is defined, the
|
||||
.Ar SU_GROUP
|
||||
and
|
||||
.Ar SU_ROOTAUTH
|
||||
groups are treated as indirect groups.
|
||||
The group members of those two groups are treated as groups themselves.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
returns the exit status of the executed subshell, or 1 if any error
|
||||
occurred while switching privileges.
|
||||
.Sh ENVIRONMENT
|
||||
Environment variables used by
|
||||
.Nm :
|
||||
.Bl -tag -width "HOME"
|
||||
.It Ev HOME
|
||||
Default home directory of real user ID unless modified as
|
||||
specified above.
|
||||
.It Ev LOGNAME
|
||||
The user ID is always the effective ID (the target user ID) after an
|
||||
.Nm
|
||||
unless the user ID is 0 (root).
|
||||
.It Ev PATH
|
||||
Default search path of real user ID unless modified as specified above.
|
||||
.It Ev TERM
|
||||
Provides terminal type which may be retained for the substituted
|
||||
user ID.
|
||||
.It Ev USER
|
||||
The user ID is always the effective ID (the target user ID) after an
|
||||
.Nm
|
||||
unless the user ID is 0 (root).
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
To become user username and use the same environment as in original shell, execute:
|
||||
.Bd -literal -offset indent
|
||||
su username
|
||||
.Ed
|
||||
.Pp
|
||||
To become user username and use environment as if full login would be performed,
|
||||
execute:
|
||||
.Bd -literal -offset indent
|
||||
su -l username
|
||||
.Ed
|
||||
.Pp
|
||||
When a
|
||||
.Fl c
|
||||
option is included
|
||||
.Em after
|
||||
the
|
||||
.Ar login
|
||||
name it is not a
|
||||
.Nm
|
||||
option, because any arguments after the
|
||||
.Ar login
|
||||
are passed to the shell.
|
||||
(See
|
||||
.Xr csh 1 ,
|
||||
.Xr ksh 1
|
||||
or
|
||||
.Xr sh 1
|
||||
for details.)
|
||||
To execute arbitrary command with privileges of user
|
||||
.Em username ,
|
||||
execute:
|
||||
.Bd -literal -offset indent
|
||||
su username -c "command args"
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr csh 1 ,
|
||||
.Xr kinit 1 ,
|
||||
.Xr login 1 ,
|
||||
.Xr sh 1 ,
|
||||
.Xr skey 1 ,
|
||||
.Xr setusercontext 3 ,
|
||||
.Xr group 5 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr passwd 5 ,
|
||||
.Xr environ 7 ,
|
||||
.Xr kerberos 8
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
command existed in
|
||||
.At v5
|
||||
(and probably earlier).
|
585
usr.bin/su/su.c
Normal file
585
usr.bin/su/su.c
Normal file
|
@ -0,0 +1,585 @@
|
|||
/* $NetBSD: su.c,v 1.69 2011/08/31 16:24:58 plunky Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1988\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";*/
|
||||
#else
|
||||
__RCSID("$NetBSD: su.c,v 1.69 2011/08/31 16:24:58 plunky Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef SKEY
|
||||
#include <skey.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
#include <login_cap.h>
|
||||
#endif
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#include <krb5.h>
|
||||
#endif
|
||||
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
#include "grutil.h"
|
||||
#endif
|
||||
#include "suutil.h"
|
||||
|
||||
#ifdef KERBEROS5
|
||||
#define ARGSTRX "-Kdflm"
|
||||
static int kerberos5(char *, const char *, uid_t);
|
||||
int use_kerberos = 1;
|
||||
#else
|
||||
#define ARGSTRX "-dflm"
|
||||
#endif
|
||||
|
||||
#ifndef SU_GROUP
|
||||
#define SU_GROUP "wheel"
|
||||
#endif
|
||||
|
||||
#define GROUP_PASSWORD "Group Password:"
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
#define ARGSTR ARGSTRX "c:"
|
||||
#else
|
||||
#define ARGSTR ARGSTRX
|
||||
#endif
|
||||
|
||||
static int check_ingroup(int, const char *, const char *, int);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
extern char **environ;
|
||||
struct passwd *pwd;
|
||||
char *p;
|
||||
#ifdef BSD4_4
|
||||
struct timeval tp;
|
||||
#endif
|
||||
uid_t ruid;
|
||||
int asme, ch, asthem, fastlogin, prio, gohome;
|
||||
enum { UNSET, YES, NO } iscsh = UNSET;
|
||||
const char *user, *shell, *avshell;
|
||||
char *username, **np;
|
||||
char *userpass, *class;
|
||||
char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
|
||||
time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
|
||||
#ifdef LOGIN_CAP
|
||||
login_cap_t *lc;
|
||||
#endif
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
char *gname;
|
||||
#endif
|
||||
|
||||
(void)setprogname(argv[0]);
|
||||
asme = asthem = fastlogin = 0;
|
||||
gohome = 1;
|
||||
shell = class = NULL;
|
||||
while ((ch = getopt(argc, argv, ARGSTR)) != -1)
|
||||
switch((char)ch) {
|
||||
#ifdef KERBEROS5
|
||||
case 'K':
|
||||
use_kerberos = 0;
|
||||
break;
|
||||
#endif
|
||||
#ifdef LOGIN_CAP
|
||||
case 'c':
|
||||
class = optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'd':
|
||||
asme = 0;
|
||||
asthem = 1;
|
||||
gohome = 0;
|
||||
break;
|
||||
case 'f':
|
||||
fastlogin = 1;
|
||||
break;
|
||||
case '-':
|
||||
case 'l':
|
||||
asme = 0;
|
||||
asthem = 1;
|
||||
break;
|
||||
case 'm':
|
||||
asme = 1;
|
||||
asthem = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
(void)fprintf(stderr,
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
"usage: %s [%s] [login[:group] [shell arguments]]\n",
|
||||
#else
|
||||
"usage: %s [%s] [login [shell arguments]]\n",
|
||||
#endif
|
||||
getprogname(), ARGSTR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
argv += optind;
|
||||
|
||||
/* Lower the priority so su runs faster */
|
||||
errno = 0;
|
||||
prio = getpriority(PRIO_PROCESS, 0);
|
||||
if (errno)
|
||||
prio = 0;
|
||||
if (prio > -2)
|
||||
(void)setpriority(PRIO_PROCESS, 0, -2);
|
||||
openlog("su", 0, LOG_AUTH);
|
||||
|
||||
/* get current login name and shell */
|
||||
ruid = getuid();
|
||||
username = getlogin();
|
||||
if (username == NULL || (pwd = getpwnam(username)) == NULL ||
|
||||
pwd->pw_uid != ruid)
|
||||
pwd = getpwuid(ruid);
|
||||
if (pwd == NULL)
|
||||
errx(EXIT_FAILURE, "who are you?");
|
||||
username = estrdup(pwd->pw_name);
|
||||
userpass = estrdup(pwd->pw_passwd);
|
||||
|
||||
if (asme) {
|
||||
if (pwd->pw_shell && *pwd->pw_shell) {
|
||||
(void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
|
||||
shell = shellbuf;
|
||||
} else {
|
||||
shell = _PATH_BSHELL;
|
||||
iscsh = NO;
|
||||
}
|
||||
}
|
||||
/* get target login information, default to root */
|
||||
user = *argv ? *argv : "root";
|
||||
np = *argv ? argv : argv - 1;
|
||||
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
if ((p = strchr(user, ':')) != NULL) {
|
||||
*p = '\0';
|
||||
gname = ++p;
|
||||
}
|
||||
else
|
||||
gname = NULL;
|
||||
|
||||
#ifdef ALLOW_EMPTY_USER
|
||||
if (user[0] == '\0' && gname != NULL)
|
||||
user = username;
|
||||
#endif
|
||||
#endif
|
||||
if ((pwd = getpwnam(user)) == NULL)
|
||||
errx(EXIT_FAILURE, "unknown login `%s'", user);
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
/* force the usage of specified class */
|
||||
if (class) {
|
||||
if (ruid)
|
||||
errx(EXIT_FAILURE, "Only root may use -c");
|
||||
|
||||
pwd->pw_class = class;
|
||||
}
|
||||
if ((lc = login_getclass(pwd->pw_class)) == NULL)
|
||||
errx(EXIT_FAILURE, "Unknown class %s\n", pwd->pw_class);
|
||||
|
||||
pw_warntime = (time_t)login_getcaptime(lc, "password-warn",
|
||||
_PASSWORD_WARNDAYS * SECSPERDAY,
|
||||
_PASSWORD_WARNDAYS * SECSPERDAY);
|
||||
#endif
|
||||
|
||||
if (ruid
|
||||
#ifdef KERBEROS5
|
||||
&& (!use_kerberos || kerberos5(username, user, pwd->pw_uid))
|
||||
#endif
|
||||
) {
|
||||
char *pass = pwd->pw_passwd;
|
||||
int ok = pwd->pw_uid != 0;
|
||||
|
||||
#ifdef SU_ROOTAUTH
|
||||
/*
|
||||
* Allow those in group rootauth to su to root, by supplying
|
||||
* their own password.
|
||||
*/
|
||||
if (!ok) {
|
||||
if ((ok = check_ingroup(-1, SU_ROOTAUTH, username, 0))) {
|
||||
pass = userpass;
|
||||
user = username;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Only allow those in group SU_GROUP to su to root,
|
||||
* but only if that group has any members.
|
||||
* If SU_GROUP has no members, allow anyone to su root
|
||||
*/
|
||||
if (!ok)
|
||||
ok = check_ingroup(-1, SU_GROUP, username, 1);
|
||||
if (!ok)
|
||||
errx(EXIT_FAILURE,
|
||||
"you are not listed in the correct secondary group (%s) to su %s.",
|
||||
SU_GROUP, user);
|
||||
/* if target requires a password, verify it */
|
||||
if (*pass && pwd->pw_uid != ruid) { /* XXX - OK? */
|
||||
p = getpass("Password:");
|
||||
#ifdef SKEY
|
||||
if (strcasecmp(p, "s/key") == 0) {
|
||||
if (skey_haskey(user))
|
||||
errx(EXIT_FAILURE,
|
||||
"Sorry, you have no s/key.");
|
||||
else {
|
||||
if (skey_authenticate(user)) {
|
||||
goto badlogin;
|
||||
}
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
if (strcmp(pass, crypt(p, pass)) != 0) {
|
||||
#ifdef SKEY
|
||||
badlogin:
|
||||
#endif
|
||||
(void)fprintf(stderr, "Sorry\n");
|
||||
syslog(LOG_WARNING,
|
||||
"BAD SU %s to %s%s", username,
|
||||
pwd->pw_name, ontty());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (asme) {
|
||||
/* if asme and non-standard target shell, must be root */
|
||||
if (chshell(pwd->pw_shell) == 0 && ruid)
|
||||
errx(EXIT_FAILURE, "permission denied (shell).");
|
||||
} else if (pwd->pw_shell && *pwd->pw_shell) {
|
||||
shell = pwd->pw_shell;
|
||||
iscsh = UNSET;
|
||||
} else {
|
||||
shell = _PATH_BSHELL;
|
||||
iscsh = NO;
|
||||
}
|
||||
|
||||
if ((p = strrchr(shell, '/')) != NULL)
|
||||
avshell = p+1;
|
||||
else
|
||||
avshell = shell;
|
||||
|
||||
/* if we're forking a csh, we want to slightly muck the args */
|
||||
if (iscsh == UNSET)
|
||||
iscsh = strstr(avshell, "csh") ? YES : NO;
|
||||
|
||||
/* set permissions */
|
||||
#ifdef LOGIN_CAP
|
||||
# ifdef ALLOW_GROUP_CHANGE
|
||||
/* if we aren't changing users, keep the current group members */
|
||||
if (ruid != pwd->pw_uid &&
|
||||
setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
|
||||
err(EXIT_FAILURE, "setting user context");
|
||||
|
||||
addgroup(lc, gname, pwd, ruid, GROUP_PASSWORD);
|
||||
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid,
|
||||
(u_int)(asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
|
||||
LOGIN_SETRESOURCES | LOGIN_SETUSER) == -1)
|
||||
err(EXIT_FAILURE, "setting user context");
|
||||
# else
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid,
|
||||
(u_int)(asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
|
||||
LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETUSER) == -1)
|
||||
err(EXIT_FAILURE, "setting user context");
|
||||
# endif
|
||||
#else
|
||||
if (setgid(pwd->pw_gid) == -1)
|
||||
err(EXIT_FAILURE, "setgid");
|
||||
/* if we aren't changing users, keep the current group members */
|
||||
if (ruid != pwd->pw_uid && initgroups(user, pwd->pw_gid) != 0)
|
||||
errx(EXIT_FAILURE, "initgroups failed");
|
||||
# ifdef ALLOW_GROUP_CHANGE
|
||||
addgroup(/*EMPTY*/, gname, pwd, ruid, GROUP_PASSWORD);
|
||||
# endif
|
||||
if (setuid(pwd->pw_uid) == -1)
|
||||
err(EXIT_FAILURE, "setuid");
|
||||
#endif
|
||||
|
||||
if (!asme) {
|
||||
if (asthem) {
|
||||
p = getenv("TERM");
|
||||
/* Create an empty environment */
|
||||
environ = emalloc(sizeof(char *));
|
||||
environ[0] = NULL;
|
||||
#ifdef LOGIN_CAP
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid,
|
||||
LOGIN_SETPATH) == -1)
|
||||
err(EXIT_FAILURE, "setting user context");
|
||||
#else
|
||||
(void)setenv("PATH", _PATH_DEFPATH, 1);
|
||||
#endif
|
||||
if (p)
|
||||
(void)setenv("TERM", p, 1);
|
||||
if (gohome && chdir(pwd->pw_dir) == -1)
|
||||
errx(EXIT_FAILURE, "no directory");
|
||||
}
|
||||
|
||||
if (asthem || pwd->pw_uid) {
|
||||
(void)setenv("LOGNAME", pwd->pw_name, 1);
|
||||
(void)setenv("USER", pwd->pw_name, 1);
|
||||
}
|
||||
(void)setenv("HOME", pwd->pw_dir, 1);
|
||||
(void)setenv("SHELL", shell, 1);
|
||||
}
|
||||
(void)setenv("SU_FROM", username, 1);
|
||||
|
||||
if (iscsh == YES) {
|
||||
if (fastlogin)
|
||||
*np-- = __UNCONST("-f");
|
||||
if (asme)
|
||||
*np-- = __UNCONST("-m");
|
||||
} else {
|
||||
if (fastlogin)
|
||||
(void)unsetenv("ENV");
|
||||
}
|
||||
|
||||
if (asthem) {
|
||||
avshellbuf[0] = '-';
|
||||
(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
|
||||
avshell = avshellbuf;
|
||||
} else if (iscsh == YES) {
|
||||
/* csh strips the first character... */
|
||||
avshellbuf[0] = '_';
|
||||
(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
|
||||
avshell = avshellbuf;
|
||||
}
|
||||
*np = __UNCONST(avshell);
|
||||
|
||||
#ifdef BSD4_4
|
||||
if (pwd->pw_change || pwd->pw_expire)
|
||||
(void)gettimeofday(&tp, NULL);
|
||||
if (pwd->pw_change) {
|
||||
if (tp.tv_sec >= pwd->pw_change) {
|
||||
(void)printf("%s -- %s's password has expired.\n",
|
||||
(ruid ? "Sorry" : "Note"), user);
|
||||
if (ruid != 0)
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (pwd->pw_change - tp.tv_sec < pw_warntime)
|
||||
(void)printf("Warning: %s's password expires on %s",
|
||||
user, ctime(&pwd->pw_change));
|
||||
}
|
||||
if (pwd->pw_expire) {
|
||||
if (tp.tv_sec >= pwd->pw_expire) {
|
||||
(void)printf("%s -- %s's account has expired.\n",
|
||||
(ruid ? "Sorry" : "Note"), user);
|
||||
if (ruid != 0)
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (pwd->pw_expire - tp.tv_sec <
|
||||
_PASSWORD_WARNDAYS * SECSPERDAY)
|
||||
(void)printf("Warning: %s's account expires on %s",
|
||||
user, ctime(&pwd->pw_expire));
|
||||
}
|
||||
#endif
|
||||
if (ruid != 0)
|
||||
syslog(LOG_NOTICE, "%s to %s%s",
|
||||
username, pwd->pw_name, ontty());
|
||||
|
||||
/* Raise our priority back to what we had before */
|
||||
(void)setpriority(PRIO_PROCESS, 0, prio);
|
||||
|
||||
(void)execv(shell, np);
|
||||
err(EXIT_FAILURE, "%s", shell);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
#ifdef KERBEROS5
|
||||
static int
|
||||
kerberos5(char *username, const char *user, uid_t uid)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_context context;
|
||||
krb5_principal princ = NULL;
|
||||
krb5_ccache ccache, ccache2;
|
||||
char *cc_name;
|
||||
const char *filename;
|
||||
|
||||
ret = krb5_init_context(&context);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
if (strcmp(user, "root") == 0)
|
||||
ret = krb5_make_principal(context, &princ,
|
||||
NULL, username, "root", NULL);
|
||||
else
|
||||
ret = krb5_make_principal(context, &princ,
|
||||
NULL, user, NULL);
|
||||
if (ret)
|
||||
goto fail;
|
||||
if (!krb5_kuserok(context, princ, user) && !uid) {
|
||||
warnx("kerberos5: not in %s's ACL.", user);
|
||||
goto fail;
|
||||
}
|
||||
ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = krb5_verify_user_lrealm(context, princ, ccache, NULL, TRUE,
|
||||
NULL);
|
||||
if (ret) {
|
||||
krb5_cc_destroy(context, ccache);
|
||||
switch (ret) {
|
||||
case KRB5_LIBOS_PWDINTR :
|
||||
break;
|
||||
case KRB5KRB_AP_ERR_BAD_INTEGRITY:
|
||||
case KRB5KRB_AP_ERR_MODIFIED:
|
||||
krb5_warnx(context, "Password incorrect");
|
||||
break;
|
||||
default :
|
||||
krb5_warn(context, ret, "krb5_verify_user");
|
||||
break;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache2);
|
||||
if (ret) {
|
||||
krb5_cc_destroy(context, ccache);
|
||||
goto fail;
|
||||
}
|
||||
ret = krb5_cc_copy_cache(context, ccache, ccache2);
|
||||
if (ret) {
|
||||
krb5_cc_destroy(context, ccache);
|
||||
krb5_cc_destroy(context, ccache2);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
filename = krb5_cc_get_name(context, ccache2);
|
||||
(void)easprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
|
||||
filename);
|
||||
if (chown(filename, uid, NOGROUP) == -1) {
|
||||
warn("chown %s", filename);
|
||||
free(cc_name);
|
||||
krb5_cc_destroy(context, ccache);
|
||||
krb5_cc_destroy(context, ccache2);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void)setenv("KRB5CCNAME", cc_name, 1);
|
||||
free(cc_name);
|
||||
krb5_cc_close(context, ccache2);
|
||||
krb5_cc_destroy(context, ccache);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (princ != NULL)
|
||||
krb5_free_principal(context, princ);
|
||||
krb5_free_context(context);
|
||||
return 1;
|
||||
}
|
||||
#endif /* KERBEROS5 */
|
||||
|
||||
static int
|
||||
check_ingroup(int gid, const char *gname, const char *user, int ifempty)
|
||||
{
|
||||
struct group *gr;
|
||||
char **g;
|
||||
#ifdef SU_INDIRECT_GROUP
|
||||
char **gr_mem;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
#endif
|
||||
int ok = 0;
|
||||
|
||||
if (gname == NULL)
|
||||
gr = getgrgid((gid_t) gid);
|
||||
else
|
||||
gr = getgrnam(gname);
|
||||
|
||||
/*
|
||||
* XXX we are relying on the fact that we only set ifempty when
|
||||
* calling to check for SU_GROUP and that is the only time a
|
||||
* missing group is acceptable.
|
||||
*/
|
||||
if (gr == NULL)
|
||||
return ifempty;
|
||||
if (!*gr->gr_mem) /* empty */
|
||||
return ifempty;
|
||||
|
||||
/*
|
||||
* Ok, first see if user is in gr_mem
|
||||
*/
|
||||
for (g = gr->gr_mem; *g; ++g) {
|
||||
if (strcmp(*g, user) == 0)
|
||||
return 1; /* ok */
|
||||
#ifdef SU_INDIRECT_GROUP
|
||||
++n; /* count them */
|
||||
#endif
|
||||
}
|
||||
#ifdef SU_INDIRECT_GROUP
|
||||
/*
|
||||
* No.
|
||||
* Now we need to duplicate the gr_mem list, and recurse for
|
||||
* each member to see if it is a group, and if so whether user is
|
||||
* in it.
|
||||
*/
|
||||
gr_mem = emalloc((n + 1) * sizeof (char *));
|
||||
for (g = gr->gr_mem, i = 0; *g; ++g) {
|
||||
gr_mem[i] = estrdup(*g);
|
||||
i++;
|
||||
}
|
||||
gr_mem[i++] = NULL;
|
||||
|
||||
for (g = gr_mem; ok == 0 && *g; ++g) {
|
||||
/*
|
||||
* If we get this far we don't accept empty/missing groups.
|
||||
*/
|
||||
ok = check_ingroup(-1, *g, user, 0);
|
||||
}
|
||||
for (g = gr_mem; *g; ++g) {
|
||||
free(*g);
|
||||
}
|
||||
free(gr_mem);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
560
usr.bin/su/su_pam.c
Normal file
560
usr.bin/su/su_pam.c
Normal file
|
@ -0,0 +1,560 @@
|
|||
/* $NetBSD: su_pam.c,v 1.16 2010/10/02 10:55:36 tron Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1988\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";*/
|
||||
#else
|
||||
__RCSID("$NetBSD: su_pam.c,v 1.16 2010/10/02 10:55:36 tron Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
#include <login_cap.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h> /* for openpam_ttyconv() */
|
||||
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
#include "grutil.h"
|
||||
#endif
|
||||
#include "suutil.h"
|
||||
|
||||
static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
|
||||
|
||||
#define ARGSTRX "-dflm"
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
#define ARGSTR ARGSTRX "c:"
|
||||
#else
|
||||
#define ARGSTR ARGSTRX
|
||||
#endif
|
||||
|
||||
static void logit(const char *, ...);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
extern char **environ;
|
||||
struct passwd *pwd, pwres;
|
||||
char *p;
|
||||
uid_t ruid;
|
||||
int asme, ch, asthem, fastlogin, prio, gohome;
|
||||
u_int setwhat;
|
||||
enum { UNSET, YES, NO } iscsh = UNSET;
|
||||
const char *user, *shell, *avshell;
|
||||
char *username, *class;
|
||||
char **np;
|
||||
char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
|
||||
int pam_err;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
char *tty;
|
||||
const char *func;
|
||||
const void *newuser;
|
||||
login_cap_t *lc;
|
||||
pam_handle_t *pamh = NULL;
|
||||
char pwbuf[1024];
|
||||
#ifdef PAM_DEBUG
|
||||
extern int _openpam_debug;
|
||||
|
||||
_openpam_debug = 1;
|
||||
#endif
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
char *gname;
|
||||
#endif
|
||||
|
||||
(void)setprogname(argv[0]);
|
||||
asme = asthem = fastlogin = 0;
|
||||
gohome = 1;
|
||||
shell = class = NULL;
|
||||
while ((ch = getopt(argc, argv, ARGSTR)) != -1)
|
||||
switch((char)ch) {
|
||||
case 'c':
|
||||
class = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
asme = 0;
|
||||
asthem = 1;
|
||||
gohome = 0;
|
||||
break;
|
||||
case 'f':
|
||||
fastlogin = 1;
|
||||
break;
|
||||
case '-':
|
||||
case 'l':
|
||||
asme = 0;
|
||||
asthem = 1;
|
||||
break;
|
||||
case 'm':
|
||||
asme = 1;
|
||||
asthem = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
(void)fprintf(stderr,
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
"Usage: %s [%s] [login[:group] [shell arguments]]\n",
|
||||
#else
|
||||
"Usage: %s [%s] [login [shell arguments]]\n",
|
||||
#endif
|
||||
getprogname(), ARGSTR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
argv += optind;
|
||||
|
||||
/* Lower the priority so su runs faster */
|
||||
errno = 0;
|
||||
prio = getpriority(PRIO_PROCESS, 0);
|
||||
if (errno)
|
||||
prio = 0;
|
||||
if (prio > -2)
|
||||
(void)setpriority(PRIO_PROCESS, 0, -2);
|
||||
openlog("su", 0, LOG_AUTH);
|
||||
|
||||
/* get current login name and shell */
|
||||
ruid = getuid();
|
||||
username = getlogin();
|
||||
if (username == NULL ||
|
||||
getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
|
||||
pwd == NULL || pwd->pw_uid != ruid) {
|
||||
if (getpwuid_r(ruid, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
|
||||
pwd = NULL;
|
||||
}
|
||||
if (pwd == NULL)
|
||||
errx(EXIT_FAILURE, "who are you?");
|
||||
username = estrdup(pwd->pw_name);
|
||||
|
||||
if (asme) {
|
||||
if (pwd->pw_shell && *pwd->pw_shell) {
|
||||
(void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
|
||||
shell = shellbuf;
|
||||
} else {
|
||||
shell = _PATH_BSHELL;
|
||||
iscsh = NO;
|
||||
}
|
||||
}
|
||||
/* get target login information, default to root */
|
||||
user = *argv ? *argv : "root";
|
||||
np = *argv ? argv : argv - 1;
|
||||
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
if ((p = strchr(user, ':')) != NULL) {
|
||||
*p = '\0';
|
||||
gname = ++p;
|
||||
}
|
||||
else
|
||||
gname = NULL;
|
||||
|
||||
#ifdef ALLOW_EMPTY_USER
|
||||
if (user[0] == '\0')
|
||||
user = username;
|
||||
#endif
|
||||
#endif
|
||||
if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
|
||||
pwd == NULL)
|
||||
errx(EXIT_FAILURE, "unknown login %s", user);
|
||||
|
||||
/*
|
||||
* PAM initialization
|
||||
*/
|
||||
#define PAM_END(msg) do { func = msg; goto done;} /* NOTREACHED */ while (/*CONSTCOND*/0)
|
||||
|
||||
if ((pam_err = pam_start("su", user, &pamc, &pamh)) != PAM_SUCCESS) {
|
||||
if (pamh != NULL)
|
||||
PAM_END("pam_start");
|
||||
/* Things went really bad... */
|
||||
syslog(LOG_ERR, "pam_start failed: %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
errx(EXIT_FAILURE, "pam_start failed");
|
||||
}
|
||||
|
||||
#define PAM_END_ITEM(item) PAM_END("pam_set_item(" # item ")")
|
||||
#define PAM_SET_ITEM(item, var) \
|
||||
if ((pam_err = pam_set_item(pamh, (item), (var))) != PAM_SUCCESS) \
|
||||
PAM_END_ITEM(item)
|
||||
|
||||
/*
|
||||
* Fill hostname, username and tty
|
||||
*/
|
||||
PAM_SET_ITEM(PAM_RUSER, username);
|
||||
if (gethostname(hostname, sizeof(hostname)) != -1)
|
||||
PAM_SET_ITEM(PAM_RHOST, hostname);
|
||||
|
||||
if ((tty = ttyname(STDERR_FILENO)) != NULL)
|
||||
PAM_SET_ITEM(PAM_TTY, tty);
|
||||
|
||||
/*
|
||||
* Authentication
|
||||
*/
|
||||
if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
|
||||
syslog(LOG_WARNING, "BAD SU %s to %s%s: %s",
|
||||
username, user, ontty(), pam_strerror(pamh, pam_err));
|
||||
(void)pam_end(pamh, pam_err);
|
||||
errx(EXIT_FAILURE, "Sorry: %s", pam_strerror(pamh, pam_err));
|
||||
}
|
||||
|
||||
/*
|
||||
* Authorization
|
||||
*/
|
||||
switch(pam_err = pam_acct_mgmt(pamh, 0)) {
|
||||
case PAM_NEW_AUTHTOK_REQD:
|
||||
pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
PAM_END("pam_chauthok");
|
||||
break;
|
||||
case PAM_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
PAM_END("pam_acct_mgmt");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* pam_authenticate might have changed the target user.
|
||||
* refresh pwd and user
|
||||
*/
|
||||
pam_err = pam_get_item(pamh, PAM_USER, &newuser);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
syslog(LOG_WARNING,
|
||||
"pam_get_item(PAM_USER): %s", pam_strerror(pamh, pam_err));
|
||||
} else {
|
||||
user = (char *)__UNCONST(newuser);
|
||||
if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
|
||||
pwd == NULL) {
|
||||
(void)pam_end(pamh, pam_err);
|
||||
syslog(LOG_ERR, "unknown login: %s", username);
|
||||
errx(EXIT_FAILURE, "unknown login: %s", username);
|
||||
}
|
||||
}
|
||||
|
||||
#define ERRX_PAM_END(args) do { \
|
||||
(void)pam_end(pamh, pam_err); \
|
||||
errx args; \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
#define ERR_PAM_END(args) do { \
|
||||
(void)pam_end(pamh, pam_err); \
|
||||
err args; \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
/* force the usage of specified class */
|
||||
if (class) {
|
||||
if (ruid)
|
||||
ERRX_PAM_END((EXIT_FAILURE, "Only root may use -c"));
|
||||
|
||||
pwd->pw_class = class;
|
||||
}
|
||||
|
||||
if ((lc = login_getclass(pwd->pw_class)) == NULL)
|
||||
ERRX_PAM_END((EXIT_FAILURE,
|
||||
"Unknown class %s\n", pwd->pw_class));
|
||||
|
||||
if (asme) {
|
||||
/* if asme and non-standard target shell, must be root */
|
||||
if (chshell(pwd->pw_shell) == 0 && ruid)
|
||||
ERRX_PAM_END((EXIT_FAILURE,
|
||||
"permission denied (shell)."));
|
||||
} else if (pwd->pw_shell && *pwd->pw_shell) {
|
||||
shell = pwd->pw_shell;
|
||||
iscsh = UNSET;
|
||||
} else {
|
||||
shell = _PATH_BSHELL;
|
||||
iscsh = NO;
|
||||
}
|
||||
|
||||
if ((p = strrchr(shell, '/')) != NULL)
|
||||
avshell = p + 1;
|
||||
else
|
||||
avshell = shell;
|
||||
|
||||
/* if we're forking a csh, we want to slightly muck the args */
|
||||
if (iscsh == UNSET)
|
||||
iscsh = strstr(avshell, "csh") ? YES : NO;
|
||||
|
||||
/*
|
||||
* Initialize the supplemental groups before pam gets to them,
|
||||
* so that other pam modules get a chance to add more when
|
||||
* we do setcred. Note, we don't relinguish our set-userid yet
|
||||
*/
|
||||
/* if we aren't changing users, keep the current group members */
|
||||
if (ruid != pwd->pw_uid &&
|
||||
setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
|
||||
ERR_PAM_END((EXIT_FAILURE, "setting user context"));
|
||||
|
||||
#ifdef ALLOW_GROUP_CHANGE
|
||||
addgroup(lc, gname, pwd, ruid, "Group Password:");
|
||||
#endif
|
||||
if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
|
||||
PAM_END("pam_setcred");
|
||||
|
||||
/*
|
||||
* Manage session.
|
||||
*/
|
||||
if (asthem) {
|
||||
pid_t pid, xpid;
|
||||
int status = 1;
|
||||
struct sigaction sa, sa_int, sa_pipe, sa_quit;
|
||||
int fds[2];
|
||||
|
||||
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
|
||||
PAM_END("pam_open_session");
|
||||
|
||||
/*
|
||||
* In order to call pam_close_session after the
|
||||
* command terminates, we need to fork.
|
||||
*/
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
(void)sigemptyset(&sa.sa_mask);
|
||||
(void)sigaction(SIGINT, &sa, &sa_int);
|
||||
(void)sigaction(SIGQUIT, &sa, &sa_quit);
|
||||
(void)sigaction(SIGPIPE, &sa, &sa_pipe);
|
||||
sa.sa_handler = SIG_DFL;
|
||||
(void)sigaction(SIGTSTP, &sa, NULL);
|
||||
/*
|
||||
* Use a pipe to guarantee the order of execution of
|
||||
* the parent and the child.
|
||||
*/
|
||||
if (pipe(fds) == -1) {
|
||||
warn("pipe failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
logit("fork failed (%s)", strerror(errno));
|
||||
goto out;
|
||||
|
||||
case 0: /* Child */
|
||||
(void)close(fds[1]);
|
||||
(void)read(fds[0], &status, 1);
|
||||
(void)close(fds[0]);
|
||||
(void)sigaction(SIGINT, &sa_int, NULL);
|
||||
(void)sigaction(SIGQUIT, &sa_quit, NULL);
|
||||
(void)sigaction(SIGPIPE, &sa_pipe, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
sa.sa_handler = SIG_IGN;
|
||||
(void)sigaction(SIGTTOU, &sa, NULL);
|
||||
(void)close(fds[0]);
|
||||
(void)setpgid(pid, pid);
|
||||
(void)tcsetpgrp(STDERR_FILENO, pid);
|
||||
(void)close(fds[1]);
|
||||
(void)sigaction(SIGPIPE, &sa_pipe, NULL);
|
||||
/*
|
||||
* Parent: wait for the child to terminate
|
||||
* and call pam_close_session.
|
||||
*/
|
||||
while ((xpid = waitpid(pid, &status, WUNTRACED))
|
||||
== pid) {
|
||||
if (WIFSTOPPED(status)) {
|
||||
(void)kill(getpid(), SIGSTOP);
|
||||
(void)tcsetpgrp(STDERR_FILENO,
|
||||
getpgid(pid));
|
||||
(void)kill(pid, SIGCONT);
|
||||
status = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
(void)tcsetpgrp(STDERR_FILENO, getpgid(0));
|
||||
|
||||
if (xpid == -1) {
|
||||
logit("Error waiting for pid %d (%s)", pid,
|
||||
strerror(errno));
|
||||
} else if (xpid != pid) {
|
||||
/* Can't happen. */
|
||||
logit("Wrong PID: %d != %d", pid, xpid);
|
||||
}
|
||||
out:
|
||||
pam_err = pam_setcred(pamh, PAM_DELETE_CRED);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
logit("pam_setcred: %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
pam_err = pam_close_session(pamh, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
logit("pam_close_session: %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
(void)pam_end(pamh, pam_err);
|
||||
exit(WEXITSTATUS(status));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The child: starting here, we don't have to care about
|
||||
* handling PAM issues if we exit, the parent will do the
|
||||
* job when we exit.
|
||||
*/
|
||||
#undef PAM_END
|
||||
#undef ERR_PAM_END
|
||||
#undef ERRX_PAM_END
|
||||
|
||||
if (!asme) {
|
||||
if (asthem) {
|
||||
char **pamenv;
|
||||
|
||||
p = getenv("TERM");
|
||||
/*
|
||||
* Create an empty environment
|
||||
*/
|
||||
environ = emalloc(sizeof(char *));
|
||||
environ[0] = NULL;
|
||||
|
||||
/*
|
||||
* Add PAM environement, before the LOGIN_CAP stuff:
|
||||
* if the login class is unspecified, we'll get the
|
||||
* same data from PAM, if -c was used, the specified
|
||||
* class must override PAM.
|
||||
*/
|
||||
if ((pamenv = pam_getenvlist(pamh)) != NULL) {
|
||||
char **envitem;
|
||||
|
||||
/*
|
||||
* XXX Here FreeBSD filters out
|
||||
* SHELL, LOGNAME, MAIL, CDPATH, IFS, PATH
|
||||
* how could we get untrusted data here?
|
||||
*/
|
||||
for (envitem = pamenv; *envitem; envitem++) {
|
||||
if (putenv(*envitem) == -1)
|
||||
free(*envitem);
|
||||
}
|
||||
|
||||
free(pamenv);
|
||||
}
|
||||
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH |
|
||||
LOGIN_SETENV | LOGIN_SETUMASK) == -1)
|
||||
err(EXIT_FAILURE, "setting user context");
|
||||
if (p)
|
||||
(void)setenv("TERM", p, 1);
|
||||
if (gohome && chdir(pwd->pw_dir) == -1)
|
||||
errx(EXIT_FAILURE, "no directory");
|
||||
}
|
||||
|
||||
if (asthem || pwd->pw_uid) {
|
||||
(void)setenv("LOGNAME", pwd->pw_name, 1);
|
||||
(void)setenv("USER", pwd->pw_name, 1);
|
||||
}
|
||||
(void)setenv("HOME", pwd->pw_dir, 1);
|
||||
(void)setenv("SHELL", shell, 1);
|
||||
}
|
||||
(void)setenv("SU_FROM", username, 1);
|
||||
|
||||
if (iscsh == YES) {
|
||||
if (fastlogin)
|
||||
*np-- = __UNCONST("-f");
|
||||
if (asme)
|
||||
*np-- = __UNCONST("-m");
|
||||
} else {
|
||||
if (fastlogin)
|
||||
(void)unsetenv("ENV");
|
||||
}
|
||||
|
||||
if (asthem) {
|
||||
avshellbuf[0] = '-';
|
||||
(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
|
||||
avshell = avshellbuf;
|
||||
} else if (iscsh == YES) {
|
||||
/* csh strips the first character... */
|
||||
avshellbuf[0] = '_';
|
||||
(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
|
||||
avshell = avshellbuf;
|
||||
}
|
||||
*np = __UNCONST(avshell);
|
||||
|
||||
if (ruid != 0)
|
||||
syslog(LOG_NOTICE, "%s to %s%s",
|
||||
username, pwd->pw_name, ontty());
|
||||
|
||||
/* Raise our priority back to what we had before */
|
||||
(void)setpriority(PRIO_PROCESS, 0, prio);
|
||||
|
||||
/*
|
||||
* Set user context, except for umask, and the stuff
|
||||
* we have done before.
|
||||
*/
|
||||
setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
|
||||
LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
|
||||
setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
|
||||
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) == -1)
|
||||
err(EXIT_FAILURE, "setusercontext");
|
||||
|
||||
(void)execv(shell, np);
|
||||
err(EXIT_FAILURE, "%s", shell);
|
||||
done:
|
||||
logit("%s: %s", func, pam_strerror(pamh, pam_err));
|
||||
(void)pam_end(pamh, pam_err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static void
|
||||
logit(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
vsyslog(LOG_ERR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
63
usr.bin/su/suutil.c
Normal file
63
usr.bin/su/suutil.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* $NetBSD: suutil.c,v 1.1 2007/10/17 21:05:39 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: suutil.c,v 1.1 2007/10/17 21:05:39 christos Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "suutil.h"
|
||||
|
||||
int
|
||||
chshell(const char *sh)
|
||||
{
|
||||
const char *cp;
|
||||
|
||||
setusershell();
|
||||
while ((cp = getusershell()) != NULL)
|
||||
if (strcmp(cp, sh) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
ontty(void)
|
||||
{
|
||||
char *p;
|
||||
static char buf[MAXPATHLEN + 4];
|
||||
|
||||
buf[0] = 0;
|
||||
if ((p = ttyname(STDERR_FILENO)) != NULL)
|
||||
(void)snprintf(buf, sizeof buf, " on %s", p);
|
||||
return buf;
|
||||
}
|
||||
|
35
usr.bin/su/suutil.h
Normal file
35
usr.bin/su/suutil.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* $NetBSD: suutil.h,v 1.1 2007/10/17 21:05:40 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
__BEGIN_DECLS
|
||||
int chshell(const char *);
|
||||
char *ontty(void);
|
||||
__END_DECLS
|
Loading…
Reference in a new issue