119908Sdist /* 235489Sbostic * Copyright (c) 1988 The Regents of the University of California. 335489Sbostic * All rights reserved. 435489Sbostic * 535489Sbostic * Redistribution and use in source and binary forms are permitted 635489Sbostic * provided that the above copyright notice and this paragraph are 735489Sbostic * duplicated in all such forms and that any documentation, 835489Sbostic * advertising materials, and other materials related to such 935489Sbostic * distribution and use acknowledge that the software was developed 1035489Sbostic * by the University of California, Berkeley. The name of the 1135489Sbostic * University may not be used to endorse or promote products derived 1235489Sbostic * from this software without specific prior written permission. 1335489Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435489Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535489Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1619908Sdist */ 1719908Sdist 1810045Ssam #ifndef lint 1919908Sdist char copyright[] = 2035489Sbostic "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 2119908Sdist All rights reserved.\n"; 2235489Sbostic #endif /* not lint */ 2310045Ssam 2419908Sdist #ifndef lint 25*36305Sbostic static char sccsid[] = "@(#)su.c 5.11 (Berkeley) 12/07/88"; 2635489Sbostic #endif /* not lint */ 2719908Sdist 2835716Sbostic #include <sys/param.h> 2935489Sbostic #include <sys/time.h> 3035489Sbostic #include <sys/resource.h> 3135489Sbostic #include <syslog.h> 321109Sbill #include <stdio.h> 331109Sbill #include <pwd.h> 3415914Sralph #include <grp.h> 351109Sbill 3635489Sbostic main(argc, argv) 3710045Ssam int argc; 3835489Sbostic char **argv; 391109Sbill { 4035489Sbostic extern char **environ; 4135489Sbostic extern int errno, optind; 4235489Sbostic register struct passwd *pwd; 4335489Sbostic register char *p, **g; 4435489Sbostic struct group *gr; 4535716Sbostic uid_t ruid, getuid(); 4635721Sbostic int asme, ch, fulllogin, fastlogin, prio; 4735716Sbostic enum { UNSET, YES, NO } iscsh = UNSET; 4835721Sbostic char *user, *shell, *username, *cleanenv[2], *nargv[4], **np; 4935716Sbostic char namebuf[50], shellbuf[MAXPATHLEN]; 5035716Sbostic char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy(); 511109Sbill 5235721Sbostic np = &nargv[3]; 5335721Sbostic *np-- = NULL; 5435721Sbostic asme = fulllogin = fastlogin = 0; 5535721Sbostic while ((ch = getopt(argc, argv, "-flm")) != EOF) 5635489Sbostic switch((char)ch) { 5735716Sbostic case 'f': 5835716Sbostic fastlogin = 1; 5935716Sbostic break; 6035489Sbostic case '-': 6135489Sbostic case 'l': 6235489Sbostic fulllogin = 1; 6335489Sbostic break; 6435721Sbostic case 'm': 6535721Sbostic asme = 1; 6635721Sbostic break; 6735489Sbostic case '?': 6835489Sbostic default: 6935815Sbostic fprintf(stderr, "usage: su [-flm] [login]\n"); 7035489Sbostic exit(1); 7135489Sbostic } 7235489Sbostic argv += optind; 7335489Sbostic 7435721Sbostic errno = 0; 7535721Sbostic prio = getpriority(PRIO_PROCESS, 0); 7635721Sbostic if (errno) 7735721Sbostic prio = 0; 7835721Sbostic (void)setpriority(PRIO_PROCESS, 0, -2); 7935721Sbostic 8035721Sbostic /* get current login name and shell */ 8135716Sbostic if ((pwd = getpwuid(ruid = getuid())) == NULL) { 8235489Sbostic fprintf(stderr, "su: who are you?\n"); 8316216Sralph exit(1); 8416216Sralph } 8535716Sbostic username = strcpy(namebuf, pwd->pw_name); 8635721Sbostic if (asme) 8735716Sbostic if (pwd->pw_shell && *pwd->pw_shell) 8835716Sbostic shell = strcpy(shellbuf, pwd->pw_shell); 8935716Sbostic else { 9035716Sbostic shell = "/bin/sh"; 9135716Sbostic iscsh = NO; 9235716Sbostic } 9335489Sbostic 9435721Sbostic /* get target login information */ 9535721Sbostic user = *argv ? *argv : "root"; 9616216Sralph if ((pwd = getpwnam(user)) == NULL) { 9735489Sbostic fprintf(stderr, "su: unknown login %s\n", user); 9816216Sralph exit(1); 9916216Sralph } 10015914Sralph 10135489Sbostic /* only allow those in group zero to su to root. */ 10235716Sbostic if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) 10335489Sbostic for (g = gr->gr_mem;; ++g) { 10435489Sbostic if (!*g) { 10535489Sbostic fprintf(stderr, "su: you are not in the correct group to su %s.\n", user); 10635489Sbostic exit(1); 10735489Sbostic } 10835489Sbostic if (!strcmp(username, *g)) 10935489Sbostic break; 11015897Sralph } 11115897Sralph 11235721Sbostic /* if target requires a password, verify it */ 11335721Sbostic if (ruid && *pwd->pw_passwd) { 11435489Sbostic p = getpass("Password:"); 11535489Sbostic if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { 11635489Sbostic fprintf(stderr, "Sorry\n"); 11735489Sbostic if (pwd->pw_uid == 0) 11835721Sbostic syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2)); 11935489Sbostic exit(1); 1201109Sbill } 1211109Sbill } 12235716Sbostic 123*36305Sbostic if (asme) { 124*36305Sbostic /* if asme and non-standard target shell, must be root */ 125*36305Sbostic if (!chshell(pwd->pw_shell) && ruid) { 126*36305Sbostic fprintf(stderr, "su: Permission denied.\n"); 127*36305Sbostic exit(1); 12835716Sbostic } 129*36305Sbostic } 130*36305Sbostic else if (pwd->pw_shell && *pwd->pw_shell) { 131*36305Sbostic shell = pwd->pw_shell; 132*36305Sbostic iscsh = UNSET; 133*36305Sbostic } else { 134*36305Sbostic shell = "/bin/sh"; 135*36305Sbostic iscsh = NO; 136*36305Sbostic } 13735716Sbostic 13835721Sbostic /* if we're forking a csh, we want to slightly muck the args */ 13935716Sbostic if (iscsh == UNSET) { 14035716Sbostic if (p = rindex(shell, '/')) 14135716Sbostic ++p; 14235716Sbostic else 14335716Sbostic p = shell; 14435716Sbostic iscsh = strcmp(p, "csh") ? NO : YES; 14535716Sbostic } 14635716Sbostic 14735721Sbostic /* set permissions */ 14810045Ssam if (setgid(pwd->pw_gid) < 0) { 14910045Ssam perror("su: setgid"); 15035489Sbostic exit(1); 15110045Ssam } 15212696Ssam if (initgroups(user, pwd->pw_gid)) { 15310045Ssam fprintf(stderr, "su: initgroups failed\n"); 15435489Sbostic exit(1); 15510045Ssam } 15610045Ssam if (setuid(pwd->pw_uid) < 0) { 15710045Ssam perror("su: setuid"); 15835489Sbostic exit(1); 15910045Ssam } 16035721Sbostic 16135721Sbostic if (!asme) { 16235721Sbostic if (fulllogin) { 16335721Sbostic p = getenv("TERM"); 16435721Sbostic cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin"; 16535721Sbostic cleanenv[1] = NULL; 16635721Sbostic environ = cleanenv; 16735721Sbostic (void)setenv("TERM", p, 1); 16835721Sbostic if (chdir(pwd->pw_dir) < 0) { 16935721Sbostic fprintf(stderr, "su: no directory\n"); 17035721Sbostic exit(1); 17135721Sbostic } 17235721Sbostic } 17335721Sbostic if (fulllogin || pwd->pw_uid) 17435721Sbostic (void)setenv("USER", pwd->pw_name, 1); 17535716Sbostic (void)setenv("HOME", pwd->pw_dir, 1); 17635716Sbostic (void)setenv("SHELL", shell, 1); 17735489Sbostic } 1781109Sbill 17935721Sbostic if (iscsh == YES) { 18035721Sbostic if (fastlogin) 18135721Sbostic *np-- = "-f"; 18235721Sbostic if (asme) 18335721Sbostic *np-- = "-m"; 18435721Sbostic } 1851109Sbill 18635716Sbostic /* csh strips the first character... */ 18735721Sbostic *np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su"; 18835716Sbostic 18935489Sbostic if (pwd->pw_uid == 0) 19035716Sbostic syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s", 19135716Sbostic username, ttyname(2)); 1921109Sbill 19335489Sbostic (void)setpriority(PRIO_PROCESS, 0, prio); 1941109Sbill 19535721Sbostic execv(shell, np); 19635716Sbostic fprintf(stderr, "su: no shell.\n"); 19735489Sbostic exit(1); 1981109Sbill } 19935722Sbostic 20035722Sbostic chshell(sh) 20135722Sbostic char *sh; 20235722Sbostic { 20335722Sbostic char *cp, *getusershell(); 20435722Sbostic 20535722Sbostic while ((cp = getusershell()) != NULL) 20635722Sbostic if (!strcmp(cp, sh)) 20735722Sbostic return(1); 20835722Sbostic return(0); 20935722Sbostic } 210