X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/96f93d9e63db6fc5de5d6fabecb591c72942b38d..966c6ec04a47e5b2a417ce244be03869cdc6b71b:/usr/src/usr.bin/su/su.c diff --git a/usr/src/usr.bin/su/su.c b/usr/src/usr.bin/su/su.c index 6bb382b6f9..89e8a1d23f 100644 --- a/usr/src/usr.bin/su/su.c +++ b/usr/src/usr.bin/su/su.c @@ -1,177 +1,204 @@ +/* + * 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 4.9 (Berkeley) %G%"; -#endif +static char sccsid[] = "@(#)su.c 5.10 (Berkeley) %G%"; +#endif /* not lint */ +#include +#include +#include +#include #include #include #include -#include -#include -#include -char userbuf[16] = "USER="; -char homebuf[128] = "HOME="; -char shellbuf[128] = "SHELL="; -char pathbuf[128] = "PATH=:/usr/ucb:/bin:/usr/bin"; -char *cleanenv[] = { userbuf, homebuf, shellbuf, pathbuf, 0, 0 }; -char *user = "root"; -char *shell = "/bin/sh"; -int fulllogin; -int fastlogin; - -extern char **environ; -struct passwd *pwd; -char *crypt(); -char *getpass(); -char *getenv(); - -main(argc,argv) +main(argc, argv) int argc; - char *argv[]; + char **argv; { - char *password; - char buf[1000]; - FILE *fp; - -again: - if (argc > 1 && strcmp(argv[1], "-f") == 0) { - fastlogin++; - argc--, argv++; - goto again; - } - if (argc > 1 && strcmp(argv[1], "-") == 0) { - fulllogin++; - argc--, argv++; - goto again; - } - if (argc > 1 && argv[1][0] != '-') { - user = argv[1]; - argc--, argv++; - } - if ((pwd = getpwuid(getuid())) == NULL) { - fprintf(stderr, "Who are you?\n"); + 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); } - strcpy(buf, pwd->pw_name); + username = strcpy(namebuf, pwd->pw_name); + if (asme) + if (pwd->pw_shell && *pwd->pw_shell) + shell = strcpy(shellbuf, pwd->pw_shell); + else { + shell = "/bin/sh"; + iscsh = NO; + } + + /* get target login information */ + user = *argv ? *argv : "root"; if ((pwd = getpwnam(user)) == NULL) { - fprintf(stderr, "Unknown login: %s\n", user); + 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) { - struct group *gr; - int i; - - if ((gr = getgrgid(0)) != NULL) { - for (i = 0; gr->gr_mem[i] != NULL; i++) - if (strcmp(buf, gr->gr_mem[i]) == 0) - goto userok; - fprintf(stderr, "You do not have permission to su %s\n", - user); - exit(1); - } - userok: - setpriority(PRIO_PROCESS, 0, -2); - } - if (pwd->pw_passwd[0] == '\0' || getuid() == 0) - goto ok; - password = getpass("Password:"); - if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) { - fprintf(stderr, "Sorry\n"); - if (pwd->pw_uid == 0) { - FILE *console = fopen("/dev/console", "w"); - if (console != NULL) { - fprintf(console, "BADSU: %s %s\r\n", - getlogin(), ttyname(2)); - fclose(console); + /* 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); } - exit(2); } -ok: - endpwent(); - if (pwd->pw_uid == 0) { - FILE *console = fopen("/dev/console", "w"); - if (console != NULL) { - fprintf(console, "SU: %s %s\r\n", - getlogin(), ttyname(2)); - fclose(console); + + /* if not asme or target's shell isn't standard, use it */ + if (!asme || !chshell(pwd->pw_shell)) + if (pwd->pw_shell && *pwd->pw_shell) { + shell = pwd->pw_shell; + iscsh = UNSET; + } else { + shell = "/bin/sh"; + 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(3); + exit(1); } if (initgroups(user, pwd->pw_gid)) { fprintf(stderr, "su: initgroups failed\n"); - exit(4); + exit(1); } if (setuid(pwd->pw_uid) < 0) { perror("su: setuid"); - exit(5); - } - if (pwd->pw_shell && *pwd->pw_shell) - shell = pwd->pw_shell; - if (fulllogin) { - cleanenv[4] = getenv("TERM"); - environ = cleanenv; + exit(1); } - if (strcmp(user, "root")) - setenv("USER", pwd->pw_name, userbuf); - setenv("SHELL", shell, shellbuf); - setenv("HOME", pwd->pw_dir, homebuf); - setpriority(PRIO_PROCESS, 0, 0); - if (fastlogin) { - *argv-- = "-f"; - *argv = "su"; - } else if (fulllogin) { - if (chdir(pwd->pw_dir) < 0) { - fprintf(stderr, "No directory\n"); - exit(6); - } - *argv = "-su"; - } else - *argv = "su"; - execv(shell, argv); - fprintf(stderr, "No shell\n"); - exit(7); -} -setenv(ename, eval, buf) - char *ename, *eval, *buf; -{ - register char *cp, *dp; - register char **ep = environ; - - /* - * this assumes an environment variable "ename" already exists - */ - while (dp = *ep++) { - for (cp = ename; *cp == *dp && *cp; cp++, dp++) - continue; - if (*cp == 0 && (*dp == '=' || *dp == 0)) { - strcat(buf, eval); - *--ep = buf; - return; + if (!asme) { + if (fulllogin) { + p = getenv("TERM"); + cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin"; + 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); } -char * -getenv(ename) - char *ename; +chshell(sh) + char *sh; { - register char *cp, *dp; - register char **ep = environ; - - while (dp = *ep++) { - for (cp = ename; *cp == *dp && *cp; cp++, dp++) - continue; - if (*cp == 0 && (*dp == '=' || *dp == 0)) - return (*--ep); - } - return ((char *)0); + char *cp, *getusershell(); + + while ((cp = getusershell()) != NULL) + if (!strcmp(cp, sh)) + return(1); + return(0); }