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 <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 <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 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 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 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