1 /*
2 * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $
3 * $Author: jtkohl $
4 */
5
6 /*
7 * Copyright (c) 1988 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the University of California, Berkeley. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23 /*
24 * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute
25 * of Technology. For copying and distribution information, please see
26 * the file <mit-copyright.h>.
27 */
28
29 #ifndef lint
30 static char rcsid_ksu_c[] =
31 "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $";
32 #endif lint
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)su.c 5.11 (Berkeley) 12/7/88";
42 #endif /* not lint */
43
44 #include <kerberos/mit-copyright.h>
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <syslog.h>
49 #include <stdio.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <kerberos/krb.h>
53 #include <netdb.h>
54 #include <sys/ioctl.h>
55
56 #ifndef LOG_AUTH
57 #define LOG_AUTH 0
58 #endif /* LOG_AUTH */
59
60 /* for Ultrix and friends ... */
61 #ifndef MAXHOSTNAMELEN
62 #define MAXHOSTNAMELEN 64
63 #endif
64
65 extern char *krb_err_txt[];
66 int kerno;
67 char lrealm[REALM_SZ];
68 char krbtkfile[128];
69
70 #define MAXPWSIZE 128 /* Biggest string we accept for a password
71 (includes space for null terminator) */
72
main(argc,argv)73 main(argc, argv)
74 int argc;
75 char **argv;
76 {
77 extern char **environ;
78 extern int errno, optind;
79 register struct passwd *pwd;
80 register char *p, **g;
81 struct group *gr;
82 uid_t ruid, getuid();
83 #ifdef NO_GETUSERSHELL
84 int ch, fulllogin, fastlogin, prio;
85 #else
86 int asme, ch, fulllogin, fastlogin, prio;
87 #endif /* NO_GETUSERSHELL */
88 enum { UNSET, YES, NO } iscsh = UNSET;
89 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
90 char namebuf[50], shellbuf[MAXPATHLEN];
91 char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
92 #ifdef NOENCRYPTION
93 #define read_long_pw_string placebo_read_pw_string
94 #else
95 #define read_long_pw_string des_read_pw_string
96 #endif
97 int read_long_pw_string();
98 char pw_buf[MAXPWSIZE];
99 char *mytty;
100
101 mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)";
102
103 np = &nargv[3];
104 *np-- = NULL;
105 #ifdef NO_GETUSERSHELL
106 fulllogin = fastlogin = 0;
107 #define GETOPTARG "-flm"
108 #else
109 asme = fulllogin = fastlogin = 0;
110 #define GETOPTARG "-fl"
111 #endif
112 while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
113 switch((char)ch) {
114 case 'f':
115 fastlogin = 1;
116 break;
117 case '-':
118 case 'l':
119 fulllogin = 1;
120 break;
121 #ifndef NO_GETUSERSHELL
122 case 'm':
123 asme = 1;
124 break;
125 #endif
126 case '?':
127 default:
128 #ifdef NO_GETUSERSHELL
129 fprintf(stderr, "usage: ksu [-fl] [login]\n");
130 #else
131 fprintf(stderr, "usage: ksu [-flm] [login]\n");
132 #endif /* NO_GETUSERSHELL */
133 exit(1);
134 }
135 argv += optind;
136
137 errno = 0;
138 prio = getpriority(PRIO_PROCESS, 0);
139 if (errno)
140 prio = 0;
141 (void)setpriority(PRIO_PROCESS, 0, -2);
142
143 /* get current login name and shell */
144 if ((pwd = getpwuid(ruid = getuid())) == NULL) {
145 fprintf(stderr, "ksu: who are you?\n");
146 exit(1);
147 }
148 username = strcpy(namebuf, pwd->pw_name);
149 #ifndef NO_GETUSERSHELL
150 if (asme)
151 if (pwd->pw_shell && *pwd->pw_shell)
152 shell = strcpy(shellbuf, pwd->pw_shell);
153 else {
154 shell = "/bin/sh";
155 iscsh = NO;
156 }
157 #endif
158
159 /* get target login information */
160 user = *argv ? *argv : "root";
161 if ((pwd = getpwnam(user)) == NULL) {
162 fprintf(stderr, "ksu: unknown login %s\n", user);
163 exit(1);
164 }
165
166 /*
167 * Only allow those with kerberos root instances in the /.klogin
168 * file to su to root.
169 */
170 if (pwd->pw_uid == 0) {
171 KTEXT_ST ticket;
172 AUTH_DAT authdata;
173 char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
174 unsigned long faddr;
175 struct hostent *hp;
176
177 /* First lets see if he has a chance! */
178 if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
179 fprintf(stderr,"Unable to get local realm\n");
180 exit(1);
181 }
182 if (koktologin(username, lrealm)) {
183 fprintf(stderr,"You are not allowed to ksu to root\n");
184 exit(1);
185 }
186 sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
187 setuid(0); /* so ticket file has good protection */
188 if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
189 "Your root instance password: ", 0)) {
190 fprintf(stderr,"Error reading password.\n");
191 exit(1);
192 }
193 p = pw_buf;
194 setenv("KRBTKFILE", krbtkfile, 1);
195 kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
196 lrealm, 2, p);
197 bzero(p, strlen(p));
198 if (kerno != KSUCCESS) {
199 printf("Unable to ksu: %s\n", krb_err_txt[kerno]);
200 syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
201 username, mytty, krb_err_txt[kerno]);
202 exit(1);
203 }
204 setpriority(PRIO_PROCESS, 0, -2);
205 /*
206 * Now use the ticket for something useful, to make sure
207 * it is valid.
208 */
209 if (gethostname(hostname, sizeof(hostname)) == -1) {
210 perror("cannot retrieve hostname");
211 dest_tkt();
212 exit(1);
213 }
214 (void) strncpy(savehost, krb_get_phost(hostname),
215 sizeof(savehost));
216 savehost[sizeof(savehost)-1] = 0;
217
218 kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
219 if (kerno == KDC_PR_UNKNOWN) {
220 printf("Warning: tgt not verified\n");
221 syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified",
222 username, mytty);
223 } else if (kerno != KSUCCESS) {
224 printf("Unable to use tgt: %s\n", krb_err_txt[kerno]);
225 syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
226 username, mytty, krb_err_txt[kerno]);
227 dest_tkt();
228 exit(1);
229 } else {
230 if (!(hp = gethostbyname(hostname))) {
231 printf("Unable to get address of %s\n",hostname);
232 dest_tkt();
233 exit(1);
234 }
235 bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
236 if ((kerno = krb_rd_req(&ticket, "rcmd", savehost,
237 faddr, &authdata, "")) != KSUCCESS) {
238 printf("Unable to verify rcmd ticket: %s\n",
239 krb_err_txt[kerno]);
240 syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
241 username, mytty, krb_err_txt[kerno]);
242 dest_tkt();
243 exit(1);
244 }
245 }
246 printf("Don't forget to kdestroy before exiting the root shell.\n");
247 } else
248 /* if target requires a password, verify it */
249 if (ruid && *pwd->pw_passwd) {
250 p = getpass("Password:");
251 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
252 fprintf(stderr, "Sorry\n");
253 if (pwd->pw_uid == 0)
254 syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty);
255 exit(1);
256 }
257 }
258
259 #ifndef NO_GETUSERSHELL
260 if (asme) {
261 /* if asme and non-standard target shell, must be root */
262 if (!chshell(pwd->pw_shell) && ruid) {
263 fprintf(stderr, "ksu: Permission denied.\n");
264 dest_tkt();
265 exit(1);
266 }
267 }
268 else
269 #endif
270 if (pwd->pw_shell && *pwd->pw_shell) {
271 shell = pwd->pw_shell;
272 iscsh = UNSET;
273 } else {
274 shell = "/bin/sh";
275 iscsh = NO;
276 }
277
278 /* if we're forking a csh, we want to slightly muck the args */
279 if (iscsh == UNSET) {
280 if (p = rindex(shell, '/'))
281 ++p;
282 else
283 p = shell;
284 iscsh = strcmp(p, "csh") ? NO : YES;
285 }
286
287 /* set permissions */
288 if (setgid(pwd->pw_gid) < 0) {
289 perror("ksu: setgid");
290 dest_tkt();
291 exit(1);
292 }
293 if (initgroups(user, pwd->pw_gid)) {
294 fprintf(stderr, "ksu: initgroups failed\n");
295 dest_tkt();
296 exit(1);
297 }
298 if (setuid(pwd->pw_uid) < 0) {
299 perror("ksu: setuid");
300 dest_tkt();
301 exit(1);
302 }
303
304 #ifndef NO_GETUSERSHELL
305 if (!asme) {
306 #endif
307 if (fulllogin) {
308 p = getenv("TERM");
309 cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
310 cleanenv[1] = NULL;
311 environ = cleanenv;
312 (void)setenv("TERM", p, 1);
313 if (chdir(pwd->pw_dir) < 0) {
314 fprintf(stderr, "ksu: no directory\n");
315 dest_tkt();
316 exit(1);
317 }
318 }
319 if (fulllogin || pwd->pw_uid)
320 (void)setenv("USER", pwd->pw_name, 1);
321 (void)setenv("HOME", pwd->pw_dir, 1);
322 (void)setenv("SHELL", shell, 1);
323 #ifndef NO_GETUSERSHELL
324 }
325 #endif
326
327 if (iscsh == YES) {
328 if (fastlogin)
329 *np-- = "-f";
330 #ifndef NO_GETUSERSHELL
331 if (asme)
332 *np-- = "-m";
333 #endif
334 }
335
336 /* csh strips the first character... */
337 *np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu";
338
339 if (pwd->pw_uid == 0)
340 syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s",
341 username, mytty);
342
343 (void)setpriority(PRIO_PROCESS, 0, prio);
344
345 execv(shell, np);
346 fprintf(stderr, "ksu: no shell.\n");
347 dest_tkt();
348 exit(1);
349 }
350
351 #ifndef NO_GETUSERSHELL
chshell(sh)352 chshell(sh)
353 char *sh;
354 {
355 char *cp, *getusershell();
356
357 while ((cp = getusershell()) != NULL)
358 if (!strcmp(cp, sh))
359 return(1);
360 return(0);
361 }
362 #endif /* NO_GETUSERSHELL */
363
koktologin(name,realm)364 koktologin(name, realm)
365 char *name;
366 char *realm;
367 {
368 struct auth_dat kdata_st;
369 AUTH_DAT *kdata = &kdata_st;
370 /* Cons together an AUTH_DAT structure for kuserok */
371 bzero((caddr_t) kdata, sizeof(*kdata));
372 strcpy(kdata->pname, name);
373 strcpy(kdata->pinst, "root");
374 strcpy(kdata->prealm, realm);
375 return (kuserok(kdata, "root"));
376 }
377