1#ifndef lint 2static char *sccsid = "@(#)login.c.1 4.31 (Berkeley) 83/06/30"; 3#endif 4 5/* 6 * login [ name ] 7 * login -r hostname (for rlogind) 8 * login -h hostname (for telnetd, etc.) 9 */ 10 11#include <sys/param.h> 12#include <sys/quota.h> 13#include <sys/stat.h> 14#include <sys/time.h> 15#include <sys/resource.h> 16 17#include <sgtty.h> 18#include <utmp.h> 19#include <signal.h> 20#include <pwd.h> 21#include <stdio.h> 22#include <lastlog.h> 23#include <errno.h> 24 25#define SCPYN(a, b) strncpy(a, b, sizeof(a)) 26 27#define NMAX sizeof(utmp.ut_name) 28 29#define FALSE 0 30#define TRUE -1 31 32char nolog[] = "/etc/nologin"; 33char qlog[] = ".hushlogin"; 34char securetty[] = "/etc/securetty"; 35char maildir[30] = "/usr/spool/mail/"; 36char lastlog[] = "/usr/adm/lastlog"; 37struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 38struct sgttyb ttyb; 39struct utmp utmp; 40char minusnam[16] = "-"; 41/* 42 * This bounds the time given to login. We initialize it here 43 * so it can be patched on machines where it's too small. 44 */ 45int timeout = 60; 46 47char homedir[64] = "HOME="; 48char shell[64] = "SHELL="; 49char term[64] = "TERM="; 50char user[20] = "USER="; 51 52char *envinit[] = 53 { homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0 }; 54 55struct passwd *pwd; 56struct passwd *getpwnam(); 57char *strcat(), *rindex(), *index(); 58int setpwent(); 59int timedout(); 60char *ttyname(); 61char *crypt(); 62char *getpass(); 63char *stypeof(); 64extern char **environ; 65extern int errno; 66 67struct tchars tc = { 68 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 69}; 70struct ltchars ltc = { 71 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 72}; 73 74int rflag; 75char rusername[NMAX+1], lusername[NMAX+1]; 76char rpassword[NMAX+1]; 77char name[NMAX+1]; 78char *rhost; 79 80main(argc, argv) 81 char *argv[]; 82{ 83 register char *namep; 84 int t, f, c, i; 85 int invalid, quietlog; 86 FILE *nlfd; 87 char *ttyn; 88 int ldisc = 0, zero = 0; 89 90 signal(SIGALRM, timedout); 91 alarm(timeout); 92 signal(SIGQUIT, SIG_IGN); 93 signal(SIGINT, SIG_IGN); 94 setpriority(PRIO_PROCESS, 0, 0); 95 quota(Q_SETUID, 0, 0, 0); 96 /* 97 * -r is used by rlogind to cause the autologin protocol; 98 * -h is used by other servers to pass the name of the 99 * remote host to login so that it may be placed in utmp and wtmp 100 */ 101 if (argc > 1) { 102 if (strcmp(argv[1], "-r") == 0) { 103 rflag = doremotelogin(argv[2]); 104 SCPYN(utmp.ut_host, argv[2]); 105 argc = 0; 106 } 107 if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 108 SCPYN(utmp.ut_host, argv[2]); 109 argc = 0; 110 } 111 } 112 ioctl(0, TIOCLSET, &zero); 113 ioctl(0, TIOCNXCL, 0); 114 ioctl(0, FIONBIO, &zero); 115 ioctl(0, FIOASYNC, &zero); 116 ioctl(0, TIOCGETP, &ttyb); 117 /* 118 * If talking to an rlogin process, 119 * propagate the terminal type and 120 * baud rate across the network. 121 */ 122 if (rflag) 123 doremoteterm(term, &ttyb); 124 ioctl(0, TIOCSLTC, <c); 125 ioctl(0, TIOCSETC, &tc); 126 ioctl(0, TIOCSETP, &ttyb); 127 for (t = getdtablesize(); t > 3; t--) 128 close(t); 129 ttyn = ttyname(0); 130 if (ttyn==(char *)0) 131 ttyn = "/dev/tty??"; 132 do { 133 ldisc = 0; 134 ioctl(0, TIOCSETD, &ldisc); 135 invalid = FALSE; 136 SCPYN(utmp.ut_name, ""); 137 /* 138 * Name specified, take it. 139 */ 140 if (argc > 1) { 141 SCPYN(utmp.ut_name, argv[1]); 142 argc = 0; 143 } 144 /* 145 * If remote login take given name, 146 * otherwise prompt user for something. 147 */ 148 if (rflag) { 149 SCPYN(utmp.ut_name, lusername); 150 /* autologin failed, prompt for passwd */ 151 if (rflag == -1) 152 rflag = 0; 153 } else 154 getloginname(&utmp); 155 if (!strcmp(pwd->pw_shell, "/bin/csh")) { 156 ldisc = NTTYDISC; 157 ioctl(0, TIOCSETD, &ldisc); 158 } 159 /* 160 * If no remote login authentication and 161 * a password exists for this user, prompt 162 * for one and verify it. 163 */ 164 if (!rflag && *pwd->pw_passwd != '\0') { 165 char *pp; 166 167 setpriority(PRIO_PROCESS, 0, -4); 168 pp = getpass("Password:"); 169 namep = crypt(pp, pwd->pw_passwd); 170 setpriority(PRIO_PROCESS, 0, 0); 171 if (strcmp(namep, pwd->pw_passwd)) 172 invalid = TRUE; 173 } 174 /* 175 * If user not super-user, check for logins disabled. 176 */ 177 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 178 while ((c = getc(nlfd)) != EOF) 179 putchar(c); 180 fflush(stdout); 181 sleep(5); 182 exit(0); 183 } 184 /* 185 * If valid so far and root is logging in, 186 * see if root logins on this terminal are permitted. 187 */ 188 if (!invalid && pwd->pw_uid == 0 && 189 !rootterm(ttyn+sizeof("/dev/")-1)) { 190 logerr("ROOT LOGIN REFUSED %s", 191 ttyn+sizeof("/dev/")-1); 192 invalid = TRUE; 193 } 194 if (invalid) { 195 printf("Login incorrect\n"); 196 if (ttyn[sizeof("/dev/tty")-1] == 'd') 197 logerr("BADDIALUP %s %s\n", 198 ttyn+sizeof("/dev/")-1, utmp.ut_name); 199 } 200 if (*pwd->pw_shell == '\0') 201 pwd->pw_shell = "/bin/sh"; 202 i = strlen(pwd->pw_shell); 203 if (chdir(pwd->pw_dir) < 0 && !invalid ) { 204 if (chdir("/") < 0) { 205 printf("No directory!\n"); 206 invalid = TRUE; 207 } else { 208 printf("No directory! %s\n", 209 "Logging in with home=/"); 210 pwd->pw_dir = "/"; 211 } 212 } 213 /* 214 * Remote login invalid must have been because 215 * of a restriction of some sort, no extra chances. 216 */ 217 if (rflag && invalid) 218 exit(1); 219 } while (invalid); 220/* committed to login turn off timeout */ 221 alarm(0); 222 223 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0) { 224 if (errno == EUSERS) 225 printf("%s.\n%s.\n", 226 "Too many users logged on already", 227 "Try again later"); 228 else if (errno == EPROCLIM) 229 printf("You have too many processes running.\n"); 230 else 231 perror("setuid"); 232 sleep(5); 233 exit(0); 234 } 235 time(&utmp.ut_time); 236 t = ttyslot(); 237 if (t > 0 && (f = open("/etc/utmp", 1)) >= 0) { 238 lseek(f, (long)(t*sizeof(utmp)), 0); 239 SCPYN(utmp.ut_line, rindex(ttyn, '/')+1); 240 write(f, (char *)&utmp, sizeof(utmp)); 241 close(f); 242 } 243 if (t > 0 && (f = open("/usr/adm/wtmp", 1)) >= 0) { 244 lseek(f, 0L, 2); 245 write(f, (char *)&utmp, sizeof(utmp)); 246 close(f); 247 } 248 quietlog = access(qlog, 0) == 0; 249 if ((f = open(lastlog, 2)) >= 0) { 250 struct lastlog ll; 251 252 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 253 if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 254 ll.ll_time != 0 && !quietlog) { 255 printf("Last login: %.*s ", 256 24-5, (char *)ctime(&ll.ll_time)); 257 if (*ll.ll_host != '\0') 258 printf("from %.*s\n", 259 sizeof (ll.ll_host), ll.ll_host); 260 else 261 printf("on %.*s\n", 262 sizeof (ll.ll_line), ll.ll_line); 263 } 264 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 265 time(&ll.ll_time); 266 SCPYN(ll.ll_line, rindex(ttyn, '/')+1); 267 SCPYN(ll.ll_host, utmp.ut_host); 268 write(f, (char *) &ll, sizeof ll); 269 close(f); 270 } 271 chown(ttyn, pwd->pw_uid, pwd->pw_gid); 272 chmod(ttyn, 0622); 273 setgid(pwd->pw_gid); 274 strncpy(name, utmp.ut_name, NMAX); 275 name[NMAX] = '\0'; 276 initgroups(name, pwd->pw_gid); 277 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 278 setuid(pwd->pw_uid); 279 environ = envinit; 280 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 281 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 282 if (term[strlen("TERM=")] == 0) 283 strncat(term, stypeof(ttyn), sizeof(term)-6); 284 strncat(user, pwd->pw_name, sizeof(user)-6); 285 if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 286 namep = pwd->pw_shell; 287 else 288 namep++; 289 strcat(minusnam, namep); 290 umask(022); 291 if (ttyn[sizeof("/dev/tty")-1] == 'd') 292 logerr("DIALUP %s %s\n", ttyn+sizeof("/dev/")-1, pwd->pw_name); 293 if (!quietlog) { 294 showmotd(); 295 strcat(maildir, pwd->pw_name); 296 if (access(maildir,4)==0) { 297 struct stat statb; 298 stat(maildir, &statb); 299 if (statb.st_size) 300 printf("You have mail.\n"); 301 } 302 } 303 signal(SIGALRM, SIG_DFL); 304 signal(SIGQUIT, SIG_DFL); 305 signal(SIGINT, SIG_DFL); 306 signal(SIGTSTP, SIG_IGN); 307 execlp(pwd->pw_shell, minusnam, 0); 308 perror(pwd->pw_shell); 309 printf("No shell\n"); 310 exit(0); 311} 312 313getloginname(up) 314 register struct utmp *up; 315{ 316 register char *namep; 317 char c; 318 319 while (up->ut_name[0] == '\0') { 320 namep = utmp.ut_name; 321 printf("login: "); 322 while ((c = getchar()) != '\n') { 323 if (c == ' ') 324 c = '_'; 325 if (c == EOF) 326 exit(0); 327 if (namep < up->ut_name+NMAX) 328 *namep++ = c; 329 } 330 } 331 setpwent(); 332 if ((pwd = getpwnam(utmp.ut_name)) == NULL) 333 pwd = &nouser; 334 endpwent(); 335} 336 337timedout() 338{ 339 340 printf("Login timed out after %d seconds\n", timeout); 341 exit(0); 342} 343 344int stopmotd; 345catch() 346{ 347 348 signal(SIGINT, SIG_IGN); 349 stopmotd++; 350} 351 352rootterm(tty) 353 char *tty; 354{ 355 register FILE *fd; 356 char buf[100]; 357 358 if ((fd = fopen(securetty, "r")) == NULL) 359 return(1); 360 while (fgets(buf, sizeof buf, fd) != NULL) { 361 buf[strlen(buf)-1] = '\0'; 362 if (strcmp(tty, buf) == 0) { 363 fclose(fd); 364 return(1); 365 } 366 } 367 fclose(fd); 368 return(0); 369} 370 371showmotd() 372{ 373 FILE *mf; 374 register c; 375 376 signal(SIGINT, catch); 377 if ((mf = fopen("/etc/motd","r")) != NULL) { 378 while ((c = getc(mf)) != EOF && stopmotd == 0) 379 putchar(c); 380 fclose(mf); 381 } 382 signal(SIGINT, SIG_IGN); 383} 384 385#undef UNKNOWN 386#define UNKNOWN "su" 387 388char * 389stypeof(ttyid) 390 char *ttyid; 391{ 392 static char typebuf[16]; 393 char buf[50]; 394 register FILE *f; 395 register char *p, *t, *q; 396 397 if (ttyid == NULL) 398 return (UNKNOWN); 399 f = fopen("/etc/ttytype", "r"); 400 if (f == NULL) 401 return (UNKNOWN); 402 /* split off end of name */ 403 for (p = q = ttyid; *p != 0; p++) 404 if (*p == '/') 405 q = p + 1; 406 407 /* scan the file */ 408 while (fgets(buf, sizeof buf, f) != NULL) { 409 for (t = buf; *t != ' ' && *t != '\t'; t++) 410 ; 411 *t++ = 0; 412 while (*t == ' ' || *t == '\t') 413 t++; 414 for (p = t; *p > ' '; p++) 415 ; 416 *p = 0; 417 if (strcmp(q,t) == 0) { 418 strcpy(typebuf, buf); 419 fclose(f); 420 return (typebuf); 421 } 422 } 423 fclose (f); 424 return (UNKNOWN); 425} 426 427doremotelogin(host) 428 char *host; 429{ 430 FILE *hostf; 431 int first = 1; 432 433 getstr(rusername, sizeof (rusername), "remuser"); 434 getstr(lusername, sizeof (lusername), "locuser"); 435 getstr(term+5, sizeof(term)-5, "Terminal type"); 436 if (getuid()) { 437 pwd = &nouser; 438 goto bad; 439 } 440 setpwent(); 441 pwd = getpwnam(lusername); 442 endpwent(); 443 if (pwd == NULL) { 444 pwd = &nouser; 445 goto bad; 446 } 447 hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0; 448again: 449 if (hostf) { 450 char ahost[32]; 451 452 while (fgets(ahost, sizeof (ahost), hostf)) { 453 char *user; 454 455 if ((user = index(ahost, '\n')) != 0) 456 *user++ = '\0'; 457 if ((user = index(ahost, ' ')) != 0) 458 *user++ = '\0'; 459 if (!strcmp(host, ahost) && 460 !strcmp(rusername, user ? user : lusername)) { 461 fclose(hostf); 462 return (1); 463 } 464 } 465 fclose(hostf); 466 } 467 if (first == 1) { 468 char *rhosts = ".rhosts"; 469 struct stat sbuf; 470 471 first = 0; 472 if (chdir(pwd->pw_dir) < 0) 473 goto again; 474 if (lstat(rhosts, &sbuf) < 0) 475 goto again; 476 if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { 477 printf("login: .rhosts is a soft link.\r\n"); 478 goto bad; 479 } 480 hostf = fopen(rhosts, "r"); 481 fstat(fileno(hostf), &sbuf); 482 if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { 483 printf("login: Bad .rhosts ownership.\r\n"); 484 fclose(hostf); 485 goto bad; 486 } 487 goto again; 488 } 489bad: 490 return (-1); 491} 492 493getstr(buf, cnt, err) 494 char *buf; 495 int cnt; 496 char *err; 497{ 498 char c; 499 500 do { 501 if (read(0, &c, 1) != 1) 502 exit(1); 503 if (--cnt < 0) { 504 printf("%s too long\r\n", err); 505 exit(1); 506 } 507 *buf++ = c; 508 } while (c != 0); 509} 510 511char *speeds[] = 512 { "0", "50", "75", "110", "134", "150", "200", "300", 513 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 514#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 515 516doremoteterm(term, tp) 517 char *term; 518 struct sgttyb *tp; 519{ 520 char *cp = index(term, '/'); 521 register int i; 522 523 if (cp) { 524 *cp++ = 0; 525 for (i = 0; i < NSPEEDS; i++) 526 if (!strcmp(speeds[i], cp)) { 527 tp->sg_ispeed = tp->sg_ospeed = i; 528 break; 529 } 530 } 531 tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 532} 533 534logerr(fmt, a1, a2, a3) 535 char *fmt, *a1, *a2, *a3; 536{ 537#ifdef LOGERR 538 FILE *cons = fopen("/dev/console", "w"); 539 540 if (cons != NULL) { 541 fprintf(cons, fmt, a1, a2, a3); 542 fputc('\r', cons); 543 fclose(cons); 544 } 545#endif 546} 547