* Copyright (c) 1988 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)su.c 5.12 (Berkeley) %G%";
#include <sys/resource.h>
extern int errno
, optind
;
register struct passwd
*pwd
;
int asme
, ch
, fulllogin
, fastlogin
, prio
;
enum { UNSET
, YES
, NO
} iscsh
= UNSET
;
char *user
, *shell
, *username
, *cleanenv
[2], *nargv
[4], **np
;
char namebuf
[50], shellbuf
[MAXPATHLEN
];
char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
asme
= fulllogin
= fastlogin
= 0;
while ((ch
= getopt(argc
, argv
, "-flm")) != EOF
)
fprintf(stderr
, "usage: su [-flm] [login]\n");
prio
= getpriority(PRIO_PROCESS
, 0);
(void)setpriority(PRIO_PROCESS
, 0, -2);
/* get current login name and shell */
if ((pwd
= getpwuid(ruid
= getuid())) == NULL
) {
fprintf(stderr
, "su: who are you?\n");
username
= strcpy(namebuf
, pwd
->pw_name
);
if (pwd
->pw_shell
&& *pwd
->pw_shell
)
shell
= strcpy(shellbuf
, pwd
->pw_shell
);
/* get target login information */
user
= *argv
? *argv
: "root";
if ((pwd
= getpwnam(user
)) == NULL
) {
fprintf(stderr
, "su: unknown login %s\n", user
);
/* only allow those in group zero to su to root. */
if (pwd
->pw_uid
== 0 && (gr
= getgrgid((gid_t
)0)))
for (g
= gr
->gr_mem
;; ++g
) {
fprintf(stderr
, "su: you are not in the correct group to su %s.\n", user
);
if (!strcmp(username
, *g
))
/* if target requires a password, verify it */
if (ruid
&& *pwd
->pw_passwd
) {
p
= getpass("Password:");
if (strcmp(pwd
->pw_passwd
, crypt(p
, pwd
->pw_passwd
))) {
fprintf(stderr
, "Sorry\n");
syslog(LOG_CRIT
|LOG_AUTH
, "su: BAD SU %s on %s", username
, ttyname(2));
/* if asme and non-standard target shell, must be root */
if (!chshell(pwd
->pw_shell
) && ruid
) {
fprintf(stderr
, "su: Permission denied.\n");
else if (pwd
->pw_shell
&& *pwd
->pw_shell
) {
/* if we're forking a csh, we want to slightly muck the args */
if (p
= rindex(shell
, '/'))
iscsh
= strcmp(p
, "csh") ? NO
: YES
;
if (setgid(pwd
->pw_gid
) < 0) {
if (initgroups(user
, pwd
->pw_gid
)) {
fprintf(stderr
, "su: initgroups failed\n");
if (setuid(pwd
->pw_uid
) < 0) {
cleanenv
[0] = _PATH_SEARCHPATH
;
(void)setenv("TERM", p
, 1);
if (chdir(pwd
->pw_dir
) < 0) {
fprintf(stderr
, "su: no directory\n");
if (fulllogin
|| pwd
->pw_uid
)
(void)setenv("USER", pwd
->pw_name
, 1);
(void)setenv("HOME", pwd
->pw_dir
, 1);
(void)setenv("SHELL", shell
, 1);
/* csh strips the first character... */
*np
= fulllogin
? "-su" : iscsh
== YES
? "_su" : "su";
syslog(LOG_NOTICE
|LOG_AUTH
, "su: %s on %s",
(void)setpriority(PRIO_PROCESS
, 0, prio
);
fprintf(stderr
, "su: no shell.\n");
char *cp
, *getusershell();
while ((cp
= getusershell()) != NULL
)