1 /* $NetBSD: login.c,v 1.71 2002/11/16 04:38:45 itojun Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __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 __RCSID("$NetBSD: login.c,v 1.71 2002/11/16 04:38:45 itojun 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/file.h> 61 #include <sys/wait.h> 62 #include <sys/socket.h> 63 64 #include <err.h> 65 #include <errno.h> 66 #include <grp.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 <time.h> 75 #include <ttyent.h> 76 #include <tzfile.h> 77 #include <unistd.h> 78 #ifdef SUPPORT_UTMP 79 #include <utmp.h> 80 #endif 81 #ifdef SUPPORT_UTMPX 82 #include <utmpx.h> 83 #endif 84 #include <util.h> 85 #ifdef SKEY 86 #include <skey.h> 87 #endif 88 #ifdef KERBEROS5 89 #include <krb5/krb5.h> 90 #include <com_err.h> 91 #endif 92 #ifdef LOGIN_CAP 93 #include <login_cap.h> 94 #endif 95 96 #include "pathnames.h" 97 98 #ifdef KERBEROS5 99 int login_krb5_get_tickets = 1; 100 int login_krb4_get_tickets = 0; 101 int login_krb5_forwardable_tgt = 0; 102 int login_krb5_retain_ccache = 0; 103 #endif 104 105 void badlogin __P((char *)); 106 void checknologin __P((char *)); 107 #ifdef SUPPORT_UTMP 108 static void doutmp __P((void)); 109 static void dolastlog __P((int)); 110 #endif 111 #ifdef SUPPORT_UTMPX 112 static void doutmpx __P((void)); 113 static void dolastlogx __P((int)); 114 #endif 115 static void update_db __P((int)); 116 void getloginname __P((void)); 117 int main __P((int, char *[])); 118 void motd __P((char *)); 119 int rootterm __P((char *)); 120 void sigint __P((int)); 121 void sleepexit __P((int)); 122 const char *stypeof __P((const char *)); 123 void timedout __P((int)); 124 #if defined(KERBEROS) 125 int klogin __P((struct passwd *, char *, char *, char *)); 126 void kdestroy __P((void)); 127 #endif 128 #ifdef KERBEROS5 129 int k5login __P((struct passwd *, char *, char *, char *)); 130 void k5destroy __P((void)); 131 int k5_read_creds __P((char*)); 132 int k5_write_creds __P((void)); 133 #endif 134 #if defined(KERBEROS) || defined(KERBEROS5) 135 void dofork __P((void)); 136 #endif 137 138 #define TTYGRPNAME "tty" /* name of group to own ttys */ 139 140 #define DEFAULT_BACKOFF 3 141 #define DEFAULT_RETRIES 10 142 143 /* 144 * This bounds the time given to login. Not a define so it can 145 * be patched on machines where it's too small. 146 */ 147 u_int timeout = 300; 148 149 #if defined(KERBEROS) || defined(KERBEROS5) 150 int notickets = 1; 151 char *instance; 152 int has_ccache = 0; 153 #endif 154 #ifdef KERBEROS 155 extern char *krbtkfile_env; 156 extern int krb_configured; 157 #endif 158 #ifdef KERBEROS5 159 extern krb5_context kcontext; 160 extern int have_forward; 161 extern char *krb5tkfile_env; 162 extern int krb5_configured; 163 #endif 164 165 #if defined(KERBEROS) && defined(KERBEROS5) 166 #define KERBEROS_CONFIGURED (krb_configured || krb5_configured) 167 #elif defined(KERBEROS) 168 #define KERBEROS_CONFIGURED krb_configured 169 #elif defined(KERBEROS5) 170 #define KERBEROS_CONFIGURED krb5_configured 171 #endif 172 173 struct passwd *pwd; 174 int failures; 175 char term[64], *envinit[1], *hostname, *username, *tty, *nested; 176 struct timeval now; 177 struct sockaddr_storage ss; 178 179 static const char copyrightstr[] = "\ 180 Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002\n\ 181 \tThe NetBSD Foundation, Inc. All rights reserved.\n\ 182 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994\n\ 183 \tThe Regents of the University of California. All rights reserved.\n\n"; 184 185 int 186 main(argc, argv) 187 int argc; 188 char *argv[]; 189 { 190 extern char **environ; 191 struct group *gr; 192 struct stat st; 193 int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval; 194 int Fflag; 195 uid_t uid, saved_uid; 196 gid_t saved_gid, saved_gids[NGROUPS_MAX]; 197 int nsaved_gids; 198 char *domain, *p, *ttyn, *pwprompt; 199 const char *salt; 200 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 201 char localhost[MAXHOSTNAMELEN + 1]; 202 int need_chpass, require_chpass; 203 int login_retries = DEFAULT_RETRIES, 204 login_backoff = DEFAULT_BACKOFF; 205 time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY; 206 #ifdef KERBEROS5 207 krb5_error_code kerror; 208 #endif 209 #if defined(KERBEROS) || defined(KERBEROS5) 210 int got_tickets = 0; 211 #endif 212 #ifdef LOGIN_CAP 213 char *shell = NULL; 214 login_cap_t *lc = NULL; 215 #endif 216 217 tbuf[0] = '\0'; 218 rval = 0; 219 pwprompt = NULL; 220 nested = NULL; 221 need_chpass = require_chpass = 0; 222 223 (void)signal(SIGALRM, timedout); 224 (void)alarm(timeout); 225 (void)signal(SIGQUIT, SIG_IGN); 226 (void)signal(SIGINT, SIG_IGN); 227 (void)setpriority(PRIO_PROCESS, 0, 0); 228 229 openlog("login", 0, LOG_AUTH); 230 231 /* 232 * -p is used by getty to tell login not to destroy the environment 233 * -f is used to skip a second login authentication 234 * -h is used by other servers to pass the name of the remote host to 235 * login so that it may be placed in utmp/utmpx and wtmp/wtmpx 236 * -s is used to force use of S/Key or equivalent. 237 */ 238 domain = NULL; 239 if (gethostname(localhost, sizeof(localhost)) < 0) 240 syslog(LOG_ERR, "couldn't get local hostname: %m"); 241 else 242 domain = strchr(localhost, '.'); 243 localhost[sizeof(localhost) - 1] = '\0'; 244 245 Fflag = fflag = hflag = pflag = sflag = 0; 246 #ifdef KERBEROS5 247 have_forward = 0; 248 #endif 249 uid = getuid(); 250 while ((ch = getopt(argc, argv, "Ffh:ps")) != -1) 251 switch (ch) { 252 case 'F': 253 Fflag = 1; 254 /* FALLTHROUGH */ 255 case 'f': 256 fflag = 1; 257 break; 258 case 'h': 259 if (uid) 260 errx(1, "-h option: %s", strerror(EPERM)); 261 hflag = 1; 262 if (domain && (p = strchr(optarg, '.')) != NULL && 263 strcasecmp(p, domain) == 0) 264 *p = 0; 265 hostname = optarg; 266 break; 267 case 'p': 268 pflag = 1; 269 break; 270 case 's': 271 sflag = 1; 272 break; 273 default: 274 case '?': 275 (void)fprintf(stderr, 276 "usage: login [-fps] [-h hostname] [username]\n"); 277 exit(1); 278 } 279 argc -= optind; 280 argv += optind; 281 282 if (*argv) { 283 username = *argv; 284 ask = 0; 285 } else 286 ask = 1; 287 288 for (cnt = getdtablesize(); cnt > 2; cnt--) 289 (void)close(cnt); 290 291 ttyn = ttyname(STDIN_FILENO); 292 if (ttyn == NULL || *ttyn == '\0') { 293 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 294 ttyn = tname; 295 } 296 if ((tty = strrchr(ttyn, '/')) != NULL) 297 ++tty; 298 else 299 tty = ttyn; 300 301 if (issetugid()) { 302 nested = strdup(user_from_uid(getuid(), 0)); 303 if (nested == NULL) { 304 syslog(LOG_ERR, "strdup: %m"); 305 sleepexit(1); 306 } 307 } 308 309 #ifdef LOGIN_CAP 310 /* Get "login-retries" and "login-backoff" from default class */ 311 if ((lc = login_getclass(NULL)) != NULL) { 312 login_retries = (int)login_getcapnum(lc, "login-retries", 313 DEFAULT_RETRIES, DEFAULT_RETRIES); 314 login_backoff = (int)login_getcapnum(lc, "login-backoff", 315 DEFAULT_BACKOFF, DEFAULT_BACKOFF); 316 login_close(lc); 317 lc = NULL; 318 } 319 #endif 320 321 #ifdef KERBEROS5 322 kerror = krb5_init_context(&kcontext); 323 if (kerror) { 324 /* 325 * If Kerberos is not configured, that is, we are 326 * not using Kerberos, do not log the error message. 327 * However, if Kerberos is configured, and the 328 * context init fails for some other reason, we need 329 * to issue a no tickets warning to the user when the 330 * login succeeds. 331 */ 332 if (kerror != ENXIO) { /* XXX NetBSD-local Heimdal hack */ 333 syslog(LOG_NOTICE, 334 "%s when initializing Kerberos context", 335 error_message(kerror)); 336 krb5_configured = 1; 337 } 338 login_krb5_get_tickets = 0; 339 } 340 #endif /* KERBEROS5 */ 341 342 for (cnt = 0;; ask = 1) { 343 #if defined(KERBEROS) 344 kdestroy(); 345 #endif 346 #if defined(KERBEROS5) 347 if (login_krb5_get_tickets) 348 k5destroy(); 349 #endif 350 if (ask) { 351 fflag = 0; 352 getloginname(); 353 } 354 rootlogin = 0; 355 #ifdef KERBEROS 356 if ((instance = strchr(username, '.')) != NULL) 357 *instance++ = '\0'; 358 else 359 instance = ""; 360 #endif 361 #ifdef KERBEROS5 362 if ((instance = strchr(username, '/')) != NULL) 363 *instance++ = '\0'; 364 else 365 instance = ""; 366 #endif 367 if (strlen(username) > MAXLOGNAME) 368 username[MAXLOGNAME] = '\0'; 369 370 /* 371 * Note if trying multiple user names; log failures for 372 * previous user name, but don't bother logging one failure 373 * for nonexistent name (mistyped username). 374 */ 375 if (failures && strcmp(tbuf, username)) { 376 if (failures > (pwd ? 0 : 1)) 377 badlogin(tbuf); 378 failures = 0; 379 } 380 (void)strlcpy(tbuf, username, sizeof(tbuf)); 381 382 if ((pwd = getpwnam(username)) != NULL) 383 salt = pwd->pw_passwd; 384 else 385 salt = "xx"; 386 387 #ifdef LOGIN_CAP 388 /* 389 * Establish the class now, before we might goto 390 * within the next block. pwd can be NULL since it 391 * falls back to the "default" class if it is. 392 */ 393 lc = login_getclass(pwd ? pwd->pw_class : NULL); 394 #endif 395 /* 396 * if we have a valid account name, and it doesn't have a 397 * password, or the -f option was specified and the caller 398 * is root or the caller isn't changing their uid, don't 399 * authenticate. 400 */ 401 if (pwd) { 402 if (pwd->pw_uid == 0) 403 rootlogin = 1; 404 405 if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 406 /* already authenticated */ 407 #ifdef KERBEROS5 408 if (login_krb5_get_tickets && Fflag) 409 k5_read_creds(username); 410 #endif 411 break; 412 } else if (pwd->pw_passwd[0] == '\0') { 413 /* pretend password okay */ 414 rval = 0; 415 goto ttycheck; 416 } 417 } 418 419 fflag = 0; 420 421 (void)setpriority(PRIO_PROCESS, 0, -4); 422 423 #ifdef SKEY 424 if (skey_haskey(username) == 0) { 425 static char skprompt[80]; 426 const char *skinfo = skey_keyinfo(username); 427 428 (void)snprintf(skprompt, sizeof(skprompt)-1, 429 "Password [%s]:", 430 skinfo ? skinfo : "error getting challenge"); 431 pwprompt = skprompt; 432 } else 433 #endif 434 pwprompt = "Password:"; 435 436 p = getpass(pwprompt); 437 438 if (pwd == NULL) { 439 rval = 1; 440 goto skip; 441 } 442 #ifdef KERBEROS 443 if ( 444 #ifdef KERBEROS5 445 /* allow a user to get both krb4 and krb5 tickets, if 446 * desired. If krb5 is compiled in, the default action 447 * is to ignore krb4 and get krb5 tickets, but the user 448 * can override this in the krb5.conf. */ 449 login_krb4_get_tickets && 450 #endif 451 klogin(pwd, instance, localhost, p) == 0) { 452 rval = 0; 453 got_tickets = 1; 454 } 455 #endif 456 #ifdef KERBEROS5 457 if (login_krb5_get_tickets && 458 k5login(pwd, instance, localhost, p) == 0) { 459 rval = 0; 460 got_tickets = 1; 461 } 462 #endif 463 #if defined(KERBEROS) || defined(KERBEROS5) 464 if (got_tickets) 465 goto skip; 466 #endif 467 #ifdef SKEY 468 if (skey_haskey(username) == 0 && 469 skey_passcheck(username, p) != -1) { 470 rval = 0; 471 goto skip; 472 } 473 #endif 474 if (!sflag && *pwd->pw_passwd != '\0' && 475 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) { 476 rval = 0; 477 require_chpass = 1; 478 goto skip; 479 } 480 rval = 1; 481 482 skip: 483 memset(p, 0, strlen(p)); 484 485 (void)setpriority(PRIO_PROCESS, 0, 0); 486 487 ttycheck: 488 /* 489 * If trying to log in as root without Kerberos, 490 * but with insecure terminal, refuse the login attempt. 491 */ 492 if (pwd && !rval && rootlogin && !rootterm(tty)) { 493 (void)fprintf(stderr, 494 "%s login refused on this terminal.\n", 495 pwd->pw_name); 496 if (hostname) 497 syslog(LOG_NOTICE, 498 "LOGIN %s REFUSED FROM %s ON TTY %s", 499 pwd->pw_name, hostname, tty); 500 else 501 syslog(LOG_NOTICE, 502 "LOGIN %s REFUSED ON TTY %s", 503 pwd->pw_name, tty); 504 continue; 505 } 506 507 if (pwd && !rval) 508 break; 509 510 (void)printf("Login incorrect\n"); 511 failures++; 512 cnt++; 513 /* we allow 10 tries, but after 3 we start backing off */ 514 if (cnt > login_backoff) { 515 if (cnt >= login_retries) { 516 badlogin(username); 517 sleepexit(1); 518 } 519 sleep((u_int)((cnt - 3) * 5)); 520 } 521 } 522 523 /* committed to login -- turn off timeout */ 524 (void)alarm((u_int)0); 525 526 endpwent(); 527 528 /* if user not super-user, check for disabled logins */ 529 #ifdef LOGIN_CAP 530 if (!login_getcapbool(lc, "ignorenologin", rootlogin)) 531 checknologin(login_getcapstr(lc, "nologin", NULL, NULL)); 532 #else 533 if (!rootlogin) 534 checknologin(NULL); 535 #endif 536 537 #ifdef LOGIN_CAP 538 quietlog = login_getcapbool(lc, "hushlogin", 0); 539 #else 540 quietlog = 0; 541 #endif 542 /* Temporarily give up special privileges so we can change */ 543 /* into NFS-mounted homes that are exported for non-root */ 544 /* access and have mode 7x0 */ 545 saved_uid = geteuid(); 546 saved_gid = getegid(); 547 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids); 548 549 (void)setegid(pwd->pw_gid); 550 initgroups(username, pwd->pw_gid); 551 (void)seteuid(pwd->pw_uid); 552 553 if (chdir(pwd->pw_dir) < 0) { 554 #ifdef LOGIN_CAP 555 if (login_getcapbool(lc, "requirehome", 0)) { 556 (void)printf("Home directory %s required\n", 557 pwd->pw_dir); 558 sleepexit(1); 559 } 560 #endif 561 (void)printf("No home directory %s!\n", pwd->pw_dir); 562 if (chdir("/")) 563 exit(0); 564 pwd->pw_dir = "/"; 565 (void)printf("Logging in with home = \"/\".\n"); 566 } 567 568 if (!quietlog) 569 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 570 571 /* regain special privileges */ 572 (void)seteuid(saved_uid); 573 setgroups(nsaved_gids, saved_gids); 574 (void)setegid(saved_gid); 575 576 #ifdef LOGIN_CAP 577 pw_warntime = login_getcaptime(lc, "password-warn", 578 _PASSWORD_WARNDAYS * SECSPERDAY, 579 _PASSWORD_WARNDAYS * SECSPERDAY); 580 #endif 581 582 (void)gettimeofday(&now, (struct timezone *)NULL); 583 if (pwd->pw_expire) { 584 if (now.tv_sec >= pwd->pw_expire) { 585 (void)printf("Sorry -- your account has expired.\n"); 586 sleepexit(1); 587 } else if (pwd->pw_expire - now.tv_sec < pw_warntime && 588 !quietlog) 589 (void)printf("Warning: your account expires on %s", 590 ctime(&pwd->pw_expire)); 591 } 592 if (pwd->pw_change) { 593 if (pwd->pw_change == _PASSWORD_CHGNOW) 594 need_chpass = 1; 595 else if (now.tv_sec >= pwd->pw_change) { 596 (void)printf("Sorry -- your password has expired.\n"); 597 sleepexit(1); 598 } else if (pwd->pw_change - now.tv_sec < pw_warntime && 599 !quietlog) 600 (void)printf("Warning: your password expires on %s", 601 ctime(&pwd->pw_change)); 602 603 } 604 /* Nothing else left to fail -- really log in. */ 605 update_db(quietlog); 606 607 (void)chown(ttyn, pwd->pw_uid, 608 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 609 610 if (ttyaction(ttyn, "login", pwd->pw_name)) 611 (void)printf("Warning: ttyaction failed.\n"); 612 613 #if defined(KERBEROS) || defined(KERBEROS5) 614 /* Fork so that we can call kdestroy */ 615 if ( 616 #ifdef KERBEROS5 617 ! login_krb5_retain_ccache && 618 #endif 619 has_ccache) 620 dofork(); 621 #endif 622 623 /* Destroy environment unless user has requested its preservation. */ 624 if (!pflag) 625 environ = envinit; 626 627 #ifdef LOGIN_CAP 628 if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid, 629 LOGIN_SETLOGIN) != 0) { 630 syslog(LOG_ERR, "setusercontext failed"); 631 exit(1); 632 } 633 if (setusercontext(lc, pwd, pwd->pw_uid, 634 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) { 635 syslog(LOG_ERR, "setusercontext failed"); 636 exit(1); 637 } 638 #else 639 (void)setgid(pwd->pw_gid); 640 641 initgroups(username, pwd->pw_gid); 642 643 if (nested == NULL && setlogin(pwd->pw_name) < 0) 644 syslog(LOG_ERR, "setlogin() failure: %m"); 645 646 /* Discard permissions last so can't get killed and drop core. */ 647 if (rootlogin) 648 (void)setuid(0); 649 else 650 (void)setuid(pwd->pw_uid); 651 #endif 652 653 if (*pwd->pw_shell == '\0') 654 pwd->pw_shell = _PATH_BSHELL; 655 #ifdef LOGIN_CAP 656 if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) { 657 if ((shell = strdup(shell)) == NULL) { 658 syslog(LOG_ERR, "Cannot alloc mem"); 659 sleepexit(1); 660 } 661 pwd->pw_shell = shell; 662 } 663 #endif 664 665 (void)setenv("HOME", pwd->pw_dir, 1); 666 (void)setenv("SHELL", pwd->pw_shell, 1); 667 if (term[0] == '\0') { 668 char *tt = (char *)stypeof(tty); 669 #ifdef LOGIN_CAP 670 if (tt == NULL) 671 tt = login_getcapstr(lc, "term", NULL, NULL); 672 #endif 673 /* unknown term -> "su" */ 674 (void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term)); 675 } 676 (void)setenv("TERM", term, 0); 677 (void)setenv("LOGNAME", pwd->pw_name, 1); 678 (void)setenv("USER", pwd->pw_name, 1); 679 680 #ifdef LOGIN_CAP 681 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH); 682 #else 683 (void)setenv("PATH", _PATH_DEFPATH, 0); 684 #endif 685 686 #ifdef KERBEROS 687 if (krbtkfile_env) 688 (void)setenv("KRBTKFILE", krbtkfile_env, 1); 689 #endif 690 #ifdef KERBEROS5 691 if (krb5tkfile_env) 692 (void)setenv("KRB5CCNAME", krb5tkfile_env, 1); 693 #endif 694 695 if (tty[sizeof("tty")-1] == 'd') 696 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 697 698 /* If fflag is on, assume caller/authenticator has logged root login. */ 699 if (rootlogin && fflag == 0) { 700 if (hostname) 701 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 702 username, tty, hostname); 703 else 704 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 705 username, tty); 706 } 707 708 #if defined(KERBEROS) || defined(KERBEROS5) 709 if (KERBEROS_CONFIGURED && !quietlog && notickets == 1) 710 (void)printf("Warning: no Kerberos tickets issued.\n"); 711 #endif 712 713 if (!quietlog) { 714 char *fname; 715 #ifdef LOGIN_CAP 716 fname = login_getcapstr(lc, "copyright", NULL, NULL); 717 if (fname != NULL && access(fname, F_OK) == 0) 718 motd(fname); 719 else 720 #endif 721 (void)printf("%s", copyrightstr); 722 723 #ifdef LOGIN_CAP 724 fname = login_getcapstr(lc, "welcome", NULL, NULL); 725 if (fname == NULL || access(fname, F_OK) != 0) 726 #endif 727 fname = _PATH_MOTDFILE; 728 motd(fname); 729 730 (void)snprintf(tbuf, 731 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 732 if (stat(tbuf, &st) == 0 && st.st_size != 0) 733 (void)printf("You have %smail.\n", 734 (st.st_mtime > st.st_atime) ? "new " : ""); 735 } 736 737 #ifdef LOGIN_CAP 738 login_close(lc); 739 #endif 740 741 (void)signal(SIGALRM, SIG_DFL); 742 (void)signal(SIGQUIT, SIG_DFL); 743 (void)signal(SIGINT, SIG_DFL); 744 (void)signal(SIGTSTP, SIG_IGN); 745 746 tbuf[0] = '-'; 747 (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 748 p + 1 : pwd->pw_shell, sizeof(tbuf) - 1); 749 750 /* Wait to change password until we're unprivileged */ 751 if (need_chpass) { 752 if (!require_chpass) 753 (void)printf( 754 "Warning: your password has expired. Please change it as soon as possible.\n"); 755 else { 756 int status; 757 758 (void)printf( 759 "Your password has expired. Please choose a new one.\n"); 760 switch (fork()) { 761 case -1: 762 warn("fork"); 763 sleepexit(1); 764 case 0: 765 execl(_PATH_BINPASSWD, "passwd", 0); 766 _exit(1); 767 default: 768 if (wait(&status) == -1 || 769 WEXITSTATUS(status)) 770 sleepexit(1); 771 } 772 } 773 } 774 775 #ifdef KERBEROS5 776 if (login_krb5_get_tickets) 777 k5_write_creds(); 778 #endif 779 execlp(pwd->pw_shell, tbuf, 0); 780 err(1, "%s", pwd->pw_shell); 781 } 782 783 #if defined(KERBEROS) || defined(KERBEROS5) 784 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */ 785 #else 786 #define NBUFSIZ (MAXLOGNAME + 1) 787 #endif 788 789 #if defined(KERBEROS) || defined(KERBEROS5) 790 /* 791 * This routine handles cleanup stuff, and the like. 792 * It exists only in the child process. 793 */ 794 #include <sys/wait.h> 795 void 796 dofork() 797 { 798 int child; 799 800 if (!(child = fork())) 801 return; /* Child process */ 802 803 /* 804 * Setup stuff? This would be things we could do in parallel 805 * with login 806 */ 807 (void)chdir("/"); /* Let's not keep the fs busy... */ 808 809 /* If we're the parent, watch the child until it dies */ 810 while (wait(0) != child) 811 ; 812 813 /* Cleanup stuff */ 814 /* Run kdestroy to destroy tickets */ 815 #ifdef KERBEROS 816 kdestroy(); 817 #endif 818 #ifdef KERBEROS5 819 if (login_krb5_get_tickets) 820 k5destroy(); 821 #endif 822 823 /* Leave */ 824 exit(0); 825 } 826 #endif 827 828 void 829 getloginname() 830 { 831 int ch; 832 char *p; 833 static char nbuf[NBUFSIZ]; 834 835 for (;;) { 836 (void)printf("login: "); 837 for (p = nbuf; (ch = getchar()) != '\n'; ) { 838 if (ch == EOF) { 839 badlogin(username); 840 exit(0); 841 } 842 if (p < nbuf + (NBUFSIZ - 1)) 843 *p++ = ch; 844 } 845 if (p > nbuf) { 846 if (nbuf[0] == '-') 847 (void)fprintf(stderr, 848 "login names may not start with '-'.\n"); 849 else { 850 *p = '\0'; 851 username = nbuf; 852 break; 853 } 854 } 855 } 856 } 857 858 int 859 rootterm(ttyn) 860 char *ttyn; 861 { 862 struct ttyent *t; 863 864 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 865 } 866 867 jmp_buf motdinterrupt; 868 869 void 870 motd(fname) 871 char *fname; 872 { 873 int fd, nchars; 874 sig_t oldint; 875 char tbuf[8192]; 876 877 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0) 878 return; 879 oldint = signal(SIGINT, sigint); 880 if (setjmp(motdinterrupt) == 0) 881 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 882 (void)write(fileno(stdout), tbuf, nchars); 883 (void)signal(SIGINT, oldint); 884 (void)close(fd); 885 } 886 887 /* ARGSUSED */ 888 void 889 sigint(signo) 890 int signo; 891 { 892 893 longjmp(motdinterrupt, 1); 894 } 895 896 /* ARGSUSED */ 897 void 898 timedout(signo) 899 int signo; 900 { 901 902 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 903 exit(0); 904 } 905 906 void 907 checknologin(fname) 908 char *fname; 909 { 910 int fd, nchars; 911 char tbuf[8192]; 912 913 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 914 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 915 (void)write(fileno(stdout), tbuf, nchars); 916 sleepexit(0); 917 } 918 } 919 920 static void 921 update_db(int quietlog) 922 { 923 if (nested != NULL) { 924 if (hostname != NULL) 925 syslog(LOG_NOTICE, "%s to %s on tty %s from %s", 926 nested, pwd->pw_name, tty, hostname); 927 else 928 syslog(LOG_NOTICE, "%s to %s on tty %s", nested, 929 pwd->pw_name, tty); 930 931 return; 932 } 933 if (hostname != NULL) { 934 socklen_t len = sizeof(ss); 935 (void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len); 936 } 937 (void)gettimeofday(&now, NULL); 938 #ifdef SUPPORT_UTMPX 939 doutmpx(); 940 dolastlogx(quietlog); 941 quietlog = 1; 942 #endif 943 #ifdef SUPPORT_UTMP 944 doutmp(); 945 dolastlog(quietlog); 946 #endif 947 } 948 949 #ifdef SUPPORT_UTMPX 950 static void 951 doutmpx() 952 { 953 struct utmpx utmpx; 954 char *t; 955 956 memset((void *)&utmpx, 0, sizeof(utmpx)); 957 utmpx.ut_tv = now; 958 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); 959 if (hostname) { 960 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); 961 utmpx.ut_ss = ss; 962 } 963 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); 964 utmpx.ut_type = USER_PROCESS; 965 utmpx.ut_pid = getpid(); 966 t = tty + strlen(tty); 967 if (t - tty >= sizeof(utmpx.ut_id)) { 968 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), 969 sizeof(utmpx.ut_id)); 970 } else { 971 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); 972 } 973 if (pututxline(&utmpx) == NULL) 974 syslog(LOG_NOTICE, "Cannot update utmpx %m"); 975 endutxent(); 976 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) 977 syslog(LOG_NOTICE, "Cannot update wtmpx %m"); 978 } 979 980 static void 981 dolastlogx(quiet) 982 int quiet; 983 { 984 struct lastlogx ll; 985 if (getlastlogx(pwd->pw_uid, &ll) != NULL) { 986 time_t t = (time_t)ll.ll_tv.tv_sec; 987 (void)printf("Last login: %.24s ", ctime(&t)); 988 if (*ll.ll_host != '\0') 989 (void)printf("from %.*s ", 990 (int)sizeof(ll.ll_host), 991 ll.ll_host); 992 (void)printf("on %.*s\n", 993 (int)sizeof(ll.ll_line), 994 ll.ll_line); 995 } 996 ll.ll_tv = now; 997 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 998 if (hostname) { 999 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 1000 ll.ll_ss = ss; 1001 } 1002 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) 1003 syslog(LOG_NOTICE, "Cannot update lastlogx %m"); 1004 } 1005 #endif 1006 1007 #ifdef SUPPORT_UTMP 1008 static void 1009 doutmp() 1010 { 1011 struct utmp utmp; 1012 1013 (void)memset((void *)&utmp, 0, sizeof(utmp)); 1014 utmp.ut_time = now.tv_sec; 1015 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 1016 if (hostname) 1017 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 1018 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 1019 login(&utmp); 1020 } 1021 1022 static void 1023 dolastlog(quiet) 1024 int quiet; 1025 { 1026 struct lastlog ll; 1027 int fd; 1028 1029 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 1030 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); 1031 if (!quiet) { 1032 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 1033 ll.ll_time != 0) { 1034 (void)printf("Last login: %.24s ", 1035 ctime(&ll.ll_time)); 1036 if (*ll.ll_host != '\0') 1037 (void)printf("from %.*s ", 1038 (int)sizeof(ll.ll_host), 1039 ll.ll_host); 1040 (void)printf("on %.*s\n", 1041 (int)sizeof(ll.ll_line), ll.ll_line); 1042 } 1043 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), 1044 SEEK_SET); 1045 } 1046 memset((void *)&ll, 0, sizeof(ll)); 1047 ll.ll_time = now.tv_sec; 1048 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 1049 if (hostname) 1050 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 1051 (void)write(fd, (char *)&ll, sizeof(ll)); 1052 (void)close(fd); 1053 } 1054 } 1055 #endif 1056 1057 void 1058 badlogin(name) 1059 char *name; 1060 { 1061 1062 if (failures == 0) 1063 return; 1064 if (hostname) { 1065 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 1066 failures, failures > 1 ? "S" : "", hostname); 1067 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1068 "%d LOGIN FAILURE%s FROM %s, %s", 1069 failures, failures > 1 ? "S" : "", hostname, name); 1070 } else { 1071 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 1072 failures, failures > 1 ? "S" : "", tty); 1073 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1074 "%d LOGIN FAILURE%s ON %s, %s", 1075 failures, failures > 1 ? "S" : "", tty, name); 1076 } 1077 } 1078 1079 const char * 1080 stypeof(ttyid) 1081 const char *ttyid; 1082 { 1083 struct ttyent *t; 1084 1085 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL); 1086 } 1087 1088 void 1089 sleepexit(eval) 1090 int eval; 1091 { 1092 1093 (void)sleep(5); 1094 exit(eval); 1095 } 1096