Flush out the last dregs in the terminal before quitting when
[unix-history] / usr / src / usr.bin / su / su.c
CommitLineData
31e00b32 1/*
7d5e1706
KB
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31e00b32
DF
16 */
17
18#ifndef lint
19char copyright[] =
7d5e1706 20"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
31e00b32 21 All rights reserved.\n";
7d5e1706 22#endif /* not lint */
31e00b32 23
13dd8b1d 24#ifndef lint
3130bef4 25static char sccsid[] = "@(#)su.c 5.10 (Berkeley) %G%";
7d5e1706 26#endif /* not lint */
13dd8b1d 27
a8d8c335 28#include <sys/param.h>
4f4c2c68
SL
29#include <sys/time.h>
30#include <sys/resource.h>
7d5e1706
KB
31#include <syslog.h>
32#include <stdio.h>
33#include <pwd.h>
34#include <grp.h>
3a265c7a 35
7d5e1706 36main(argc, argv)
13dd8b1d 37 int argc;
7d5e1706 38 char **argv;
3a265c7a 39{
7d5e1706
KB
40 extern char **environ;
41 extern int errno, optind;
7d5e1706
KB
42 register struct passwd *pwd;
43 register char *p, **g;
44 struct group *gr;
a8d8c335 45 uid_t ruid, getuid();
6964f298 46 int asme, ch, fulllogin, fastlogin, prio;
a8d8c335 47 enum { UNSET, YES, NO } iscsh = UNSET;
6964f298 48 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
a8d8c335
KB
49 char namebuf[50], shellbuf[MAXPATHLEN];
50 char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
3a265c7a 51
6964f298
KB
52 np = &nargv[3];
53 *np-- = NULL;
54 asme = fulllogin = fastlogin = 0;
55 while ((ch = getopt(argc, argv, "-flm")) != EOF)
7d5e1706 56 switch((char)ch) {
a8d8c335
KB
57 case 'f':
58 fastlogin = 1;
59 break;
7d5e1706
KB
60 case '-':
61 case 'l':
62 fulllogin = 1;
63 break;
6964f298
KB
64 case 'm':
65 asme = 1;
66 break;
7d5e1706
KB
67 case '?':
68 default:
3130bef4 69 fprintf(stderr, "usage: su [-flm] [login]\n");
7d5e1706
KB
70 exit(1);
71 }
72 argv += optind;
da31c6da 73
6964f298
KB
74 errno = 0;
75 prio = getpriority(PRIO_PROCESS, 0);
76 if (errno)
77 prio = 0;
78 (void)setpriority(PRIO_PROCESS, 0, -2);
79
80 /* get current login name and shell */
a8d8c335 81 if ((pwd = getpwuid(ruid = getuid())) == NULL) {
7d5e1706 82 fprintf(stderr, "su: who are you?\n");
96f93d9e
RC
83 exit(1);
84 }
a8d8c335 85 username = strcpy(namebuf, pwd->pw_name);
6964f298 86 if (asme)
a8d8c335
KB
87 if (pwd->pw_shell && *pwd->pw_shell)
88 shell = strcpy(shellbuf, pwd->pw_shell);
89 else {
90 shell = "/bin/sh";
91 iscsh = NO;
92 }
7d5e1706 93
6964f298
KB
94 /* get target login information */
95 user = *argv ? *argv : "root";
96f93d9e 96 if ((pwd = getpwnam(user)) == NULL) {
7d5e1706 97 fprintf(stderr, "su: unknown login %s\n", user);
96f93d9e
RC
98 exit(1);
99 }
7d5e1706
KB
100
101 /* only allow those in group zero to su to root. */
a8d8c335 102 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
7d5e1706
KB
103 for (g = gr->gr_mem;; ++g) {
104 if (!*g) {
105 fprintf(stderr, "su: you are not in the correct group to su %s.\n", user);
106 exit(1);
107 }
108 if (!strcmp(username, *g))
109 break;
a8a168db 110 }
a8a168db 111
6964f298
KB
112 /* if target requires a password, verify it */
113 if (ruid && *pwd->pw_passwd) {
7d5e1706
KB
114 p = getpass("Password:");
115 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
116 fprintf(stderr, "Sorry\n");
117 if (pwd->pw_uid == 0)
6964f298 118 syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2));
7d5e1706 119 exit(1);
3a265c7a 120 }
3a265c7a 121 }
a8d8c335 122
7b34c4f8
KB
123 /* if not asme or target's shell isn't standard, use it */
124 if (!asme || !chshell(pwd->pw_shell))
a8d8c335
KB
125 if (pwd->pw_shell && *pwd->pw_shell) {
126 shell = pwd->pw_shell;
127 iscsh = UNSET;
128 } else {
129 shell = "/bin/sh";
130 iscsh = NO;
131 }
132
6964f298 133 /* if we're forking a csh, we want to slightly muck the args */
a8d8c335
KB
134 if (iscsh == UNSET) {
135 if (p = rindex(shell, '/'))
136 ++p;
137 else
138 p = shell;
139 iscsh = strcmp(p, "csh") ? NO : YES;
140 }
141
6964f298 142 /* set permissions */
13dd8b1d
SL
143 if (setgid(pwd->pw_gid) < 0) {
144 perror("su: setgid");
7d5e1706 145 exit(1);
13dd8b1d 146 }
4f4c2c68 147 if (initgroups(user, pwd->pw_gid)) {
13dd8b1d 148 fprintf(stderr, "su: initgroups failed\n");
7d5e1706 149 exit(1);
13dd8b1d
SL
150 }
151 if (setuid(pwd->pw_uid) < 0) {
152 perror("su: setuid");
7d5e1706 153 exit(1);
13dd8b1d 154 }
6964f298
KB
155
156 if (!asme) {
157 if (fulllogin) {
158 p = getenv("TERM");
159 cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
160 cleanenv[1] = NULL;
161 environ = cleanenv;
162 (void)setenv("TERM", p, 1);
163 if (chdir(pwd->pw_dir) < 0) {
164 fprintf(stderr, "su: no directory\n");
165 exit(1);
166 }
167 }
168 if (fulllogin || pwd->pw_uid)
169 (void)setenv("USER", pwd->pw_name, 1);
a8d8c335
KB
170 (void)setenv("HOME", pwd->pw_dir, 1);
171 (void)setenv("SHELL", shell, 1);
3a265c7a 172 }
3a265c7a 173
6964f298
KB
174 if (iscsh == YES) {
175 if (fastlogin)
176 *np-- = "-f";
177 if (asme)
178 *np-- = "-m";
179 }
a8d8c335
KB
180
181 /* csh strips the first character... */
6964f298 182 *np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su";
7d5e1706
KB
183
184 if (pwd->pw_uid == 0)
a8d8c335
KB
185 syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s",
186 username, ttyname(2));
7d5e1706
KB
187
188 (void)setpriority(PRIO_PROCESS, 0, prio);
189
6964f298 190 execv(shell, np);
a8d8c335 191 fprintf(stderr, "su: no shell.\n");
7d5e1706 192 exit(1);
3a265c7a 193}
7b34c4f8
KB
194
195chshell(sh)
196 char *sh;
197{
198 char *cp, *getusershell();
199
200 while ((cp = getusershell()) != NULL)
201 if (!strcmp(cp, sh))
202 return(1);
203 return(0);
204}