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