1 /*- 2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if 0 35 static char copyright[] = 36 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 47 48 /* 49 * login [ name ] 50 * login -h hostname (for telnetd, etc.) 51 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 52 */ 53 54 #include <sys/copyright.h> 55 #include <sys/param.h> 56 #include <sys/wait.h> 57 #include <sys/stat.h> 58 #include <sys/socket.h> 59 #include <sys/time.h> 60 #include <sys/resource.h> 61 #include <sys/file.h> 62 #include <netinet/in.h> 63 #include <arpa/inet.h> 64 65 #include <err.h> 66 #include <errno.h> 67 #include <grp.h> 68 #include <libutil.h> 69 #include <login_cap.h> 70 #include <netdb.h> 71 #include <pwd.h> 72 #include <setjmp.h> 73 #include <signal.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <syslog.h> 78 #include <ttyent.h> 79 #include <unistd.h> 80 #include <utmp.h> 81 82 #ifndef NO_PAM 83 #include <security/pam_appl.h> 84 #include <security/pam_misc.h> 85 #endif 86 87 #include "login.h" 88 #include "pathnames.h" 89 90 /* wrapper for KAME-special getnameinfo() */ 91 #ifndef NI_WITHSCOPEID 92 #define NI_WITHSCOPEID 0 93 #endif 94 95 static int auth_traditional __P((void)); 96 static void badlogin __P((char *)); 97 static void dolastlog __P((int)); 98 static void getloginname __P((void)); 99 static void motd __P((const char *)); 100 static void refused __P((const char *,const char *,int)); 101 static int rootterm __P((char *)); 102 static void sigint __P((int)); 103 static void sleepexit __P((int)); 104 static const char *stypeof __P((char *)); 105 static void timedout __P((int)); 106 static void usage __P((void)); 107 108 #ifndef NO_PAM 109 static int auth_pam __P((void)); 110 static int export_pam_environment __P((void)); 111 static int ok_to_export __P((const char *)); 112 113 static pam_handle_t *pamh = NULL; 114 static char **environ_pam; 115 116 #define PAM_END { \ 117 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 118 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \ 119 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 120 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \ 121 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \ 122 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \ 123 } 124 #endif /* NO_PAM */ 125 126 #define TTYGRPNAME "tty" /* group to own ttys */ 127 #define DEFAULT_BACKOFF 3 128 #define DEFAULT_RETRIES 10 129 #define DEFAULT_PROMPT "login: " 130 #define DEFAULT_PASSWD_PROMPT "Password:" 131 #define INVALID_HOST "invalid hostname" 132 #define UNKNOWN "su" 133 #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 134 #define NBUFSIZ UT_NAMESIZE + 64 135 136 /* 137 * This bounds the time given to login. Not a define so it can 138 * be patched on machines where it's too small. 139 */ 140 u_int timeout = 300; 141 142 /* Buffer for signal handling of timeout */ 143 jmp_buf timeout_buf; 144 145 struct passwd *pwd; 146 int failures; 147 char *term, *envinit[1], *hostname, *passwd_prompt, *prompt, *tty, *username; 148 char full_hostname[MAXHOSTNAMELEN]; 149 150 int 151 main(argc, argv) 152 int argc; 153 char *argv[]; 154 { 155 struct group *gr; 156 struct stat st; 157 struct timeval tp; 158 struct utmp utmp; 159 int rootok, retries, backoff; 160 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 161 time_t warntime; 162 uid_t uid, euid; 163 gid_t egid; 164 char *p, *ttyn; 165 char tbuf[MAXPATHLEN + 2]; 166 char tname[sizeof(_PATH_TTY) + 10]; 167 char *shell = NULL; 168 static char default_prompt[] = DEFAULT_PROMPT; 169 static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT; 170 static char invalid_host[] = INVALID_HOST; 171 login_cap_t *lc = NULL; 172 #ifndef NO_PAM 173 pid_t pid; 174 int e; 175 #endif /* NO_PAM */ 176 177 (void)signal(SIGQUIT, SIG_IGN); 178 (void)signal(SIGINT, SIG_IGN); 179 (void)signal(SIGHUP, SIG_IGN); 180 if (setjmp(timeout_buf)) { 181 if (failures) 182 badlogin(tbuf); 183 (void)fprintf(stderr, "Login timed out after %d seconds\n", 184 timeout); 185 exit(0); 186 } 187 (void)signal(SIGALRM, timedout); 188 (void)alarm(timeout); 189 (void)setpriority(PRIO_PROCESS, 0, 0); 190 191 openlog("login", LOG_ODELAY, LOG_AUTH); 192 193 /* 194 * -p is used by getty to tell login not to destroy the environment 195 * -f is used to skip a second login authentication 196 * -h is used by other servers to pass the name of the remote 197 * host to login so that it may be placed in utmp and wtmp 198 */ 199 *full_hostname = '\0'; 200 term = NULL; 201 202 fflag = hflag = pflag = 0; 203 uid = getuid(); 204 euid = geteuid(); 205 egid = getegid(); 206 while ((ch = getopt(argc, argv, "fh:p")) != -1) 207 switch (ch) { 208 case 'f': 209 fflag = 1; 210 break; 211 case 'h': 212 if (uid) 213 errx(1, "-h option: %s", strerror(EPERM)); 214 hflag = 1; 215 if (strlcpy(full_hostname, optarg, 216 sizeof(full_hostname)) >= sizeof(full_hostname)) 217 errx(1, "-h option: %s: exceeds maximum " 218 "hostname size", optarg); 219 220 trimdomain(optarg, UT_HOSTSIZE); 221 222 if (strlen(optarg) > UT_HOSTSIZE) { 223 struct addrinfo hints, *res; 224 int ga_err; 225 226 memset(&hints, 0, sizeof(hints)); 227 hints.ai_family = AF_UNSPEC; 228 ga_err = getaddrinfo(optarg, NULL, &hints, 229 &res); 230 if (ga_err == 0) { 231 char hostbuf[MAXHOSTNAMELEN]; 232 233 getnameinfo(res->ai_addr, 234 res->ai_addrlen, 235 hostbuf, 236 sizeof(hostbuf), NULL, 0, 237 NI_NUMERICHOST| 238 NI_WITHSCOPEID); 239 optarg = strdup(hostbuf); 240 if (optarg == NULL) { 241 syslog(LOG_NOTICE, 242 "strdup(): %m"); 243 sleepexit(1); 244 } 245 } else 246 optarg = invalid_host; 247 if (res != NULL) 248 freeaddrinfo(res); 249 } 250 hostname = optarg; 251 break; 252 case 'p': 253 pflag = 1; 254 break; 255 case '?': 256 default: 257 if (!uid) 258 syslog(LOG_ERR, "invalid flag %c", ch); 259 usage(); 260 } 261 argc -= optind; 262 argv += optind; 263 264 if (*argv) { 265 username = *argv; 266 ask = 0; 267 } else 268 ask = 1; 269 270 for (cnt = getdtablesize(); cnt > 2; cnt--) 271 (void)close(cnt); 272 273 ttyn = ttyname(STDIN_FILENO); 274 if (ttyn == NULL || *ttyn == '\0') { 275 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 276 ttyn = tname; 277 } 278 if ((tty = strrchr(ttyn, '/')) != NULL) 279 ++tty; 280 else 281 tty = ttyn; 282 283 /* 284 * Get "login-retries" & "login-backoff" from default class 285 */ 286 lc = login_getclass(NULL); 287 prompt = login_getcapstr(lc, "prompt", default_prompt, default_prompt); 288 passwd_prompt = login_getcapstr(lc, "passwd_prompt", 289 default_passwd_prompt, default_passwd_prompt); 290 retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, 291 DEFAULT_RETRIES); 292 backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, 293 DEFAULT_BACKOFF); 294 login_close(lc); 295 lc = NULL; 296 297 for (cnt = 0;; ask = 1) { 298 if (ask) { 299 fflag = 0; 300 getloginname(); 301 } 302 rootlogin = 0; 303 rootok = rootterm(tty); /* Default (auth may change) */ 304 305 if (strlen(username) > UT_NAMESIZE) 306 username[UT_NAMESIZE] = '\0'; 307 308 /* 309 * Note if trying multiple user names; log failures for 310 * previous user name, but don't bother logging one failure 311 * for nonexistent name (mistyped username). 312 */ 313 if (failures && strcmp(tbuf, username)) { 314 if (failures > (pwd ? 0 : 1)) 315 badlogin(tbuf); 316 } 317 (void)strlcpy(tbuf, username, sizeof(tbuf)); 318 319 pwd = getpwnam(username); 320 321 /* 322 * if we have a valid account name, and it doesn't have a 323 * password, or the -f option was specified and the caller 324 * is root or the caller isn't changing their uid, don't 325 * authenticate. 326 */ 327 if (pwd != NULL) { 328 if (pwd->pw_uid == 0) 329 rootlogin = 1; 330 331 if (fflag && (uid == (uid_t)0 || 332 uid == (uid_t)pwd->pw_uid)) { 333 /* already authenticated */ 334 break; 335 } else if (pwd->pw_passwd[0] == '\0') { 336 if (!rootlogin || rootok) { 337 /* pretend password okay */ 338 rval = 0; 339 goto ttycheck; 340 } 341 } 342 } 343 344 fflag = 0; 345 346 (void)setpriority(PRIO_PROCESS, 0, -4); 347 348 #ifndef NO_PAM 349 /* 350 * Try to authenticate using PAM. If a PAM system error 351 * occurs, perhaps because of a botched configuration, 352 * then fall back to using traditional Unix authentication. 353 */ 354 if ((rval = auth_pam()) == -1) 355 #endif /* NO_PAM */ 356 rval = auth_traditional(); 357 358 (void)setpriority(PRIO_PROCESS, 0, 0); 359 360 /* 361 * PAM authentication may have changed "pwd" to the 362 * entry for the template user. Check again to see if 363 * this is a root login after all. 364 */ 365 if (pwd != NULL && pwd->pw_uid == 0) 366 rootlogin = 1; 367 368 ttycheck: 369 /* 370 * If trying to log in as root without Kerberos, 371 * but with insecure terminal, refuse the login attempt. 372 */ 373 if (pwd && !rval) { 374 if (rootlogin && !rootok) 375 refused(NULL, "NOROOT", 0); 376 else /* valid password & authenticated */ 377 break; 378 } 379 380 (void)printf("Login incorrect\n"); 381 failures++; 382 383 /* 384 * we allow up to 'retry' (10) tries, 385 * but after 'backoff' (3) we start backing off 386 */ 387 if (++cnt > backoff) { 388 if (cnt >= retries) { 389 badlogin(username); 390 sleepexit(1); 391 } 392 sleep((u_int)((cnt - backoff) * 5)); 393 } 394 } 395 396 /* committed to login -- turn off timeout */ 397 (void)alarm((u_int)0); 398 (void)signal(SIGHUP, SIG_DFL); 399 400 endpwent(); 401 402 /* 403 * Establish the login class. 404 */ 405 lc = login_getpwclass(pwd); 406 407 quietlog = login_getcapbool(lc, "hushlogin", 0); 408 /* 409 * Switching needed for NFS with root access disabled. 410 * 411 * XXX: This change fails to modify the additional groups for the 412 * process, and as such, may restrict rights normally granted 413 * through those groups. 414 */ 415 (void)setegid(pwd->pw_gid); 416 (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 417 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 418 if (login_getcapbool(lc, "requirehome", 0)) 419 refused("Home directory not available", "HOMEDIR", 1); 420 if (chdir("/") < 0) 421 refused("Cannot find root directory", "ROOTDIR", 1); 422 if (!quietlog || *pwd->pw_dir) 423 printf("No home directory.\nLogging in with home = \"/\".\n"); 424 pwd->pw_dir = strdup("/"); 425 if (pwd->pw_dir == NULL) { 426 syslog(LOG_NOTICE, "strdup(): %m"); 427 sleepexit(1); 428 } 429 } 430 (void)seteuid(euid); 431 (void)setegid(egid); 432 if (!quietlog) 433 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 434 435 if (pwd->pw_change || pwd->pw_expire) 436 (void)gettimeofday(&tp, (struct timezone *)NULL); 437 438 warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN, 439 DEFAULT_WARN); 440 441 if (pwd->pw_expire) { 442 if (tp.tv_sec >= pwd->pw_expire) { 443 refused("Sorry -- your account has expired", "EXPIRED", 444 1); 445 } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog) 446 (void)printf("Warning: your account expires on %s", 447 ctime(&pwd->pw_expire)); 448 } 449 450 if (lc != NULL) { 451 if (hostname) { 452 struct addrinfo hints, *res; 453 int ga_err; 454 455 memset(&hints, 0, sizeof(hints)); 456 hints.ai_family = AF_UNSPEC; 457 ga_err = getaddrinfo(full_hostname, NULL, &hints, 458 &res); 459 if (ga_err == 0) { 460 char hostbuf[MAXHOSTNAMELEN]; 461 462 getnameinfo(res->ai_addr, res->ai_addrlen, 463 hostbuf, sizeof(hostbuf), NULL, 0, 464 NI_NUMERICHOST|NI_WITHSCOPEID); 465 if ((optarg = strdup(hostbuf)) == NULL) { 466 syslog(LOG_NOTICE, "strdup(): %m"); 467 sleepexit(1); 468 } 469 } else 470 optarg = NULL; 471 if (res != NULL) 472 freeaddrinfo(res); 473 if (!auth_hostok(lc, full_hostname, optarg)) 474 refused("Permission denied", "HOST", 1); 475 } 476 477 if (!auth_ttyok(lc, tty)) 478 refused("Permission denied", "TTY", 1); 479 480 if (!auth_timeok(lc, time(NULL))) 481 refused("Logins not available right now", "TIME", 1); 482 } 483 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 484 if (*pwd->pw_shell == '\0') 485 pwd->pw_shell = strdup(_PATH_BSHELL); 486 if (pwd->pw_shell == NULL) { 487 syslog(LOG_NOTICE, "strdup(): %m"); 488 sleepexit(1); 489 } 490 if (*shell == '\0') /* Not overridden */ 491 shell = pwd->pw_shell; 492 if ((shell = strdup(shell)) == NULL) { 493 syslog(LOG_NOTICE, "strdup(): %m"); 494 sleepexit(1); 495 } 496 497 #ifdef LOGIN_ACCESS 498 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) 499 refused("Permission denied", "ACCESS", 1); 500 #endif /* LOGIN_ACCESS */ 501 502 /* Nothing else left to fail -- really log in. */ 503 memset((void *)&utmp, 0, sizeof(utmp)); 504 (void)time(&utmp.ut_time); 505 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 506 if (hostname) 507 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 508 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 509 login(&utmp); 510 511 dolastlog(quietlog); 512 513 /* 514 * Set device protections, depending on what terminal the 515 * user is logged in. This feature is used on Suns to give 516 * console users better privacy. 517 */ 518 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 519 520 /* 521 * Clear flags of the tty. None should be set, and when the 522 * user sets them otherwise, this can cause the chown to fail. 523 * Since it isn't clear that flags are useful on character 524 * devices, we just clear them. 525 */ 526 if (chflags(ttyn, 0) && errno != EOPNOTSUPP) 527 syslog(LOG_ERR, "chmod(%s): %m", ttyn); 528 if (chown(ttyn, pwd->pw_uid, 529 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 530 syslog(LOG_ERR, "chmod(%s): %m", ttyn); 531 532 533 /* 534 * Preserve TERM if it happens to be already set. 535 */ 536 if ((term = getenv("TERM")) != NULL) { 537 if ((term = strdup(term)) == NULL) { 538 syslog(LOG_NOTICE, 539 "strdup(): %m"); 540 sleepexit(1); 541 } 542 } 543 544 /* 545 * Exclude cons/vt/ptys only, assume dialup otherwise 546 * TODO: Make dialup tty determination a library call 547 * for consistency (finger etc.) 548 */ 549 if (hostname==NULL && isdialuptty(tty)) 550 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 551 552 #ifdef LOGALL 553 /* 554 * Syslog each successful login, so we don't have to watch hundreds 555 * of wtmp or lastlogin files. 556 */ 557 if (hostname) 558 syslog(LOG_INFO, "login from %s on %s as %s", 559 full_hostname, tty, pwd->pw_name); 560 else 561 syslog(LOG_INFO, "login on %s as %s", 562 tty, pwd->pw_name); 563 #endif 564 565 /* 566 * If fflag is on, assume caller/authenticator has logged root login. 567 */ 568 if (rootlogin && fflag == 0) 569 { 570 if (hostname) 571 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 572 username, tty, full_hostname); 573 else 574 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 575 username, tty); 576 } 577 578 /* 579 * Destroy environment unless user has requested its preservation. 580 * We need to do this before setusercontext() because that may 581 * set or reset some environment variables. 582 */ 583 if (!pflag) 584 environ = envinit; 585 586 /* 587 * PAM modules might add supplementary groups during pam_setcred(). 588 */ 589 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 590 syslog(LOG_ERR, "setusercontext() failed - exiting"); 591 exit(1); 592 } 593 594 #ifndef NO_PAM 595 if (pamh) { 596 if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 597 syslog(LOG_ERR, "pam_open_session: %s", 598 pam_strerror(pamh, e)); 599 } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) 600 != PAM_SUCCESS) { 601 syslog(LOG_ERR, "pam_setcred: %s", 602 pam_strerror(pamh, e)); 603 } 604 605 /* 606 * Add any environmental variables that the 607 * PAM modules may have set. 608 * Call *after* opening session! 609 */ 610 if (pamh) { 611 environ_pam = pam_getenvlist(pamh); 612 if (environ_pam) 613 export_pam_environment(); 614 } 615 616 /* 617 * We must fork() before setuid() because we need to call 618 * pam_close_session() as root. 619 */ 620 pid = fork(); 621 if (pid < 0) { 622 err(1, "fork"); 623 PAM_END; 624 exit(0); 625 } else if (pid) { 626 /* parent - wait for child to finish, then cleanup 627 session */ 628 wait(NULL); 629 PAM_END; 630 exit(0); 631 } else { 632 if ((e = pam_end(pamh, PAM_DATA_SILENT)) != PAM_SUCCESS) 633 syslog(LOG_ERR, "pam_end: %s", 634 pam_strerror(pamh, e)); 635 } 636 } 637 #endif /* NO_PAM */ 638 639 /* 640 * We don't need to be root anymore, so 641 * set the user and session context 642 */ 643 if (setlogin(username) != 0) { 644 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 645 exit(1); 646 } 647 if (setusercontext(lc, pwd, pwd->pw_uid, 648 LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 649 syslog(LOG_ERR, "setusercontext() failed - exiting"); 650 exit(1); 651 } 652 653 (void)setenv("SHELL", pwd->pw_shell, 1); 654 (void)setenv("HOME", pwd->pw_dir, 1); 655 if (term != NULL && *term != '\0') 656 (void)setenv("TERM", term, 1); /* Preset overrides */ 657 else { 658 (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ 659 } 660 (void)setenv("LOGNAME", username, 1); 661 (void)setenv("USER", username, 1); 662 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 663 664 if (!quietlog) { 665 const char *cw; 666 667 cw = login_getcapstr(lc, "copyright", NULL, NULL); 668 if (cw != NULL && access(cw, F_OK) == 0) 669 motd(cw); 670 else 671 (void)printf("%s\n\t%s %s\n", 672 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 673 "The Regents of the University of California. ", 674 "All rights reserved."); 675 676 (void)printf("\n"); 677 678 cw = login_getcapstr(lc, "welcome", NULL, NULL); 679 if (cw == NULL || access(cw, F_OK) != 0) 680 cw = _PATH_MOTDFILE; 681 motd(cw); 682 683 if (login_getcapbool(lc, "nocheckmail", 0) == 0) { 684 /* $MAIL may have been set by class. */ 685 cw = getenv("MAIL"); 686 if (cw != NULL) 687 strlcpy(tbuf, cw, sizeof(tbuf)); 688 else 689 snprintf(tbuf, sizeof(tbuf), "%s/%s", 690 _PATH_MAILDIR, pwd->pw_name); 691 if (stat(tbuf, &st) == 0 && st.st_size != 0) 692 (void)printf("You have %smail.\n", 693 (st.st_mtime > st.st_atime) ? "new " : ""); 694 } 695 } 696 697 login_close(lc); 698 699 (void)signal(SIGALRM, SIG_DFL); 700 (void)signal(SIGQUIT, SIG_DFL); 701 (void)signal(SIGINT, SIG_DFL); 702 (void)signal(SIGTSTP, SIG_IGN); 703 704 /* 705 * Login shells have a leading '-' in front of argv[0] 706 */ 707 if ((u_int)snprintf(tbuf, sizeof(tbuf), "-%s", 708 (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >= 709 sizeof(tbuf)) { 710 syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 711 username); 712 errx(1, "shell exceeds maximum pathname size"); 713 } 714 715 execlp(shell, tbuf, (char *)0); 716 err(1, "%s", shell); 717 } 718 719 static int 720 auth_traditional() 721 { 722 int rval; 723 char *p; 724 const char *ep; 725 const char *salt; 726 727 rval = 1; 728 salt = pwd != NULL ? pwd->pw_passwd : "xx"; 729 730 p = getpass(passwd_prompt); 731 ep = crypt(p, salt); 732 733 if (pwd) { 734 if (!p[0] && pwd->pw_passwd[0]) 735 ep = ":"; 736 if (strcmp(ep, pwd->pw_passwd) == 0) 737 rval = 0; 738 } 739 740 /* clear entered password */ 741 memset(p, 0, strlen(p)); 742 return rval; 743 } 744 745 #ifndef NO_PAM 746 /* 747 * Attempt to authenticate the user using PAM. Returns 0 if the user is 748 * authenticated, or 1 if not authenticated. If some sort of PAM system 749 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 750 * function returns -1. This can be used as an indication that we should 751 * fall back to a different authentication mechanism. 752 */ 753 static int 754 auth_pam() 755 { 756 const char *tmpl_user; 757 const void *item; 758 int rval; 759 int e; 760 static struct pam_conv conv = { misc_conv, NULL }; 761 762 if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { 763 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 764 return -1; 765 } 766 if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { 767 syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", 768 pam_strerror(pamh, e)); 769 return -1; 770 } 771 if (hostname != NULL && 772 (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { 773 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 774 pam_strerror(pamh, e)); 775 return -1; 776 } 777 e = pam_authenticate(pamh, 0); 778 switch (e) { 779 780 case PAM_SUCCESS: 781 /* 782 * With PAM we support the concept of a "template" 783 * user. The user enters a login name which is 784 * authenticated by PAM, usually via a remote service 785 * such as RADIUS or TACACS+. If authentication 786 * succeeds, a different but related "template" name 787 * is used for setting the credentials, shell, and 788 * home directory. The name the user enters need only 789 * exist on the remote authentication server, but the 790 * template name must be present in the local password 791 * database. 792 * 793 * This is supported by two various mechanisms in the 794 * individual modules. However, from the application's 795 * point of view, the template user is always passed 796 * back as a changed value of the PAM_USER item. 797 */ 798 if ((e = pam_get_item(pamh, PAM_USER, &item)) == 799 PAM_SUCCESS) { 800 tmpl_user = (const char *) item; 801 if (strcmp(username, tmpl_user) != 0) 802 pwd = getpwnam(tmpl_user); 803 } else 804 syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 805 pam_strerror(pamh, e)); 806 rval = 0; 807 break; 808 809 case PAM_AUTH_ERR: 810 case PAM_USER_UNKNOWN: 811 case PAM_MAXTRIES: 812 rval = 1; 813 break; 814 815 default: 816 syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 817 rval = -1; 818 break; 819 } 820 821 if (rval == 0) { 822 e = pam_acct_mgmt(pamh, 0); 823 if (e == PAM_NEW_AUTHTOK_REQD) { 824 e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 825 if (e != PAM_SUCCESS) { 826 syslog(LOG_ERR, "pam_chauthtok: %s", 827 pam_strerror(pamh, e)); 828 rval = 1; 829 } 830 } else if (e != PAM_SUCCESS) { 831 rval = 1; 832 } 833 } 834 835 if (rval != 0) { 836 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 837 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 838 } 839 pamh = NULL; 840 } 841 return rval; 842 } 843 844 static int 845 export_pam_environment() 846 { 847 char **pp; 848 849 for (pp = environ_pam; *pp != NULL; pp++) { 850 if (ok_to_export(*pp)) 851 (void) putenv(*pp); 852 free(*pp); 853 } 854 return PAM_SUCCESS; 855 } 856 857 /* 858 * Sanity checks on PAM environmental variables: 859 * - Make sure there is an '=' in the string. 860 * - Make sure the string doesn't run on too long. 861 * - Do not export certain variables. This list was taken from the 862 * Solaris pam_putenv(3) man page. 863 */ 864 static int 865 ok_to_export(s) 866 const char *s; 867 { 868 static const char *noexport[] = { 869 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 870 "IFS", "PATH", NULL 871 }; 872 const char **pp; 873 size_t n; 874 875 if (strlen(s) > 1024 || strchr(s, '=') == NULL) 876 return 0; 877 if (strncmp(s, "LD_", 3) == 0) 878 return 0; 879 for (pp = noexport; *pp != NULL; pp++) { 880 n = strlen(*pp); 881 if (s[n] == '=' && strncmp(s, *pp, n) == 0) 882 return 0; 883 } 884 return 1; 885 } 886 #endif /* NO_PAM */ 887 888 static void 889 usage() 890 { 891 892 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 893 exit(1); 894 } 895 896 /* 897 * Allow for authentication style and/or kerberos instance 898 */ 899 900 void 901 getloginname() 902 { 903 int ch; 904 char *p; 905 static char nbuf[NBUFSIZ]; 906 907 for (;;) { 908 (void)printf("%s", prompt); 909 for (p = nbuf; (ch = getchar()) != '\n'; ) { 910 if (ch == EOF) { 911 badlogin(username); 912 exit(0); 913 } 914 if (p < nbuf + (NBUFSIZ - 1)) 915 *p++ = ch; 916 } 917 if (p > nbuf) { 918 if (nbuf[0] == '-') 919 (void)fprintf(stderr, 920 "login names may not start with '-'.\n"); 921 else { 922 *p = '\0'; 923 username = nbuf; 924 break; 925 } 926 } 927 } 928 } 929 930 int 931 rootterm(ttyn) 932 char *ttyn; 933 { 934 struct ttyent *t; 935 936 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 937 } 938 939 volatile int motdinterrupt; 940 941 void 942 sigint(signo) 943 int signo __unused; 944 { 945 motdinterrupt = 1; 946 } 947 948 void 949 motd(motdfile) 950 const char *motdfile; 951 { 952 int fd, nchars; 953 sig_t oldint; 954 char tbuf[256]; 955 956 if ((fd = open(motdfile, O_RDONLY, 0)) < 0) 957 return; 958 motdinterrupt = 0; 959 oldint = signal(SIGINT, sigint); 960 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt) 961 (void)write(fileno(stdout), tbuf, nchars); 962 (void)signal(SIGINT, oldint); 963 (void)close(fd); 964 } 965 966 /* ARGSUSED */ 967 void 968 timedout(signo) 969 int signo; 970 { 971 972 longjmp(timeout_buf, signo); 973 } 974 975 976 void 977 dolastlog(quiet) 978 int quiet; 979 { 980 struct lastlog ll; 981 int fd; 982 983 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 984 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 985 if (!quiet) { 986 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 987 ll.ll_time != 0) { 988 (void)printf("Last login: %.*s ", 989 24-5, (char *)ctime(&ll.ll_time)); 990 if (*ll.ll_host != '\0') 991 (void)printf("from %.*s\n", 992 (int)sizeof(ll.ll_host), 993 ll.ll_host); 994 else 995 (void)printf("on %.*s\n", 996 (int)sizeof(ll.ll_line), 997 ll.ll_line); 998 } 999 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 1000 } 1001 memset((void *)&ll, 0, sizeof(ll)); 1002 (void)time(&ll.ll_time); 1003 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 1004 if (hostname) 1005 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 1006 (void)write(fd, (char *)&ll, sizeof(ll)); 1007 (void)close(fd); 1008 } else { 1009 syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG); 1010 } 1011 } 1012 1013 void 1014 badlogin(name) 1015 char *name; 1016 { 1017 1018 if (failures == 0) 1019 return; 1020 if (hostname) { 1021 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 1022 failures, failures > 1 ? "S" : "", full_hostname); 1023 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1024 "%d LOGIN FAILURE%s FROM %s, %s", 1025 failures, failures > 1 ? "S" : "", full_hostname, name); 1026 } else { 1027 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 1028 failures, failures > 1 ? "S" : "", tty); 1029 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1030 "%d LOGIN FAILURE%s ON %s, %s", 1031 failures, failures > 1 ? "S" : "", tty, name); 1032 } 1033 failures = 0; 1034 } 1035 1036 const char * 1037 stypeof(ttyid) 1038 char *ttyid; 1039 { 1040 struct ttyent *t; 1041 1042 if (ttyid != NULL && *ttyid != '\0') { 1043 t = getttynam(ttyid); 1044 if (t != NULL && t->ty_type != NULL) 1045 return (t->ty_type); 1046 } 1047 return (UNKNOWN); 1048 } 1049 1050 void 1051 refused(msg, rtype, lout) 1052 const char *msg; 1053 const char *rtype; 1054 int lout; 1055 { 1056 1057 if (msg != NULL) 1058 printf("%s.\n", msg); 1059 if (hostname) 1060 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 1061 pwd->pw_name, rtype, full_hostname, tty); 1062 else 1063 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 1064 pwd->pw_name, rtype, tty); 1065 if (lout) 1066 sleepexit(1); 1067 } 1068 1069 void 1070 sleepexit(eval) 1071 int eval; 1072 { 1073 1074 (void)sleep(5); 1075 exit(eval); 1076 } 1077