1 /* $OpenBSD: login.c,v 1.35 2000/10/14 20:33:13 miod Exp $ */ 2 /* $NetBSD: login.c,v 1.13 1996/05/15 23:50:16 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 46 #endif 47 static char rcsid[] = "$OpenBSD: login.c,v 1.35 2000/10/14 20:33:13 miod Exp $"; 48 #endif /* not lint */ 49 50 /* 51 * login [ name ] 52 * login -h hostname (for telnetd, etc.) 53 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 54 */ 55 56 #include <sys/param.h> 57 #include <sys/stat.h> 58 #include <sys/time.h> 59 #include <sys/resource.h> 60 #include <sys/wait.h> 61 62 #include <err.h> 63 #include <errno.h> 64 #include <fcntl.h> 65 #include <grp.h> 66 #include <login_cap.h> 67 #include <pwd.h> 68 #include <setjmp.h> 69 #include <signal.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <syslog.h> 74 #include <ttyent.h> 75 #include <tzfile.h> 76 #include <unistd.h> 77 #include <utmp.h> 78 #include <util.h> 79 #include <skey.h> 80 81 #include "pathnames.h" 82 83 void badlogin __P((char *)); 84 void checknologin __P((void)); 85 void dolastlog __P((int)); 86 void getloginname __P((void)); 87 void motd __P((void)); 88 int rootterm __P((char *)); 89 void sigint __P((int)); 90 void sighup __P((int)); 91 void sleepexit __P((int)); 92 char *stypeof __P((char *)); 93 void timedout __P((int)); 94 int pwcheck __P((char *, char *, char *, char *)); 95 #if defined(KERBEROS) || defined(KERBEROS5) 96 int klogin __P((struct passwd *, char *, char *, char *)); 97 void kdestroy __P((void)); 98 void dofork __P((void)); 99 void kgettokens __P((char *)); 100 #endif 101 102 extern int check_failedlogin __P((uid_t)); 103 extern void log_failedlogin __P((uid_t, char *, char *, char *)); 104 105 #define TTYGRPNAME "tty" /* name of group to own ttys */ 106 107 /* 108 * This bounds the time given to login. Not a define so it can 109 * be patched on machines where it's too small. 110 * XXX - should be a login.conf variable! 111 */ 112 u_int timeout = 300; 113 114 #if defined(KERBEROS) || defined(KERBEROS5) 115 int notickets = 1; 116 char *instance; 117 char *krbtkfile_env; 118 int authok; 119 #endif 120 121 struct passwd *pwd; 122 login_cap_t *lc = NULL; 123 int failures; 124 char term[64], *hostname, *tty; 125 char *username = NULL, *rusername = NULL; 126 127 int 128 main(argc, argv) 129 int argc; 130 char *argv[]; 131 { 132 extern char **environ; 133 struct group *gr; 134 struct stat st; 135 struct timeval tp; 136 struct utmp utmp; 137 int ask, ch, cnt, fflag, hflag, pflag, uflag, quietlog, rootlogin, rval; 138 uid_t uid; 139 char *domain, *p, *salt, *ttyn, *shell; 140 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 141 char localhost[MAXHOSTNAMELEN]; 142 143 (void)signal(SIGALRM, timedout); 144 (void)alarm(timeout); 145 (void)signal(SIGQUIT, SIG_IGN); 146 (void)signal(SIGINT, SIG_IGN); 147 (void)signal(SIGHUP, sighup); 148 (void)setpriority(PRIO_PROCESS, 0, 0); 149 150 openlog("login", LOG_ODELAY, LOG_AUTH); 151 152 /* 153 * -p is used by getty to tell login not to destroy the environment 154 * -f is used to skip a second login authentication 155 * -h is used by other servers to pass the name of the remote 156 * host to login so that it may be placed in utmp and wtmp 157 */ 158 domain = NULL; 159 if (gethostname(localhost, sizeof(localhost)) < 0) 160 syslog(LOG_ERR, "couldn't get local hostname: %m"); 161 else 162 domain = strchr(localhost, '.'); 163 if (domain) { 164 domain++; 165 if (*domain && strchr(domain, '.') == NULL) 166 domain = localhost; 167 } 168 169 fflag = hflag = pflag = 0; 170 uid = getuid(); 171 while ((ch = getopt(argc, argv, "fh:u:p")) != -1) 172 switch (ch) { 173 case 'f': 174 fflag = 1; 175 break; 176 case 'h': 177 if (uid) 178 errx(1, "-h option: %s", strerror(EPERM)); 179 hflag = 1; 180 if (domain && (p = strchr(optarg, '.')) && 181 strcasecmp(p+1, domain) == 0) 182 *p = 0; 183 hostname = optarg; 184 break; 185 case 'p': 186 pflag = 1; 187 break; 188 case 'u': 189 if (uid) 190 errx(1, "-u option: %s", strerror(EPERM)); 191 uflag = 1; 192 rusername = optarg; 193 break; 194 case '?': 195 default: 196 if (!uid) 197 syslog(LOG_ERR, "invalid flag %c", ch); 198 (void)fprintf(stderr, 199 "usage: login [-fp] [-h hostname] [username]\n"); 200 exit(1); 201 } 202 argc -= optind; 203 argv += optind; 204 205 if (*argv) { 206 username = *argv; 207 ask = 0; 208 } else 209 ask = 1; 210 211 for (cnt = getdtablesize(); cnt > 2; cnt--) 212 (void)close(cnt); 213 214 ttyn = ttyname(STDIN_FILENO); 215 if (ttyn == NULL || *ttyn == '\0') { 216 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 217 ttyn = tname; 218 } 219 if ((tty = strrchr(ttyn, '/'))) 220 ++tty; 221 else 222 tty = ttyn; 223 224 for (cnt = 0;; ask = 1) { 225 #if defined(KERBEROS) || defined(KERBEROS5) 226 kdestroy(); 227 authok = 0; 228 #endif 229 if (ask) { 230 fflag = 0; 231 getloginname(); 232 } 233 rootlogin = 0; 234 235 #if defined(KERBEROS) || defined(KERBEROS5) 236 /* 237 * Why should anyone with a root instance be able 238 * to be root here? 239 */ 240 instance = ""; 241 #endif 242 #ifdef KERBEROS 243 if ((instance = strchr(username, '.')) != NULL) { 244 if (strncmp(instance, ".root", 5) == 0) 245 rootlogin = 1; 246 *instance++ = '\0'; 247 } else 248 instance = ""; 249 #endif 250 #ifdef KERBEROS5 251 if ((instance = strchr(username, '/')) != NULL) { 252 if (strncmp(instance, "/root", 5) == 0) 253 rootlogin = 1; 254 *instance++ = '\0'; 255 } else 256 instance = ""; 257 #endif 258 if (strlen(username) > UT_NAMESIZE) 259 username[UT_NAMESIZE] = '\0'; 260 261 /* 262 * Note if trying multiple user names; log failures for 263 * previous user name, but don't bother logging one failure 264 * for nonexistent name (mistyped username). 265 */ 266 if (failures && strcmp(tbuf, username)) { 267 if (failures > (pwd ? 0 : 1)) 268 badlogin(tbuf); 269 failures = 0; 270 } 271 (void)strlcpy(tbuf, username, sizeof tbuf); 272 273 if ((pwd = getpwnam(username))) 274 salt = pwd->pw_passwd; 275 else 276 salt = "xx"; 277 lc = login_getclass(pwd ? pwd->pw_class : LOGIN_DEFCLASS); 278 if (!lc) 279 err(1, "unable to get login class"); 280 281 /* 282 * If we have a valid account name, and it doesn't have a 283 * password, or the -f option was specified and the caller 284 * is root or the caller isn't changing their uid, don't 285 * authenticate. 286 */ 287 if (pwd) { 288 if (pwd->pw_uid == 0) 289 rootlogin = 1; 290 291 if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 292 /* already authenticated */ 293 break; 294 } else if (pwd->pw_passwd[0] == '\0') { 295 /* pretend password okay */ 296 rval = 0; 297 #if defined(KERBEROS) || defined(KERBEROS5) 298 authok = 1; 299 #endif 300 goto ttycheck; 301 } 302 } 303 304 fflag = 0; 305 306 (void)setpriority(PRIO_PROCESS, 0, -4); 307 308 p = getpass("Password:"); 309 310 if (pwd) { 311 #if defined(KERBEROS) || defined(KERBEROS5) 312 rval = klogin(pwd, instance, localhost, p); 313 if (rval != 0 && rootlogin && pwd->pw_uid != 0) 314 rootlogin = 0; 315 if (rval == 1) { 316 /* Fall back on password file. */ 317 if (pwd->pw_uid != 0) 318 rootlogin = 0; 319 rval = pwcheck(username, p, salt, pwd->pw_passwd); 320 } 321 if (rval == 0) 322 authok = 1; 323 #else 324 rval = pwcheck(username, p, salt, pwd->pw_passwd); 325 #endif 326 } else { 327 #ifdef SKEY 328 if (strcasecmp(p, "s/key") == 0) 329 (void)skey_authenticate(username); 330 else 331 #endif 332 { 333 useconds_t us; 334 335 /* 336 * Sleep between 1 and 3 seconds 337 * to emulate a crypt. 338 */ 339 us = arc4random() % 3000000; 340 usleep(us); 341 } 342 rval = 1; 343 } 344 memset(p, 0, strlen(p)); 345 346 (void)setpriority(PRIO_PROCESS, 0, 0); 347 348 ttycheck: 349 /* 350 * If trying to log in as root without Kerberos, 351 * but with insecure terminal, refuse the login attempt. 352 */ 353 #if defined(KERBEROS) || defined(KERBEROS5) 354 if (authok == 1) 355 #endif 356 /* if logging in as root, user must be on a secure tty */ 357 if (pwd && rval == 0 && (!rootlogin || rootterm(tty))) 358 break; 359 360 /* 361 * We don't want to give out info to an attacker trying 362 * to guess root's password so we always say "login refused" 363 * in that case, not "Login incorrect". 364 */ 365 if (rootlogin && !rootterm(tty)) { 366 (void)fprintf(stderr, 367 "%s login refused on this terminal.\n", 368 pwd ? pwd->pw_name : "root"); 369 if (hostname) 370 syslog(LOG_NOTICE, 371 "LOGIN %s REFUSED FROM %s%s%s ON TTY %s", 372 pwd ? pwd->pw_name : "root", 373 rusername ? rusername : "", 374 rusername ? "@" : "", hostname, tty); 375 else 376 syslog(LOG_NOTICE, 377 "LOGIN %s REFUSED ON TTY %s", 378 pwd ? pwd->pw_name : "root", tty); 379 } else 380 (void)printf("Login incorrect\n"); 381 failures++; 382 if (pwd) 383 log_failedlogin(pwd->pw_uid, hostname, rusername, tty); 384 /* we allow 10 tries, but after 3 we start backing off */ 385 if (++cnt > 3) { 386 if (cnt >= 10) { 387 badlogin(username); 388 sleepexit(1); 389 } 390 sleep((u_int)((cnt - 3) * 5)); 391 } 392 } 393 394 /* committed to login -- turn off timeout */ 395 (void)alarm((u_int)0); 396 397 endpwent(); 398 399 /* if user not super-user, check for disabled logins */ 400 if (!rootlogin) 401 checknologin(); 402 403 setegid(pwd->pw_gid); 404 seteuid(pwd->pw_uid); 405 406 if (chdir(pwd->pw_dir) < 0) { 407 (void)printf("No home directory %s!\n", pwd->pw_dir); 408 if (login_getcapbool(lc, "requirehome", 0)) 409 exit(1); 410 if (chdir("/")) 411 exit(0); 412 pwd->pw_dir = "/"; 413 (void)printf("Logging in with home = \"/\".\n"); 414 } 415 416 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 417 if (*shell == '\0') 418 shell = _PATH_BSHELL; 419 else if (strlen(shell) >= MAXPATHLEN) { 420 syslog(LOG_ERR, "shell path too long: %s", shell); 421 warnx("invalid shell"); 422 sleepexit(1); 423 } 424 425 quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) || 426 login_getcapbool(lc, "hushlogin", 0) || 427 (access(_PATH_HUSHLOGIN, F_OK) == 0)); 428 429 seteuid(0); 430 setegid(0); /* XXX use a saved gid instead? */ 431 432 if (pwd->pw_change || pwd->pw_expire) 433 (void)gettimeofday(&tp, (struct timezone *)NULL); 434 if (pwd->pw_expire) { 435 if (tp.tv_sec >= pwd->pw_expire) { 436 (void)printf("Sorry -- your account has expired.\n"); 437 sleepexit(1); 438 } else if (!quietlog &&pwd->pw_expire - tp.tv_sec < 439 login_getcaptime(lc, "expire-warn", 440 2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY)) 441 (void)printf("Warning: your account expires on %s", 442 ctime(&pwd->pw_expire)); 443 } 444 if (pwd->pw_change) { 445 if (tp.tv_sec >= pwd->pw_change) { 446 (void)printf("Sorry -- your password has expired.\n"); 447 sleepexit(1); 448 } else if (!quietlog && pwd->pw_change - tp.tv_sec < 449 login_getcaptime(lc, "password-warn", 450 2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY)) 451 (void)printf("Warning: your password expires on %s", 452 ctime(&pwd->pw_change)); 453 } 454 455 /* Nothing else left to fail -- really log in. */ 456 (void)signal(SIGHUP, SIG_DFL); 457 memset((void *)&utmp, 0, sizeof(utmp)); 458 (void)time(&utmp.ut_time); 459 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 460 if (hostname) 461 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 462 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 463 login(&utmp); 464 465 if (!quietlog) 466 (void)check_failedlogin(pwd->pw_uid); 467 dolastlog(quietlog); 468 469 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 470 471 (void)chown(ttyn, pwd->pw_uid, 472 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 473 #if defined(KERBEROS) || defined(KERBEROS5) 474 /* Fork so that we can call kdestroy */ 475 if (krbtkfile_env) 476 dofork(); 477 #endif 478 479 /* Destroy environment unless user has requested its preservation. */ 480 if (!pflag) { 481 if ((environ = calloc(1, sizeof (char *))) == NULL) 482 err(1, "calloc"); 483 } else { 484 char **cpp, **cpp2; 485 486 for (cpp2 = cpp = environ; *cpp; cpp++) { 487 if (strncmp(*cpp, "LD_", 3) && 488 strncmp(*cpp, "ENV=", 4) && 489 strncmp(*cpp, "BASH_ENV=", 9) && 490 strncmp(*cpp, "IFS=", 4)) 491 *cpp2++ = *cpp; 492 } 493 *cpp2 = 0; 494 } 495 /* Note: setusercontext(3) will set PATH */ 496 if (setenv("HOME", pwd->pw_dir, 1) == -1 || 497 setenv("SHELL", shell, 1) == -1) { 498 warn("unable to setenv()"); 499 exit(1); 500 } 501 if (term[0] == '\0') 502 (void)strlcpy(term, stypeof(tty), sizeof(term)); 503 if (setenv("TERM", term, 0) == -1 || 504 setenv("LOGNAME", pwd->pw_name, 1) == -1 || 505 setenv("USER", pwd->pw_name, 1) == -1) { 506 warn("unable to setenv()"); 507 exit(1); 508 } 509 if (hostname) { 510 if (setenv("REMOTEHOST", hostname, 1) == -1) { 511 warn("unable to setenv()"); 512 exit(1); 513 } 514 } 515 if (rusername) { 516 if (setenv("REMOTEUSER", rusername, 1) == -1) { 517 warn("unable to setenv()"); 518 exit(1); 519 } 520 } 521 #ifdef KERBEROS 522 if (krbtkfile_env) { 523 if (setenv("KRBTKFILE", krbtkfile_env, 1) == -1) { 524 warn("unable to setenv()"); 525 exit(1); 526 } 527 } 528 #endif 529 #ifdef KERBEROS5 530 if (krbtkfile_env) { 531 if (setenv("KRB5CCNAME", krbtkfile_env, 1) == -1) { 532 warn("unable to setenv()"); 533 exit(1); 534 } 535 } 536 #endif 537 /* If fflag is on, assume caller/authenticator has logged root login. */ 538 if (rootlogin && fflag == 0) { 539 if (hostname) 540 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s%s%s", 541 username, tty, rusername ? rusername : "", 542 rusername ? "@" : "", hostname); 543 else 544 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); 545 } 546 547 #if defined(KERBEROS) || defined(KERBEROS5) 548 if (!quietlog && notickets == 1) 549 (void)printf("Warning: no Kerberos tickets issued.\n"); 550 #endif 551 552 if (!quietlog) { 553 #if 0 554 (void)printf("%s\n\t%s %s\n\n", 555 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 556 "The Regents of the University of California. ", 557 "All rights reserved."); 558 #endif 559 motd(); 560 (void)snprintf(tbuf, 561 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 562 if (stat(tbuf, &st) == 0 && st.st_size != 0) 563 (void)printf("You have %smail.\n", 564 (st.st_mtime > st.st_atime) ? "new " : ""); 565 } 566 567 (void)signal(SIGALRM, SIG_DFL); 568 (void)signal(SIGQUIT, SIG_DFL); 569 (void)signal(SIGINT, SIG_DFL); 570 (void)signal(SIGTSTP, SIG_IGN); 571 572 tbuf[0] = '-'; 573 (void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ? 574 p + 1 : shell, sizeof tbuf - 1); 575 576 /* Discard permissions last so can't get killed and drop core. */ 577 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL)) { 578 warn("unable to set user context"); 579 exit(1); 580 } 581 582 #ifdef KERBEROS 583 kgettokens(pwd->pw_dir); 584 #endif 585 586 execlp(shell, tbuf, 0); 587 err(1, "%s", shell); 588 } 589 590 int 591 pwcheck(user, p, salt, passwd) 592 char *user, *p, *salt, *passwd; 593 { 594 #ifdef SKEY 595 if (strcasecmp(p, "s/key") == 0) 596 return skey_authenticate(user); 597 #endif 598 return strcmp(crypt(p, salt), passwd); 599 } 600 601 #if defined(KERBEROS) || defined(KERBEROS5) 602 #define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ 603 #else 604 #define NBUFSIZ (UT_NAMESIZE + 1) 605 #endif 606 607 #if defined(KERBEROS) || defined(KERBEROS5) 608 /* 609 * This routine handles cleanup stuff, and the like. 610 * It exists only in the child process. 611 */ 612 #include <sys/wait.h> 613 void 614 dofork() 615 { 616 int child; 617 618 if (!(child = fork())) 619 return; /* Child process */ 620 621 /* Setup stuff? This would be things we could do in parallel with login */ 622 (void) chdir("/"); /* Let's not keep the fs busy... */ 623 624 /* If we're the parent, watch the child until it dies */ 625 while (wait(0) != child) 626 ; 627 628 /* Cleanup stuff */ 629 /* Run kdestroy to destroy tickets */ 630 kdestroy(); 631 632 /* Leave */ 633 exit(0); 634 } 635 #endif 636 637 void 638 getloginname() 639 { 640 int ch; 641 char *p; 642 static char nbuf[NBUFSIZ]; 643 644 for (;;) { 645 (void)printf("login: "); 646 for (p = nbuf; (ch = getchar()) != '\n'; ) { 647 if (ch == EOF) { 648 badlogin(username); 649 exit(0); 650 } 651 if (p < nbuf + (NBUFSIZ - 1)) 652 *p++ = ch; 653 } 654 if (p > nbuf) { 655 if (nbuf[0] == '-') 656 (void)fprintf(stderr, 657 "login names may not start with '-'.\n"); 658 else { 659 *p = '\0'; 660 username = nbuf; 661 break; 662 } 663 } 664 } 665 } 666 667 int 668 rootterm(ttyn) 669 char *ttyn; 670 { 671 struct ttyent *t; 672 673 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 674 } 675 676 jmp_buf motdinterrupt; 677 678 void 679 motd() 680 { 681 int fd, nchars; 682 sig_t oldint; 683 char tbuf[8192]; 684 char *motd; 685 686 motd = login_getcapstr(lc, "welcome", _PATH_MOTDFILE, _PATH_MOTDFILE); 687 688 if ((fd = open(motd, O_RDONLY, 0)) < 0) 689 return; 690 oldint = signal(SIGINT, sigint); 691 if (setjmp(motdinterrupt) == 0) 692 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 693 (void)write(fileno(stdout), tbuf, nchars); 694 (void)signal(SIGINT, oldint); 695 (void)close(fd); 696 } 697 698 /* ARGSUSED */ 699 void 700 sigint(signo) 701 int signo; 702 { 703 longjmp(motdinterrupt, 1); 704 } 705 706 /* ARGSUSED */ 707 void 708 timedout(signo) 709 int signo; 710 { 711 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 712 exit(0); 713 } 714 715 void 716 checknologin() 717 { 718 int fd, nchars; 719 char *nologin; 720 char tbuf[8192]; 721 722 if (!login_getcapbool(lc, "ignorenologin", 0)) { 723 nologin = login_getcapstr(lc, "nologin", _PATH_NOLOGIN, 724 _PATH_NOLOGIN); 725 if ((fd = open(nologin, O_RDONLY, 0)) >= 0) { 726 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 727 (void)write(fileno(stdout), tbuf, nchars); 728 sleepexit(0); 729 } 730 } 731 } 732 733 void 734 dolastlog(quiet) 735 int quiet; 736 { 737 struct lastlog ll; 738 int fd; 739 740 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 741 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); 742 if (!quiet) { 743 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 744 ll.ll_time != 0) { 745 (void)printf("Last login: %.*s ", 746 24-5, (char *)ctime(&ll.ll_time)); 747 (void)printf("on %.*s", 748 (int)sizeof(ll.ll_line), 749 ll.ll_line); 750 if (*ll.ll_host != '\0') 751 (void)printf(" from %.*s", 752 (int)sizeof(ll.ll_host), 753 ll.ll_host); 754 (void)putchar('\n'); 755 } 756 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), 757 SEEK_SET); 758 } 759 memset((void *)&ll, 0, sizeof(ll)); 760 (void)time(&ll.ll_time); 761 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 762 if (hostname) 763 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 764 (void)write(fd, (char *)&ll, sizeof(ll)); 765 (void)close(fd); 766 } 767 } 768 769 void 770 badlogin(name) 771 char *name; 772 { 773 if (failures == 0) 774 return; 775 if (hostname) { 776 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s%s%s", 777 failures, failures > 1 ? "S" : "", 778 rusername ? rusername : "", rusername ? "@" : "", hostname); 779 syslog(LOG_AUTHPRIV|LOG_NOTICE, 780 "%d LOGIN FAILURE%s FROM %s%s%s, %s", 781 failures, failures > 1 ? "S" : "", 782 rusername ? rusername : "", rusername ? "@" : "", 783 hostname, name); 784 } else { 785 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 786 failures, failures > 1 ? "S" : "", tty); 787 syslog(LOG_AUTHPRIV|LOG_NOTICE, 788 "%d LOGIN FAILURE%s ON %s, %s", 789 failures, failures > 1 ? "S" : "", tty, name); 790 } 791 } 792 793 #undef UNKNOWN 794 #define UNKNOWN "su" 795 796 char * 797 stypeof(ttyid) 798 char *ttyid; 799 { 800 struct ttyent *t; 801 802 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : 803 login_getcapstr(lc, "term", UNKNOWN, UNKNOWN)); 804 } 805 806 void 807 sleepexit(eval) 808 int eval; 809 { 810 (void)sleep(5); 811 exit(eval); 812 } 813 814 void 815 sighup(signum) 816 int signum; 817 { 818 if (username) 819 badlogin(username); 820 exit(0); 821 } 822