file reorg, pathnames.h, paths.h
[unix-history] / usr / src / usr.bin / su / su.c
/*
* Copyright (c) 1988 The Regents of the University of California.
* All rights reserved.
*
* 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.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)su.c 5.12 (Berkeley) %G%";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <syslog.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include "pathnames.h"
main(argc, argv)
int argc;
char **argv;
{
extern char **environ;
extern int errno, optind;
register struct passwd *pwd;
register char *p, **g;
struct group *gr;
uid_t ruid, getuid();
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();
np = &nargv[3];
*np-- = NULL;
asme = fulllogin = fastlogin = 0;
while ((ch = getopt(argc, argv, "-flm")) != EOF)
switch((char)ch) {
case 'f':
fastlogin = 1;
break;
case '-':
case 'l':
fulllogin = 1;
break;
case 'm':
asme = 1;
break;
case '?':
default:
fprintf(stderr, "usage: su [-flm] [login]\n");
exit(1);
}
argv += optind;
errno = 0;
prio = getpriority(PRIO_PROCESS, 0);
if (errno)
prio = 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");
exit(1);
}
username = strcpy(namebuf, pwd->pw_name);
if (asme)
if (pwd->pw_shell && *pwd->pw_shell)
shell = strcpy(shellbuf, pwd->pw_shell);
else {
shell = _PATH_BSHELL;
iscsh = NO;
}
/* get target login information */
user = *argv ? *argv : "root";
if ((pwd = getpwnam(user)) == NULL) {
fprintf(stderr, "su: unknown login %s\n", user);
exit(1);
}
/* 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) {
if (!*g) {
fprintf(stderr, "su: you are not in the correct group to su %s.\n", user);
exit(1);
}
if (!strcmp(username, *g))
break;
}
/* 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");
if (pwd->pw_uid == 0)
syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2));
exit(1);
}
}
if (asme) {
/* if asme and non-standard target shell, must be root */
if (!chshell(pwd->pw_shell) && ruid) {
fprintf(stderr, "su: Permission denied.\n");
exit(1);
}
}
else if (pwd->pw_shell && *pwd->pw_shell) {
shell = pwd->pw_shell;
iscsh = UNSET;
} else {
shell = _PATH_BSHELL;
iscsh = NO;
}
/* if we're forking a csh, we want to slightly muck the args */
if (iscsh == UNSET) {
if (p = rindex(shell, '/'))
++p;
else
p = shell;
iscsh = strcmp(p, "csh") ? NO : YES;
}
/* set permissions */
if (setgid(pwd->pw_gid) < 0) {
perror("su: setgid");
exit(1);
}
if (initgroups(user, pwd->pw_gid)) {
fprintf(stderr, "su: initgroups failed\n");
exit(1);
}
if (setuid(pwd->pw_uid) < 0) {
perror("su: setuid");
exit(1);
}
if (!asme) {
if (fulllogin) {
p = getenv("TERM");
cleanenv[0] = _PATH_SEARCHPATH;
cleanenv[1] = NULL;
environ = cleanenv;
(void)setenv("TERM", p, 1);
if (chdir(pwd->pw_dir) < 0) {
fprintf(stderr, "su: no directory\n");
exit(1);
}
}
if (fulllogin || pwd->pw_uid)
(void)setenv("USER", pwd->pw_name, 1);
(void)setenv("HOME", pwd->pw_dir, 1);
(void)setenv("SHELL", shell, 1);
}
if (iscsh == YES) {
if (fastlogin)
*np-- = "-f";
if (asme)
*np-- = "-m";
}
/* csh strips the first character... */
*np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su";
if (pwd->pw_uid == 0)
syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s",
username, ttyname(2));
(void)setpriority(PRIO_PROCESS, 0, prio);
execv(shell, np);
fprintf(stderr, "su: no shell.\n");
exit(1);
}
chshell(sh)
char *sh;
{
char *cp, *getusershell();
while ((cp = getusershell()) != NULL)
if (!strcmp(cp, sh))
return(1);
return(0);
}