1/*- 2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2002 Networks Associates Technologies, Inc. 5 * All rights reserved. 6 * 7 * Portions of this software were developed for the FreeBSD Project by 8 * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 * ("CBOSS"), as part of the DARPA CHATS research program. 11 * Portions copyright (c) 1999-2007 Apple Inc. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 */ 41 42#if 0 43#ifndef lint 44static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 45#endif 46#endif 47 48#include <sys/cdefs.h> 49__FBSDID("$FreeBSD: src/usr.bin/login/login.c,v 1.106 2007/07/04 00:00:40 scf Exp $"); 50 51/* 52 * login [ name ] 53 * login -h hostname (for telnetd, etc.) 54 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 55 */ 56 57#ifndef __APPLE__ 58#include <sys/copyright.h> 59#endif 60#ifdef __APPLE__ 61#include <TargetConditionals.h> 62#endif 63#include <sys/param.h> 64#include <sys/file.h> 65#include <sys/stat.h> 66#include <sys/time.h> 67#include <sys/resource.h> 68#include <sys/wait.h> 69 70#include <err.h> 71#include <errno.h> 72#include <grp.h> 73#ifdef __APPLE__ 74#include <util.h> 75#else 76#include <libutil.h> 77#endif 78#ifdef LOGIN_CAP 79#include <login_cap.h> 80#endif 81#include <pwd.h> 82#include <setjmp.h> 83#include <signal.h> 84#include <stdio.h> 85#include <stdlib.h> 86#include <string.h> 87#include <syslog.h> 88#include <ttyent.h> 89#include <unistd.h> 90#ifdef __APPLE__ 91#include <utmpx.h> 92#ifdef USE_PAM 93#else /* !USE_PAM */ 94#ifndef _UTX_USERSIZE 95#define _UTX_USERSIZE MAXLOGNAME 96#endif 97#endif /* USE_PAM */ 98#endif /* __APPLE__ */ 99 100#include <sys/types.h> 101#include <sys/socket.h> 102#include <netinet/in.h> 103#include <arpa/inet.h> 104#include <netdb.h> 105 106#ifdef USE_BSM_AUDIT 107#include <bsm/libbsm.h> 108#include <bsm/audit.h> 109#include <bsm/audit_session.h> 110#include <bsm/audit_uevents.h> 111#endif 112 113#ifdef __APPLE__ 114#include <mach/mach_types.h> 115#include <mach/task.h> 116#include <mach/mach_init.h> 117#include <servers/bootstrap.h> 118 119#include <sys/file.h> 120#include <tzfile.h> 121#endif /* __APPLE__ */ 122 123#ifdef USE_PAM 124#include <security/pam_appl.h> 125#include <security/openpam.h> 126#endif /* USE_PAM */ 127 128#include "login.h" 129#include "pathnames.h" 130 131#ifdef USE_PAM 132static int auth_pam(int skip_auth); 133#endif /* USE_PAM */ 134static void bail(int, int); 135#ifdef USE_PAM 136static int export(const char *); 137static void export_pam_environment(void); 138#endif /* USE_PAM */ 139static int motd(const char *); 140static void badlogin(char *); 141static char *getloginname(void); 142#ifdef USE_PAM 143static void pam_syslog(const char *); 144static void pam_cleanup(void); 145#endif /* USE_PAM */ 146static void refused(const char *, const char *, int); 147static const char *stypeof(char *); 148static void sigint(int); 149static void timedout(int); 150static void usage(void); 151 152#ifdef __APPLE__ 153static void dolastlog(int); 154static void handle_sighup(int); 155 156#ifndef USE_PAM 157static void checknologin(void); 158static int rootterm(const char *); 159#endif /* !USE_PAM */ 160#endif /* __APPLE__ */ 161 162#define TTYGRPNAME "tty" /* group to own ttys */ 163#define DEFAULT_BACKOFF 3 164#define DEFAULT_RETRIES 10 165#define DEFAULT_PROMPT "login: " 166#define DEFAULT_PASSWD_PROMPT "Password:" 167#define TERM_UNKNOWN "su" 168#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 169#define NO_SLEEP_EXIT 0 170#define SLEEP_EXIT 5 171 172/* 173 * This bounds the time given to login. Not a define so it can 174 * be patched on machines where it's too small. 175 */ 176static u_int timeout = 300; 177 178/* Buffer for signal handling of timeout */ 179static jmp_buf timeout_buf; 180 181struct passwd *pwd; 182static int failures; 183 184static char *envinit[1]; /* empty environment list */ 185 186/* 187 * Command line flags and arguments 188 */ 189static int fflag; /* -f: do not perform authentication */ 190#ifdef __APPLE__ 191static int lflag; /* -l: login session to the commmand that follows username */ 192#endif 193static int hflag; /* -h: login from remote host */ 194static char *hostname; /* hostname from command line */ 195static int pflag; /* -p: preserve environment */ 196 197/* 198 * User name 199 */ 200static char *username; /* user name */ 201static char *olduser; /* previous user name */ 202 203/* 204 * Prompts 205 */ 206static char default_prompt[] = DEFAULT_PROMPT; 207static const char *prompt; 208static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT; 209static const char *passwd_prompt; 210 211static char *tty; 212 213/* 214 * PAM data 215 */ 216#ifdef USE_PAM 217static pam_handle_t *pamh = NULL; 218static struct pam_conv pamc = { openpam_ttyconv, NULL }; 219static int pam_err; 220static int pam_silent = PAM_SILENT; 221static int pam_cred_established; 222static int pam_session_established; 223#endif /* USE_PAM */ 224 225#ifdef __APPLE__ 226pid_t pid; 227 228#ifdef USE_PAM 229static struct lastlogx lastlog; 230#endif /* USE_PAM */ 231 232#ifdef USE_BSM_AUDIT 233extern au_tid_addr_t tid; 234#endif /* USE_BSM_AUDIT */ 235#endif /* __APPLE__ */ 236 237int 238main(int argc, char *argv[]) 239{ 240 struct group *gr; 241 struct stat st; 242 int retries, backoff; 243 int ask, ch, cnt, quietlog = 0, rootlogin, rval; 244 uid_t uid, euid; 245 gid_t egid; 246 char *term; 247 char *p, *ttyn; 248 char tname[sizeof(_PATH_TTY) + 10]; 249 char *arg0; 250 const char *tp; 251#ifdef __APPLE__ 252 int prio; 253#ifdef USE_PAM 254 const char *name = "login"; /* PAM config */ 255#else 256 struct utmpx utmp; 257#endif /* USE_PAM */ 258 const char *shell = NULL; 259#endif /* !__APPLE__ */ 260#ifdef LOGIN_CAP 261 login_cap_t *lc = NULL; 262 login_cap_t *lc_user = NULL; 263#endif /* LOGIN_CAP */ 264#ifndef __APPLE__ 265 pid_t pid; 266#endif 267#ifdef USE_BSM_AUDIT 268 char auditsuccess = 1; 269#endif 270 271 (void)signal(SIGQUIT, SIG_IGN); 272 (void)signal(SIGINT, SIG_IGN); 273 (void)signal(SIGHUP, SIG_IGN); 274 if (setjmp(timeout_buf)) { 275 if (failures) 276 badlogin(username); 277 (void)fprintf(stderr, "Login timed out after %d seconds\n", 278 timeout); 279 bail(NO_SLEEP_EXIT, 0); 280 } 281 (void)signal(SIGALRM, timedout); 282 (void)alarm(timeout); 283#ifdef __APPLE__ 284 prio = getpriority(PRIO_PROCESS, 0); 285#endif 286 (void)setpriority(PRIO_PROCESS, 0, 0); 287 288 openlog("login", LOG_ODELAY, LOG_AUTH); 289 290 uid = getuid(); 291 euid = geteuid(); 292 egid = getegid(); 293 294#ifdef __APPLE__ 295 while ((ch = getopt(argc, argv, "1fh:lpq")) != -1) 296#else 297 while ((ch = getopt(argc, argv, "fh:p")) != -1) 298#endif 299 switch (ch) { 300 case 'f': 301 fflag = 1; 302 break; 303 case 'h': 304 if (uid != 0) 305 errx(1, "-h option: %s", strerror(EPERM)); 306 if (strlen(optarg) >= MAXHOSTNAMELEN) 307 errx(1, "-h option: %s: exceeds maximum " 308 "hostname size", optarg); 309 hflag = 1; 310 hostname = optarg; 311 break; 312 case 'p': 313 pflag = 1; 314 break; 315#ifdef __APPLE__ 316 case '1': 317 break; 318 case 'l': 319 lflag = 1; 320 break; 321 case 'q': 322 quietlog = 1; 323 break; 324#endif 325 case '?': 326 default: 327 if (uid == 0) 328 syslog(LOG_ERR, "invalid flag %c", ch); 329 usage(); 330 } 331 argc -= optind; 332 argv += optind; 333 334 if (argc > 0) { 335 username = strdup(*argv); 336 if (username == NULL) 337 err(1, "strdup()"); 338 ask = 0; 339#ifdef __APPLE__ 340 argv++; 341#endif /* __APPLE__ */ 342 } else { 343 ask = 1; 344 } 345 346#ifndef __APPLE__ 347 setproctitle("-%s", getprogname()); 348#endif /* !__APPLE__ */ 349 350 for (cnt = getdtablesize(); cnt > 2; cnt--) 351 (void)close(cnt); 352 353 /* 354 * Get current TTY 355 */ 356 ttyn = ttyname(STDIN_FILENO); 357 if (ttyn == NULL || *ttyn == '\0') { 358 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 359 ttyn = tname; 360 } 361 if ((tty = strrchr(ttyn, '/')) != NULL) 362 ++tty; 363 else 364 tty = ttyn; 365 366#ifdef LOGIN_CAP 367 /* 368 * Get "login-retries" & "login-backoff" from default class 369 */ 370 lc = login_getclass(NULL); 371 prompt = login_getcapstr(lc, "login_prompt", 372 default_prompt, default_prompt); 373 passwd_prompt = login_getcapstr(lc, "passwd_prompt", 374 default_passwd_prompt, default_passwd_prompt); 375 retries = login_getcapnum(lc, "login-retries", 376 DEFAULT_RETRIES, DEFAULT_RETRIES); 377 backoff = login_getcapnum(lc, "login-backoff", 378 DEFAULT_BACKOFF, DEFAULT_BACKOFF); 379 login_close(lc); 380 lc = NULL; 381#else /* !LOGIN_CAP */ 382 prompt = default_prompt; 383 passwd_prompt = default_passwd_prompt; 384 retries = DEFAULT_RETRIES; 385 backoff = DEFAULT_BACKOFF; 386#endif /* !LOGIN_CAP */ 387 388#ifdef __APPLE__ 389#ifdef USE_BSM_AUDIT 390 /* Set the terminal id */ 391 au_tid_t old_tid; 392 audit_set_terminal_id(&old_tid); 393 tid.at_type = AU_IPv4; 394 tid.at_addr[0] = old_tid.machine; 395 if (fstat(STDIN_FILENO, &st) < 0) { 396 fprintf(stderr, "login: Unable to stat terminal\n"); 397 au_login_fail("Unable to stat terminal", 1); 398 exit(-1); 399 } 400 if (S_ISCHR(st.st_mode)) { 401 tid.at_port = st.st_rdev; 402 } else { 403 tid.at_port = 0; 404 } 405#endif /* USE_BSM_AUDIT */ 406#endif /* __APPLE__ */ 407 408 /* 409 * Try to authenticate the user until we succeed or time out. 410 */ 411 for (cnt = 0;; ask = 1) { 412 if (ask) { 413 fflag = 0; 414 if (olduser != NULL) 415 free(olduser); 416 olduser = username; 417 username = getloginname(); 418 } 419 rootlogin = 0; 420 421#ifdef __APPLE__ 422 if (strlen(username) > _UTX_USERSIZE) 423 username[_UTX_USERSIZE] = '\0'; 424#endif /* __APPLE__ */ 425 426 /* 427 * Note if trying multiple user names; log failures for 428 * previous user name, but don't bother logging one failure 429 * for nonexistent name (mistyped username). 430 */ 431 if (failures && strcmp(olduser, username) != 0) { 432 if (failures > (pwd ? 0 : 1)) 433 badlogin(olduser); 434 } 435 436#ifdef __APPLE__ 437#ifdef USE_PAM 438 /* get lastlog info before PAM make a new entry */ 439 if (!quietlog) 440 getlastlogxbyname(username, &lastlog); 441#endif /* USE_PAM */ 442#endif /* __APPLE__ */ 443 444 pwd = getpwnam(username); 445 446#ifdef USE_PAM 447 /* 448 * Load the PAM policy and set some variables 449 */ 450#ifdef __APPLE__ 451 if (fflag && (pwd != NULL) && (pwd->pw_uid == uid)) { 452 name = "login.term"; 453 } 454#endif 455 pam_err = pam_start(name, username, &pamc, &pamh); 456 if (pam_err != PAM_SUCCESS) { 457 pam_syslog("pam_start()"); 458#ifdef USE_BSM_AUDIT 459 au_login_fail("PAM Error", 1); 460#endif 461 bail(NO_SLEEP_EXIT, 1); 462 } 463 pam_err = pam_set_item(pamh, PAM_TTY, tty); 464 if (pam_err != PAM_SUCCESS) { 465 pam_syslog("pam_set_item(PAM_TTY)"); 466#ifdef USE_BSM_AUDIT 467 au_login_fail("PAM Error", 1); 468#endif 469 bail(NO_SLEEP_EXIT, 1); 470 } 471 pam_err = pam_set_item(pamh, PAM_RHOST, hostname); 472 if (pam_err != PAM_SUCCESS) { 473 pam_syslog("pam_set_item(PAM_RHOST)"); 474#ifdef USE_BSM_AUDIT 475 au_login_fail("PAM Error", 1); 476#endif 477 bail(NO_SLEEP_EXIT, 1); 478 } 479#endif /* USE_PAM */ 480 481 if (pwd != NULL && pwd->pw_uid == 0) 482 rootlogin = 1; 483 484 /* 485 * If the -f option was specified and the caller is 486 * root or the caller isn't changing their uid, don't 487 * authenticate. 488 */ 489 if (pwd != NULL && fflag && 490 (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) { 491#ifdef USE_PAM 492 rval = auth_pam(fflag); 493#else 494 rval = 0; 495#endif /* USE_PAM */ 496#ifdef USE_BSM_AUDIT 497 auditsuccess = 0; /* opened a terminal window only */ 498#endif 499 500#ifdef __APPLE__ 501#ifndef USE_PAM 502 /* If the account doesn't have a password, authenticate. */ 503 } else if (pwd != NULL && pwd->pw_passwd[0] == '\0') { 504 rval = 0; 505#endif /* !USE_PAM */ 506#endif /* __APPLE__ */ 507 } else if( pwd ) { 508 fflag = 0; 509 (void)setpriority(PRIO_PROCESS, 0, -4); 510#ifdef USE_PAM 511 rval = auth_pam(fflag); 512#else 513 { 514 char* salt = pwd->pw_passwd; 515 char* p = getpass(passwd_prompt); 516 rval = strcmp(crypt(p, salt), salt); 517 memset(p, 0, strlen(p)); 518 } 519#endif 520 (void)setpriority(PRIO_PROCESS, 0, 0); 521 } else { 522 rval = -1; 523 } 524 525#ifdef __APPLE__ 526#ifndef USE_PAM 527 /* 528 * If trying to log in as root but with insecure terminal, 529 * refuse the login attempt. 530 */ 531 if (pwd && rootlogin && !rootterm(tty)) { 532 refused("root login refused on this terminal", "ROOTTERM", 0); 533#ifdef USE_BSM_AUDIT 534 au_login_fail("Login refused on terminal", 0); 535#endif 536 continue; 537 } 538#endif /* !USE_PAM */ 539#endif /* __APPLE__ */ 540 541 if (pwd && rval == 0) 542 break; 543 544#ifdef USE_PAM 545 pam_cleanup(); 546#endif /* USE_PAM */ 547 548 /* 549 * We are not exiting here, but this corresponds to a failed 550 * login event, so set exitstatus to 1. 551 */ 552#ifdef USE_BSM_AUDIT 553 au_login_fail("Login incorrect", 1); 554#endif 555 556 (void)printf("Login incorrect\n"); 557 failures++; 558 559 pwd = NULL; 560 561 /* 562 * Allow up to 'retry' (10) attempts, but start 563 * backing off after 'backoff' (3) attempts. 564 */ 565 if (++cnt > backoff) { 566 if (cnt >= retries) { 567 badlogin(username); 568 bail(SLEEP_EXIT, 1); 569 } 570 sleep((u_int)((cnt - backoff) * 5)); 571 } 572 } 573 574 /* committed to login -- turn off timeout */ 575 (void)alarm((u_int)0); 576 (void)signal(SIGHUP, SIG_DFL); 577 578 endpwent(); 579 580#ifdef __APPLE__ 581 if (!pwd) { 582 fprintf(stderr, "login: Unable to find user: %s\n", username); 583 exit(1); 584 } 585 586#ifndef USE_PAM 587 /* if user not super-user, check for disabled logins */ 588 if (!rootlogin) 589 checknologin(); 590#endif /* !USE_PAM */ 591#endif /* APPLE */ 592 593#ifdef USE_BSM_AUDIT 594 /* Audit successful login. */ 595 if (auditsuccess) 596 au_login_success(fflag); 597#endif 598 599#ifdef LOGIN_CAP 600 /* 601 * Establish the login class. 602 */ 603 lc = login_getpwclass(pwd); 604 lc_user = login_getuserclass(pwd); 605 606 if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0))) 607 quietlog = login_getcapbool(lc, "hushlogin", 0); 608#endif /* LOGIN_CAP */ 609 610#ifndef __APPLE__ 611 /* 612 * Switching needed for NFS with root access disabled. 613 * 614 * XXX: This change fails to modify the additional groups for the 615 * process, and as such, may restrict rights normally granted 616 * through those groups. 617 */ 618 (void)setegid(pwd->pw_gid); 619 (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 620 621 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 622#ifdef LOGIN_CAP 623 if (login_getcapbool(lc, "requirehome", 0)) 624 refused("Home directory not available", "HOMEDIR", 1); 625#endif /* LOGIN_CAP */ 626 if (chdir("/") < 0) 627 refused("Cannot find root directory", "ROOTDIR", 1); 628 if (!quietlog || *pwd->pw_dir) 629 printf("No home directory.\nLogging in with home = \"/\".\n"); 630 pwd->pw_dir = strdup("/"); 631 if (pwd->pw_dir == NULL) { 632 syslog(LOG_NOTICE, "strdup(): %m"); 633 bail(SLEEP_EXIT, 1); 634 } 635 } 636 637 (void)seteuid(euid); 638 (void)setegid(egid); 639#endif /* !__APPLE__ */ 640 if (!quietlog) { 641 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 642#ifdef USE_PAM 643 if (!quietlog) 644 pam_silent = 0; 645#endif /* USE_PAM */ 646 } 647 648#ifdef __APPLE__ 649 /* Nothing else left to fail -- really log in. */ 650#ifndef USE_PAM 651 memset((void *)&utmp, 0, sizeof(utmp)); 652 (void)gettimeofday(&utmp.ut_tv, NULL); 653 (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user)); 654 if (hostname) 655 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 656 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 657 utmp.ut_type = USER_PROCESS | UTMPX_AUTOFILL_MASK; 658 utmp.ut_pid = getpid(); 659 pututxline(&utmp); 660#endif /* USE_PAM */ 661 662 shell = ""; 663#endif /* !__APPLE__ */ 664#ifdef LOGIN_CAP 665 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 666#endif /* !LOGIN_CAP */ 667 if (*pwd->pw_shell == '\0') 668 pwd->pw_shell = strdup(_PATH_BSHELL); 669 if (pwd->pw_shell == NULL) { 670 syslog(LOG_NOTICE, "strdup(): %m"); 671 bail(SLEEP_EXIT, 1); 672 } 673 674#if defined(__APPLE__) && TARGET_OS_EMBEDDED 675 /* on embedded, allow a shell to live in /var/debug_mount/bin/sh */ 676#define _PATH_DEBUGSHELL "/var/debug_mount/bin/sh" 677 if (stat(pwd->pw_shell, &st) != 0) { 678 if (stat(_PATH_DEBUGSHELL, &st) == 0) { 679 pwd->pw_shell = strdup(_PATH_DEBUGSHELL); 680 } 681 } 682#endif 683 684 if (*shell == '\0') /* Not overridden */ 685 shell = pwd->pw_shell; 686 if ((shell = strdup(shell)) == NULL) { 687 syslog(LOG_NOTICE, "strdup(): %m"); 688 bail(SLEEP_EXIT, 1); 689 } 690 691#ifdef __APPLE__ 692 dolastlog(quietlog); 693#endif 694 695#ifndef __APPLE__ 696 /* 697 * Set device protections, depending on what terminal the 698 * user is logged in. This feature is used on Suns to give 699 * console users better privacy. 700 */ 701 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 702#endif /* !__APPLE__ */ 703 704 /* 705 * Clear flags of the tty. None should be set, and when the 706 * user sets them otherwise, this can cause the chown to fail. 707 * Since it isn't clear that flags are useful on character 708 * devices, we just clear them. 709 * 710 * We don't log in the case of EOPNOTSUPP because dev might be 711 * on NFS, which doesn't support chflags. 712 * 713 * We don't log in the EROFS because that means that /dev is on 714 * a read only file system and we assume that the permissions there 715 * are sane. 716 */ 717 if (ttyn != tname && chflags(ttyn, 0)) 718#ifdef __APPLE__ 719 if (errno != EOPNOTSUPP && errno != ENOTSUP && errno != EROFS) 720#else 721 if (errno != EOPNOTSUPP && errno != EROFS) 722#endif 723 syslog(LOG_ERR, "chflags(%s): %m", ttyn); 724 if (ttyn != tname && chown(ttyn, pwd->pw_uid, 725 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 726 if (errno != EROFS) 727 syslog(LOG_ERR, "chown(%s): %m", ttyn); 728 729#ifdef __APPLE__ 730 (void)chmod(ttyn, 0620); 731#endif /* __APPLE__ */ 732 733#ifndef __APPLE__ 734 /* 735 * Exclude cons/vt/ptys only, assume dialup otherwise 736 * TODO: Make dialup tty determination a library call 737 * for consistency (finger etc.) 738 */ 739 if (hflag && isdialuptty(tty)) 740 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 741#endif /* !__APPLE__ */ 742 743#ifdef LOGALL 744 /* 745 * Syslog each successful login, so we don't have to watch 746 * hundreds of wtmp or lastlogin files. 747 */ 748 if (hflag) 749 syslog(LOG_INFO, "login from %s on %s as %s", 750 hostname, tty, pwd->pw_name); 751 else 752 syslog(LOG_INFO, "login on %s as %s", 753 tty, pwd->pw_name); 754#endif 755 756 /* 757 * If fflag is on, assume caller/authenticator has logged root 758 * login. 759 */ 760 if (rootlogin && fflag == 0) { 761 if (hflag) 762 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 763 username, tty, hostname); 764 else 765 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 766 username, tty); 767 } 768 769 /* 770 * Destroy environment unless user has requested its 771 * preservation - but preserve TERM in all cases 772 */ 773 term = getenv("TERM"); 774 if (!pflag) 775 environ = envinit; 776 if (term != NULL) 777 setenv("TERM", term, 0); 778 779#ifndef __APPLE__ 780 /* 781 * PAM modules might add supplementary groups during pam_setcred(). 782 */ 783 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 784 syslog(LOG_ERR, "setusercontext() failed - exiting"); 785 bail(NO_SLEEP_EXIT, 1); 786 } 787#endif /* !__APPLE__ */ 788#ifdef USE_PAM 789 if (!fflag) { 790 pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED); 791 if (pam_err != PAM_SUCCESS) { 792 pam_syslog("pam_setcred()"); 793 bail(NO_SLEEP_EXIT, 1); 794 } 795 pam_cred_established = 1; 796 } 797 798 pam_err = pam_open_session(pamh, pam_silent); 799 if (pam_err != PAM_SUCCESS) { 800 pam_syslog("pam_open_session()"); 801 bail(NO_SLEEP_EXIT, 1); 802 } 803 pam_session_established = 1; 804#endif /* USE_PAM */ 805 806#ifdef __APPLE__ 807 /* <rdar://problem/5377791> 808 Install a signal handler that will forward SIGHUP to the 809 child and process group. The parent should not exit on 810 SIGHUP so that the tty ownership can be reset. */ 811 (void)signal(SIGHUP, handle_sighup); 812#endif /* __APPLE__ */ 813 814 /* 815 * We must fork() before setuid() because we need to call 816 * pam_close_session() as root. 817 */ 818 pid = fork(); 819 if (pid < 0) { 820 err(1, "fork"); 821 } else if (pid != 0) { 822 /* 823 * Parent: wait for child to finish, then clean up 824 * session. 825 */ 826 int status; 827#ifndef __APPLE__ 828 setproctitle("-%s [pam]", getprogname()); 829#endif /* !__APPLE__ */ 830#ifdef __APPLE__ 831 /* Our SIGHUP handler may interrupt the wait */ 832 int res; 833 do { 834 res = waitpid(pid, &status, 0); 835 } while (res == -1 && errno == EINTR); 836#else 837 waitpid(pid, &status, 0); 838#endif 839#ifdef __APPLE__ 840 chown(ttyn, 0, 0); 841 chmod(ttyn, 0666); 842#endif /* __APPLE__ */ 843 bail(NO_SLEEP_EXIT, 0); 844 } 845 846 /* 847 * NOTICE: We are now in the child process! 848 */ 849 850#ifdef __APPLE__ 851 /* Restore the default SIGHUP handler for the child. */ 852 (void)signal(SIGHUP, SIG_DFL); 853#endif /* __APPLE__ */ 854 855#ifdef USE_PAM 856 /* 857 * Add any environment variables the PAM modules may have set. 858 */ 859 export_pam_environment(); 860 861 /* 862 * We're done with PAM now; our parent will deal with the rest. 863 */ 864 pam_end(pamh, 0); 865 pamh = NULL; 866#endif /* USE_PAM */ 867 868 /* 869 * We don't need to be root anymore, so set the login name and 870 * the UID. 871 */ 872 if (setlogin(username) != 0) { 873 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 874 bail(NO_SLEEP_EXIT, 1); 875 } 876#ifdef __APPLE__ 877 /* <rdar://problem/6041650> restore process priority if not changing uids */ 878 if (uid == (uid_t)pwd->pw_uid) { 879 (void)setpriority(PRIO_PROCESS, 0, prio); 880 } 881 882 (void)setgid(pwd->pw_gid); 883 if (initgroups(username, pwd->pw_gid) == -1) 884 syslog(LOG_ERR, "login: initgroups() failed"); 885 (void) setuid(rootlogin ? 0 : pwd->pw_uid); 886#else /* !__APPLE__ */ 887 if (setusercontext(lc, pwd, pwd->pw_uid, 888 LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 889 syslog(LOG_ERR, "setusercontext() failed - exiting"); 890 exit(1); 891 } 892#endif /* !__APPLE__ */ 893 894#ifdef __APPLE__ 895 /* We test for the home directory after pam_open_session(3) 896 * as the home directory may have been mounted by a session 897 * module, and after changing uid as the home directory may 898 * be NFS with root access disabled. */ 899 if (!lflag) { 900 /* First do a stat in case the homedir is automounted */ 901 stat(pwd->pw_dir,&st); 902 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 903 printf("No home directory: %s\n", pwd->pw_dir); 904 if (chdir("/") < 0) { 905 refused("Cannot find root directory", "ROOTDIR", 0); 906 exit(1); 907 } 908 pwd->pw_dir = strdup("/"); 909 if (pwd->pw_dir == NULL) { 910 syslog(LOG_NOTICE, "strdup(): %m"); 911 exit(1); 912 } 913 } 914 } 915#endif /* __APPLE__ */ 916 if (pwd->pw_shell) { 917 (void)setenv("SHELL", pwd->pw_shell, 1); 918 } else { 919 syslog(LOG_ERR, "pwd->pw_shell not set - exiting"); 920 bail(NO_SLEEP_EXIT, 1); 921 } 922 if (pwd->pw_dir) { 923 (void)setenv("HOME", pwd->pw_dir, 1); 924 } else { 925 (void)setenv("HOME", "/", 1); 926 } 927 /* Overwrite "term" from login.conf(5) for any known TERM */ 928 if (term == NULL && (tp = stypeof(tty)) != NULL) 929 (void)setenv("TERM", tp, 1); 930 else 931 (void)setenv("TERM", TERM_UNKNOWN, 0); 932 (void)setenv("LOGNAME", username, 1); 933 (void)setenv("USER", username, 1); 934 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 935 936#ifdef __APPLE__ 937 /* Re-enable crash reporter */ 938 do { 939 kern_return_t kr; 940 mach_port_t bp, ep, mts; 941 thread_state_flavor_t flavor = 0; 942 943#if defined(__ppc__) 944 flavor = PPC_THREAD_STATE64; 945#elif defined(__i386__) || defined(__x86_64__) 946 flavor = x86_THREAD_STATE; 947#elif defined(__arm__) 948 flavor = ARM_THREAD_STATE; 949#else 950#error unsupported architecture 951#endif 952 953 mts = mach_task_self(); 954 955 kr = task_get_bootstrap_port(mts, &bp); 956 if (kr != KERN_SUCCESS) { 957 syslog(LOG_ERR, "task_get_bootstrap_port() failure: %s (%d)", 958 bootstrap_strerror(kr), kr); 959 break; 960 } 961 962 const char* bs = "com.apple.ReportCrash"; 963 kr = bootstrap_look_up(bp, (char*)bs, &ep); 964 if (kr != KERN_SUCCESS) { 965 syslog(LOG_ERR, "bootstrap_look_up(%s) failure: %s (%d)", 966 bs, bootstrap_strerror(kr), kr); 967 break; 968 } 969 970 kr = task_set_exception_ports(mts, EXC_MASK_CRASH, ep, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, flavor); 971 if (kr != KERN_SUCCESS) { 972 syslog(LOG_ERR, "task_set_exception_ports() failure: %d", kr); 973 break; 974 } 975 } while (0); 976#endif /* __APPLE__ */ 977 978 if (!quietlog) { 979#ifdef LOGIN_CAP 980 const char *cw; 981 982 cw = login_getcapstr(lc, "copyright", NULL, NULL); 983 if (cw == NULL || motd(cw) == -1) 984 (void)printf("%s", copyright); 985 986 (void)printf("\n"); 987 988 cw = login_getcapstr(lc, "welcome", NULL, NULL); 989 if (cw != NULL && access(cw, F_OK) == 0) 990 motd(cw); 991 else 992 motd(_PATH_MOTDFILE); 993 994 if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 && 995 login_getcapbool(lc, "nocheckmail", 0) == 0) { 996#else /* !LOGIN_CAP */ 997 motd(_PATH_MOTDFILE); 998 { 999#endif /* !LOGIN_CAP */ 1000 char *cx; 1001 1002 /* $MAIL may have been set by class. */ 1003 cx = getenv("MAIL"); 1004 if (cx == NULL) { 1005 asprintf(&cx, "%s/%s", 1006 _PATH_MAILDIR, pwd->pw_name); 1007 } 1008 if (cx && stat(cx, &st) == 0 && st.st_size != 0) 1009 (void)printf("You have %smail.\n", 1010 (st.st_mtime > st.st_atime) ? "new " : ""); 1011 if (getenv("MAIL") == NULL) 1012 free(cx); 1013 } 1014 } 1015 1016#ifdef LOGIN_CAP 1017 login_close(lc_user); 1018 login_close(lc); 1019#endif /* LOGIN_CAP */ 1020 1021 (void)signal(SIGALRM, SIG_DFL); 1022 (void)signal(SIGQUIT, SIG_DFL); 1023 (void)signal(SIGINT, SIG_DFL); 1024 (void)signal(SIGTSTP, SIG_IGN); 1025 1026#ifdef __APPLE__ 1027 if (fflag && *argv) pwd->pw_shell = *argv; 1028#endif /* __APPLE__ */ 1029 1030 /* 1031 * Login shells have a leading '-' in front of argv[0] 1032 */ 1033 p = strrchr(pwd->pw_shell, '/'); 1034#ifdef __APPLE__ 1035 if (asprintf(&arg0, "%s%s", lflag ? "" : "-", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) { 1036#else /* __APPLE__ */ 1037 if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) { 1038#endif /* __APPLE__ */ 1039 syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 1040 username); 1041 errx(1, "shell exceeds maximum pathname size"); 1042 } else if (arg0 == NULL) { 1043 err(1, "asprintf()"); 1044 } 1045 1046#ifdef __APPLE__ 1047 if (fflag && *argv) { 1048 *argv = arg0; 1049 execvp(pwd->pw_shell, argv); 1050 err(1, "%s", arg0); 1051 } 1052#endif /* __APPLE__ */ 1053 execlp(shell, arg0, (char *)0); 1054 err(1, "%s", shell); 1055 1056 /* 1057 * That's it, folks! 1058 */ 1059} 1060 1061#ifdef USE_PAM 1062/* 1063 * Attempt to authenticate the user using PAM. Returns 0 if the user is 1064 * authenticated, or 1 if not authenticated. If some sort of PAM system 1065 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 1066 * function returns -1. This can be used as an indication that we should 1067 * fall back to a different authentication mechanism. 1068 */ 1069static int 1070auth_pam(int skip_auth) 1071{ 1072 const char *tmpl_user; 1073 const void *item; 1074 int rval; 1075 1076 rval = 0; 1077 1078 if (skip_auth == 0) 1079 { 1080 pam_err = pam_authenticate(pamh, pam_silent); 1081 switch (pam_err) { 1082 1083 case PAM_SUCCESS: 1084 /* 1085 * With PAM we support the concept of a "template" 1086 * user. The user enters a login name which is 1087 * authenticated by PAM, usually via a remote service 1088 * such as RADIUS or TACACS+. If authentication 1089 * succeeds, a different but related "template" name 1090 * is used for setting the credentials, shell, and 1091 * home directory. The name the user enters need only 1092 * exist on the remote authentication server, but the 1093 * template name must be present in the local password 1094 * database. 1095 * 1096 * This is supported by two various mechanisms in the 1097 * individual modules. However, from the application's 1098 * point of view, the template user is always passed 1099 * back as a changed value of the PAM_USER item. 1100 */ 1101 pam_err = pam_get_item(pamh, PAM_USER, &item); 1102 if (pam_err == PAM_SUCCESS) { 1103 tmpl_user = (const char *)item; 1104 if (strcmp(username, tmpl_user) != 0) 1105 pwd = getpwnam(tmpl_user); 1106 } else { 1107 pam_syslog("pam_get_item(PAM_USER)"); 1108 } 1109 rval = 0; 1110 break; 1111 1112 case PAM_AUTH_ERR: 1113 case PAM_USER_UNKNOWN: 1114 case PAM_MAXTRIES: 1115 rval = 1; 1116 break; 1117 1118 default: 1119 pam_syslog("pam_authenticate()"); 1120 rval = -1; 1121 break; 1122 } 1123 } 1124 1125 if (rval == 0) { 1126 pam_err = pam_acct_mgmt(pamh, pam_silent); 1127 switch (pam_err) { 1128 case PAM_SUCCESS: 1129 break; 1130 case PAM_NEW_AUTHTOK_REQD: 1131 if (skip_auth == 0) 1132 { 1133 pam_err = pam_chauthtok(pamh, 1134 pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK); 1135 if (pam_err != PAM_SUCCESS) { 1136 pam_syslog("pam_chauthtok()"); 1137 rval = 1; 1138 } 1139 } 1140 else 1141 { 1142 pam_syslog("pam_acct_mgmt()"); 1143 } 1144 break; 1145 default: 1146 pam_syslog("pam_acct_mgmt()"); 1147 rval = 1; 1148 break; 1149 } 1150 } 1151 1152 if (rval != 0) { 1153 pam_end(pamh, pam_err); 1154 pamh = NULL; 1155 } 1156 return (rval); 1157} 1158 1159/* 1160 * Export any environment variables PAM modules may have set 1161 */ 1162static void 1163export_pam_environment() 1164{ 1165 char **pam_env; 1166 char **pp; 1167 1168 pam_env = pam_getenvlist(pamh); 1169 if (pam_env != NULL) { 1170 for (pp = pam_env; *pp != NULL; pp++) { 1171 (void)export(*pp); 1172 free(*pp); 1173 } 1174 } 1175} 1176 1177/* 1178 * Perform sanity checks on an environment variable: 1179 * - Make sure there is an '=' in the string. 1180 * - Make sure the string doesn't run on too long. 1181 * - Do not export certain variables. This list was taken from the 1182 * Solaris pam_putenv(3) man page. 1183 * Then export it. 1184 */ 1185static int 1186export(const char *s) 1187{ 1188 static const char *noexport[] = { 1189 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 1190 "IFS", "PATH", NULL 1191 }; 1192 char *p; 1193 const char **pp; 1194 size_t n; 1195 1196 if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL) 1197 return (0); 1198 if (strncmp(s, "LD_", 3) == 0) 1199 return (0); 1200 for (pp = noexport; *pp != NULL; pp++) { 1201 n = strlen(*pp); 1202 if (s[n] == '=' && strncmp(s, *pp, n) == 0) 1203 return (0); 1204 } 1205 *p = '\0'; 1206 (void)setenv(s, p + 1, 1); 1207 *p = '='; 1208 return (1); 1209} 1210#endif /* USE_PAM */ 1211 1212static void 1213usage() 1214{ 1215#ifdef __APPLE__ 1216 (void)fprintf(stderr, "usage: login [-pq] [-h hostname] [username]\n"); 1217 (void)fprintf(stderr, " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n"); 1218#else 1219 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 1220#endif 1221 exit(1); 1222} 1223 1224/* 1225 * Prompt user and read login name from stdin. 1226 */ 1227static char * 1228getloginname() 1229{ 1230 char *nbuf, *p; 1231 int ch; 1232 1233 nbuf = malloc(MAXLOGNAME); 1234 if (nbuf == NULL) 1235 err(1, "malloc()"); 1236 do { 1237 (void)printf("%s", prompt); 1238 for (p = nbuf; (ch = getchar()) != '\n'; ) { 1239 if (ch == EOF) { 1240 badlogin(username); 1241 bail(NO_SLEEP_EXIT, 0); 1242 } 1243 if (p < nbuf + MAXLOGNAME - 1) 1244 *p++ = ch; 1245 } 1246 } while (p == nbuf); 1247 1248 *p = '\0'; 1249 if (nbuf[0] == '-') { 1250#ifdef USE_PAM 1251 pam_silent = 0; 1252#endif /* USE_PAM */ 1253 memmove(nbuf, nbuf + 1, strlen(nbuf)); 1254 } else { 1255#ifdef USE_PAM 1256 pam_silent = PAM_SILENT; 1257#endif /* USE_PAM */ 1258 } 1259 return nbuf; 1260} 1261 1262#ifdef __APPLE__ 1263#ifndef USE_PAM 1264static int 1265rootterm(const char* ttyn) 1266{ 1267 struct ttyent *t; 1268 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 1269} 1270#endif /* !USE_PAM */ 1271#endif /* __APPLE__ */ 1272 1273/* 1274 * SIGINT handler for motd(). 1275 */ 1276static volatile int motdinterrupt; 1277static void 1278sigint(int signo __unused) 1279{ 1280 motdinterrupt = 1; 1281} 1282 1283/* 1284 * Display the contents of a file (such as /etc/motd). 1285 */ 1286static int 1287motd(const char *motdfile) 1288{ 1289 sig_t oldint; 1290 FILE *f; 1291 int ch; 1292 1293 if ((f = fopen(motdfile, "r")) == NULL) 1294 return (-1); 1295 motdinterrupt = 0; 1296 oldint = signal(SIGINT, sigint); 1297 while ((ch = fgetc(f)) != EOF && !motdinterrupt) 1298 putchar(ch); 1299 signal(SIGINT, oldint); 1300 if (ch != EOF || ferror(f)) { 1301 fclose(f); 1302 return (-1); 1303 } 1304 fclose(f); 1305 return (0); 1306} 1307 1308/* 1309 * SIGHUP handler 1310 * Forwards the SIGHUP to the child process and current process group. 1311 */ 1312static void 1313handle_sighup(int signo) 1314{ 1315 if (pid > 0) { 1316 /* close the controlling terminal */ 1317 close(STDIN_FILENO); 1318 close(STDOUT_FILENO); 1319 close(STDERR_FILENO); 1320 /* Ignore SIGHUP to avoid tail-recursion on signaling 1321 the current process group (of which we are a member). */ 1322 (void)signal(SIGHUP, SIG_IGN); 1323 /* Forward the signal to the current process group. */ 1324 (void)kill(0, signo); 1325 /* Forward the signal to the child if not a member of the current 1326 * process group <rdar://problem/6244808>. */ 1327 if (getpgid(pid) != getpgrp()) { 1328 (void)kill(pid, signo); 1329 } 1330 } 1331} 1332 1333/* 1334 * SIGALRM handler, to enforce login prompt timeout. 1335 * 1336 * XXX This can potentially confuse the hell out of PAM. We should 1337 * XXX instead implement a conversation function that returns 1338 * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal 1339 * XXX handler just set a flag. 1340 */ 1341static void 1342timedout(int signo __unused) 1343{ 1344 1345 longjmp(timeout_buf, signo); 1346} 1347 1348#ifdef __APPLE__ 1349#ifndef USE_PAM 1350void 1351checknologin() 1352{ 1353 int fd, nchars; 1354 char tbuf[8192]; 1355 1356 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 1357 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 1358 (void)write(fileno(stdout), tbuf, nchars); 1359#ifdef USE_BSM_AUDIT 1360 au_login_fail("No login", 0); 1361#endif 1362 sleep(5); 1363 exit(0); 1364 } 1365} 1366#endif /* !USE_PAM */ 1367 1368void 1369dolastlog(quiet) 1370 int quiet; 1371{ 1372#ifdef USE_PAM 1373 if (quiet) 1374 return; 1375 if (*lastlog.ll_line) { 1376 (void)printf("Last login: %.*s ", 1377 24-5, (char *)ctime(&lastlog.ll_tv.tv_sec)); 1378 if (*lastlog.ll_host != '\0') 1379 (void)printf("from %.*s\n", 1380 (int)sizeof(lastlog.ll_host), 1381 lastlog.ll_host); 1382 else 1383 (void)printf("on %.*s\n", 1384 (int)sizeof(lastlog.ll_line), 1385 lastlog.ll_line); 1386 } 1387#else /* !USE_PAM */ 1388 struct lastlogx ll; 1389 1390 if(!quiet && getlastlogx(pwd->pw_uid, &ll) != NULL) { 1391 (void)printf("Last login: %.*s ", 1392 24-5, (char *)ctime(&ll.ll_tv.tv_sec)); 1393 if (*ll.ll_host != '\0') 1394 (void)printf("from %.*s\n", 1395 (int)sizeof(ll.ll_host), 1396 ll.ll_host); 1397 else 1398 (void)printf("on %.*s\n", 1399 (int)sizeof(ll.ll_line), 1400 ll.ll_line); 1401 } 1402#endif /* USE_PAM */ 1403} 1404#endif /* __APPLE__ */ 1405 1406static void 1407badlogin(char *name) 1408{ 1409 1410 if (failures == 0) 1411 return; 1412 if (hflag) { 1413 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 1414 failures, failures > 1 ? "S" : "", hostname); 1415 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1416 "%d LOGIN FAILURE%s FROM %s, %s", 1417 failures, failures > 1 ? "S" : "", hostname, name); 1418 } else { 1419 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 1420 failures, failures > 1 ? "S" : "", tty); 1421 syslog(LOG_AUTHPRIV|LOG_NOTICE, 1422 "%d LOGIN FAILURE%s ON %s, %s", 1423 failures, failures > 1 ? "S" : "", tty, name); 1424 } 1425 failures = 0; 1426} 1427 1428const char * 1429stypeof(char *ttyid) 1430{ 1431 struct ttyent *t; 1432 1433 if (ttyid != NULL && *ttyid != '\0') { 1434 t = getttynam(ttyid); 1435 if (t != NULL && t->ty_type != NULL) 1436 return (t->ty_type); 1437 } 1438 return (NULL); 1439} 1440 1441static void 1442refused(const char *msg, const char *rtype, int lout) 1443{ 1444 1445 if (msg != NULL) 1446 printf("%s.\n", msg); 1447 if (hflag) 1448 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 1449 pwd->pw_name, rtype, hostname, tty); 1450 else 1451 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 1452 pwd->pw_name, rtype, tty); 1453 if (lout) 1454 bail(SLEEP_EXIT, 1); 1455} 1456 1457#ifdef USE_PAM 1458/* 1459 * Log a PAM error 1460 */ 1461static void 1462pam_syslog(const char *msg) 1463{ 1464 syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); 1465} 1466 1467/* 1468 * Shut down PAM 1469 */ 1470static void 1471pam_cleanup() 1472{ 1473 1474 if (pamh != NULL) { 1475 if (pam_session_established) { 1476 pam_err = pam_close_session(pamh, 0); 1477 if (pam_err != PAM_SUCCESS) 1478 pam_syslog("pam_close_session()"); 1479 } 1480 pam_session_established = 0; 1481 if (pam_cred_established) { 1482 pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED); 1483 if (pam_err != PAM_SUCCESS) 1484 pam_syslog("pam_setcred()"); 1485 } 1486 pam_cred_established = 0; 1487 pam_end(pamh, pam_err); 1488 pamh = NULL; 1489 } 1490} 1491#endif /* USE_PAM */ 1492 1493/* 1494 * Exit, optionally after sleeping a few seconds 1495 */ 1496void 1497bail(int sec, int eval) 1498{ 1499 1500#ifdef USE_PAM 1501 pam_cleanup(); 1502#endif /* USE_PAM */ 1503#ifdef USE_BSM_AUDIT 1504 if (pwd != NULL) 1505 audit_logout(); 1506#endif 1507 (void)sleep(sec); 1508 exit(eval); 1509} 1510