1 /* 2 * Copyright (c) 1980, 1987, 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. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)login.c 5.37 (Berkeley) 03/14/89"; 26 #endif /* not lint */ 27 28 /* 29 * login [ name ] 30 * login -h hostname (for telnetd, etc.) 31 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 32 */ 33 34 #include <sys/param.h> 35 #include <sys/quota.h> 36 #include <sys/stat.h> 37 #include <sys/time.h> 38 #include <sys/resource.h> 39 #include <sys/file.h> 40 #include <sys/ioctl.h> 41 42 #include <utmp.h> 43 #include <signal.h> 44 #include <lastlog.h> 45 #include <errno.h> 46 #include <ttyent.h> 47 #include <syslog.h> 48 #include <grp.h> 49 #include <pwd.h> 50 #include <setjmp.h> 51 #include <stdio.h> 52 #include <strings.h> 53 #include "pathnames.h" 54 55 #ifdef KERBEROS 56 #include <kerberos/krb.h> 57 #include <sys/termios.h> 58 char realm[REALM_SZ]; 59 int kerror = KSUCCESS, notickets = 1; 60 #endif 61 62 #define TTYGRPNAME "tty" /* name of group to own ttys */ 63 64 /* 65 * This bounds the time given to login. Not a define so it can 66 * be patched on machines where it's too small. 67 */ 68 int timeout = 300; 69 70 struct passwd *pwd; 71 int failures; 72 char term[64], *hostname, *username, *tty; 73 74 struct sgttyb sgttyb; 75 struct tchars tc = { 76 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 77 }; 78 struct ltchars ltc = { 79 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 80 }; 81 82 char *months[] = 83 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 84 "Sep", "Oct", "Nov", "Dec" }; 85 86 main(argc, argv) 87 int argc; 88 char **argv; 89 { 90 extern int errno, optind; 91 extern char *optarg, **environ; 92 struct timeval tp; 93 struct tm *ttp; 94 struct group *gr; 95 register int ch; 96 register char *p; 97 int ask, fflag, hflag, pflag, cnt; 98 int quietlog, passwd_req, ioctlval, timedout(); 99 char *domain, *salt, *envinit[1], *ttyn, *pp; 100 char tbuf[MAXPATHLEN + 2]; 101 char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 102 time_t time(); 103 off_t lseek(); 104 105 (void)signal(SIGALRM, timedout); 106 (void)alarm((u_int)timeout); 107 (void)signal(SIGQUIT, SIG_IGN); 108 (void)signal(SIGINT, SIG_IGN); 109 (void)setpriority(PRIO_PROCESS, 0, 0); 110 (void)quota(Q_SETUID, 0, 0, 0); 111 112 /* 113 * -p is used by getty to tell login not to destroy the environment 114 * -f is used to skip a second login authentication 115 * -h is used by other servers to pass the name of the remote 116 * host to login so that it may be placed in utmp and wtmp 117 */ 118 (void)gethostname(tbuf, sizeof(tbuf)); 119 domain = index(tbuf, '.'); 120 121 fflag = hflag = pflag = 0; 122 passwd_req = 1; 123 while ((ch = getopt(argc, argv, "fh:p")) != EOF) 124 switch (ch) { 125 case 'f': 126 fflag = 1; 127 break; 128 case 'h': 129 if (getuid()) { 130 fprintf(stderr, 131 "login: -h for super-user only.\n"); 132 exit(1); 133 } 134 hflag = 1; 135 if (domain && (p = index(optarg, '.')) && 136 strcasecmp(p, domain) == 0) 137 *p = 0; 138 hostname = optarg; 139 break; 140 case 'p': 141 pflag = 1; 142 break; 143 case '?': 144 default: 145 fprintf(stderr, "usage: login [-fp] [username]\n"); 146 exit(1); 147 } 148 argc -= optind; 149 argv += optind; 150 if (*argv) { 151 username = *argv; 152 ask = 0; 153 } else 154 ask = 1; 155 156 ioctlval = 0; 157 (void)ioctl(0, TIOCLSET, &ioctlval); 158 (void)ioctl(0, TIOCNXCL, 0); 159 (void)fcntl(0, F_SETFL, ioctlval); 160 (void)ioctl(0, TIOCGETP, &sgttyb); 161 sgttyb.sg_erase = CERASE; 162 sgttyb.sg_kill = CKILL; 163 (void)ioctl(0, TIOCSLTC, <c); 164 (void)ioctl(0, TIOCSETC, &tc); 165 (void)ioctl(0, TIOCSETP, &sgttyb); 166 167 for (cnt = getdtablesize(); cnt > 2; cnt--) 168 close(cnt); 169 170 ttyn = ttyname(0); 171 if (ttyn == NULL || *ttyn == '\0') 172 ttyn = "/dev/tty??"; 173 if (tty = rindex(ttyn, '/')) 174 ++tty; 175 else 176 tty = ttyn; 177 178 openlog("login", LOG_ODELAY, LOG_AUTH); 179 180 for (cnt = 0;; ask = 1) { 181 ioctlval = 0; 182 (void)ioctl(0, TIOCSETD, &ioctlval); 183 184 if (ask) { 185 fflag = 0; 186 getloginname(); 187 } 188 /* 189 * Note if trying multiple user names; 190 * log failures for previous user name, 191 * but don't bother logging one failure 192 * for nonexistent name (mistyped username). 193 */ 194 if (failures && strcmp(tbuf, username)) { 195 if (failures > (pwd ? 0 : 1)) 196 badlogin(tbuf); 197 failures = 0; 198 } 199 (void)strcpy(tbuf, username); 200 if (pwd = getpwnam(username)) 201 salt = pwd->pw_passwd; 202 else 203 salt = "xx"; 204 205 /* if user not super-user, check for disabled logins */ 206 if (pwd == NULL || pwd->pw_uid) 207 checknologin(); 208 209 /* 210 * Disallow automatic login to root; if not invoked by 211 * root, disallow if the uid's differ. 212 */ 213 if (fflag && pwd) { 214 int uid = getuid(); 215 216 passwd_req = pwd->pw_uid == 0 || 217 (uid && uid != pwd->pw_uid); 218 } 219 220 /* 221 * If no pre-authentication and a password exists 222 * for this user, prompt for one and verify it. 223 */ 224 if (!passwd_req || (pwd && !*pwd->pw_passwd)) 225 break; 226 227 setpriority(PRIO_PROCESS, 0, -4); 228 pp = getpass("Password:"); 229 p = crypt(pp, salt); 230 setpriority(PRIO_PROCESS, 0, 0); 231 232 #ifdef KERBEROS 233 234 /* 235 * If not present in pw file, act as we normally would. 236 * If we aren't Kerberos-authenticated, try the normal 237 * pw file for a password. If that's ok, log the user 238 * in without issueing any tickets. 239 */ 240 241 if (pwd && !krb_get_lrealm(realm,1)) { 242 /* get TGT for local realm 243 * be careful about uid's here for ticket 244 * file ownership 245 */ 246 (void) setreuid(geteuid(),pwd->pw_uid); 247 kerror = krb_get_pw_in_tkt( 248 pwd->pw_name, "", realm, 249 "krbtgt", realm, DEFAULT_TKT_LIFE, pp); 250 (void) setuid(0); 251 if (kerror == INTK_OK) { 252 bzero(pp, strlen(pp)); 253 notickets = 0; /* user got ticket */ 254 break; 255 } 256 } 257 #endif 258 (void) bzero(pp, strlen(pp)); 259 if (pwd && !strcmp(p, pwd->pw_passwd)) 260 break; 261 262 printf("Login incorrect\n"); 263 failures++; 264 /* we allow 10 tries, but after 3 we start backing off */ 265 if (++cnt > 3) { 266 if (cnt >= 10) { 267 badlogin(username); 268 (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 269 sleepexit(1); 270 } 271 sleep((u_int)((cnt - 3) * 5)); 272 } 273 } 274 275 /* committed to login -- turn off timeout */ 276 (void)alarm((u_int)0); 277 278 /* 279 * If valid so far and root is logging in, see if root logins on 280 * this terminal are permitted. 281 */ 282 if (pwd->pw_uid == 0 && !rootterm(tty)) { 283 if (hostname) 284 syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", 285 hostname); 286 else 287 syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); 288 printf("Login incorrect\n"); 289 sleepexit(1); 290 } 291 292 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 293 switch(errno) { 294 case EUSERS: 295 fprintf(stderr, 296 "Too many users logged on already.\nTry again later.\n"); 297 break; 298 case EPROCLIM: 299 fprintf(stderr, 300 "You have too many processes running.\n"); 301 break; 302 default: 303 perror("quota (Q_SETUID)"); 304 } 305 sleepexit(0); 306 } 307 308 if (chdir(pwd->pw_dir) < 0) { 309 printf("No directory %s!\n", pwd->pw_dir); 310 if (chdir("/")) 311 exit(0); 312 pwd->pw_dir = "/"; 313 printf("Logging in with home = \"/\".\n"); 314 } 315 316 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 317 318 #ifdef KERBEROS 319 if (notickets && !quietlog) 320 printf("Warning: no Kerberos tickets issued\n"); 321 #endif 322 323 #define TWOWEEKS (14*24*60*60) 324 if (pwd->pw_change || pwd->pw_expire) 325 (void)gettimeofday(&tp, (struct timezone *)NULL); 326 if (pwd->pw_change) 327 if (tp.tv_sec >= pwd->pw_change) { 328 printf("Sorry -- your password has expired.\n"); 329 sleepexit(1); 330 } 331 else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { 332 ttp = localtime(&pwd->pw_change); 333 printf("Warning: your password expires on %s %d, 19%d\n", 334 months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); 335 } 336 if (pwd->pw_expire) 337 if (tp.tv_sec >= pwd->pw_expire) { 338 printf("Sorry -- your account has expired.\n"); 339 sleepexit(1); 340 } 341 else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { 342 ttp = localtime(&pwd->pw_expire); 343 printf("Warning: your account expires on %s %d, 19%d\n", 344 months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); 345 } 346 347 /* nothing else left to fail -- really log in */ 348 { 349 struct utmp utmp; 350 351 bzero((char *)&utmp, sizeof(utmp)); 352 (void)time(&utmp.ut_time); 353 strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 354 if (hostname) 355 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 356 strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 357 login(&utmp); 358 } 359 360 dolastlog(quietlog); 361 362 if (!hflag) { /* XXX */ 363 static struct winsize win = { 0, 0, 0, 0 }; 364 365 (void)ioctl(0, TIOCSWINSZ, &win); 366 } 367 368 (void)chown(ttyn, pwd->pw_uid, 369 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 370 (void)chmod(ttyn, 0620); 371 (void)setgid(pwd->pw_gid); 372 373 initgroups(username, pwd->pw_gid); 374 375 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 376 (void)setuid(pwd->pw_uid); 377 378 if (*pwd->pw_shell == '\0') 379 pwd->pw_shell = _PATH_BSHELL; 380 /* turn on new line discipline for the csh */ 381 else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { 382 ioctlval = NTTYDISC; 383 (void)ioctl(0, TIOCSETD, &ioctlval); 384 } 385 386 /* destroy environment unless user has requested preservation */ 387 if (!pflag) 388 environ = envinit; 389 (void)setenv("HOME", pwd->pw_dir, 1); 390 (void)setenv("SHELL", pwd->pw_shell, 1); 391 if (term[0] == '\0') 392 strncpy(term, stypeof(tty), sizeof(term)); 393 (void)setenv("TERM", term, 0); 394 (void)setenv("USER", pwd->pw_name, 1); 395 (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); 396 397 if (tty[sizeof("tty")-1] == 'd') 398 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 399 if (pwd->pw_uid == 0) 400 if (hostname) 401 syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 402 tty, hostname); 403 else 404 syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 405 406 if (!quietlog) { 407 struct stat st; 408 409 motd(); 410 (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 411 if (stat(tbuf, &st) == 0 && st.st_size != 0) 412 printf("You have %smail.\n", 413 (st.st_mtime > st.st_atime) ? "new " : ""); 414 } 415 416 (void)signal(SIGALRM, SIG_DFL); 417 (void)signal(SIGQUIT, SIG_DFL); 418 (void)signal(SIGINT, SIG_DFL); 419 (void)signal(SIGTSTP, SIG_IGN); 420 421 tbuf[0] = '-'; 422 strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 423 p + 1 : pwd->pw_shell); 424 execlp(pwd->pw_shell, tbuf, 0); 425 fprintf(stderr, "login: no shell: "); 426 perror(pwd->pw_shell); 427 exit(0); 428 } 429 430 getloginname() 431 { 432 register int ch; 433 register char *p; 434 static char nbuf[UT_NAMESIZE + 1]; 435 436 for (;;) { 437 printf("login: "); 438 for (p = nbuf; (ch = getchar()) != '\n'; ) { 439 if (ch == EOF) { 440 badlogin(username); 441 exit(0); 442 } 443 if (p < nbuf + UT_NAMESIZE) 444 *p++ = ch; 445 } 446 if (p > nbuf) 447 if (nbuf[0] == '-') 448 fprintf(stderr, 449 "login names may not start with '-'.\n"); 450 else { 451 *p = '\0'; 452 username = nbuf; 453 break; 454 } 455 } 456 } 457 458 timedout() 459 { 460 fprintf(stderr, "Login timed out after %d seconds\n", timeout); 461 exit(0); 462 } 463 464 rootterm(ttyn) 465 char *ttyn; 466 { 467 struct ttyent *t; 468 469 return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 470 } 471 472 jmp_buf motdinterrupt; 473 474 motd() 475 { 476 register int fd, nchars; 477 int (*oldint)(), sigint(); 478 char tbuf[8192]; 479 480 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 481 return; 482 oldint = signal(SIGINT, sigint); 483 if (setjmp(motdinterrupt) == 0) 484 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 485 (void)write(fileno(stdout), tbuf, nchars); 486 (void)signal(SIGINT, oldint); 487 (void)close(fd); 488 } 489 490 sigint() 491 { 492 longjmp(motdinterrupt, 1); 493 } 494 495 checknologin() 496 { 497 register int fd, nchars; 498 char tbuf[8192]; 499 500 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 501 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 502 (void)write(fileno(stdout), tbuf, nchars); 503 sleepexit(0); 504 } 505 } 506 507 dolastlog(quiet) 508 int quiet; 509 { 510 struct lastlog ll; 511 int fd; 512 char *ctime(); 513 514 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 515 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 516 if (!quiet) { 517 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 518 ll.ll_time != 0) { 519 printf("Last login: %.*s ", 520 24-5, (char *)ctime(&ll.ll_time)); 521 if (*ll.ll_host != '\0') 522 printf("from %.*s\n", 523 sizeof(ll.ll_host), ll.ll_host); 524 else 525 printf("on %.*s\n", 526 sizeof(ll.ll_line), ll.ll_line); 527 } 528 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 529 } 530 bzero((char *)&ll, sizeof(ll)); 531 (void)time(&ll.ll_time); 532 strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 533 if (hostname) 534 strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 535 (void)write(fd, (char *)&ll, sizeof(ll)); 536 (void)close(fd); 537 } 538 } 539 540 badlogin(name) 541 char *name; 542 { 543 if (failures == 0) 544 return; 545 if (hostname) 546 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 547 failures, failures > 1 ? "S" : "", hostname, name); 548 else 549 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 550 failures, failures > 1 ? "S" : "", tty, name); 551 } 552 553 #undef UNKNOWN 554 #define UNKNOWN "su" 555 556 char * 557 stypeof(ttyid) 558 char *ttyid; 559 { 560 struct ttyent *t; 561 562 return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 563 } 564 565 getstr(buf, cnt, err) 566 char *buf, *err; 567 int cnt; 568 { 569 char ch; 570 571 do { 572 if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 573 exit(1); 574 if (--cnt < 0) { 575 fprintf(stderr, "%s too long\r\n", err); 576 sleepexit(1); 577 } 578 *buf++ = ch; 579 } while (ch); 580 } 581 582 sleepexit(eval) 583 int eval; 584 { 585 sleep((u_int)5); 586 exit(eval); 587 } 588