11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 489615Sdes * Copyright (c) 2002 Networks Associates Technologies, Inc. 589615Sdes * All rights reserved. 61590Srgrimes * 789615Sdes * Portions of this software were developed for the FreeBSD Project by 889615Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network 989615Sdes * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1089615Sdes * ("CBOSS"), as part of the DARPA CHATS research program. 1189615Sdes * 121590Srgrimes * Redistribution and use in source and binary forms, with or without 131590Srgrimes * modification, are permitted provided that the following conditions 141590Srgrimes * are met: 151590Srgrimes * 1. Redistributions of source code must retain the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer. 171590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181590Srgrimes * notice, this list of conditions and the following disclaimer in the 191590Srgrimes * documentation and/or other materials provided with the distribution. 201590Srgrimes * 3. All advertising materials mentioning features or use of this software 211590Srgrimes * must display the following acknowledgement: 221590Srgrimes * This product includes software developed by the University of 231590Srgrimes * California, Berkeley and its contributors. 241590Srgrimes * 4. Neither the name of the University nor the names of its contributors 251590Srgrimes * may be used to endorse or promote products derived from this software 261590Srgrimes * without specific prior written permission. 271590Srgrimes * 281590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 291590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 301590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 311590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 321590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 331590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 341590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 351590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 361590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 371590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 381590Srgrimes * SUCH DAMAGE. 391590Srgrimes */ 401590Srgrimes 4187628Sdwmalone#if 0 4287628Sdwmalone#ifndef lint 4387628Sdwmalonestatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 4487628Sdwmalone#endif 4587628Sdwmalone#endif 4687628Sdwmalone 4787233Smarkm#include <sys/cdefs.h> 4887233Smarkm__FBSDID("$FreeBSD$"); 4987233Smarkm 501590Srgrimes/* 511590Srgrimes * login [ name ] 521590Srgrimes * login -h hostname (for telnetd, etc.) 531590Srgrimes * login -f name (for pre-authenticated login: datakit, xterm, etc.) 541590Srgrimes */ 551590Srgrimes 5687180Smarkm#include <sys/param.h> 5787180Smarkm#include <sys/file.h> 581590Srgrimes#include <sys/stat.h> 591590Srgrimes#include <sys/time.h> 601590Srgrimes#include <sys/resource.h> 6187180Smarkm#include <sys/wait.h> 621590Srgrimes 631590Srgrimes#include <err.h> 641590Srgrimes#include <errno.h> 651590Srgrimes#include <grp.h> 66200462Sdelphij#include <libutil.h> 6741079Sjdp#include <login_cap.h> 681590Srgrimes#include <pwd.h> 691590Srgrimes#include <setjmp.h> 701590Srgrimes#include <signal.h> 711590Srgrimes#include <stdio.h> 721590Srgrimes#include <stdlib.h> 731590Srgrimes#include <string.h> 741590Srgrimes#include <syslog.h> 751590Srgrimes#include <ttyent.h> 761590Srgrimes#include <unistd.h> 771590Srgrimes 7841279Sjdp#include <security/pam_appl.h> 7991714Sdes#include <security/openpam.h> 803702Spst 8187173Smarkm#include "login.h" 821590Srgrimes#include "pathnames.h" 831590Srgrimes 8489994Sdesstatic int auth_pam(void); 8589994Sdesstatic void bail(int, int); 86264309Sjillesstatic void bail_internal(int, int, int); 8789994Sdesstatic int export(const char *); 8889994Sdesstatic void export_pam_environment(void); 8989994Sdesstatic int motd(const char *); 9089994Sdesstatic void badlogin(char *); 9189994Sdesstatic char *getloginname(void); 9289994Sdesstatic void pam_syslog(const char *); 9389994Sdesstatic void pam_cleanup(void); 9489994Sdesstatic void refused(const char *, const char *, int); 9589994Sdesstatic const char *stypeof(char *); 9689994Sdesstatic void sigint(int); 9789994Sdesstatic void timedout(int); 98264309Sjillesstatic void bail_sig(int); 9989994Sdesstatic void usage(void); 1001590Srgrimes 10187173Smarkm#define TTYGRPNAME "tty" /* group to own ttys */ 10287173Smarkm#define DEFAULT_BACKOFF 3 10387173Smarkm#define DEFAULT_RETRIES 10 10476786Sobrien#define DEFAULT_PROMPT "login: " 10576786Sobrien#define DEFAULT_PASSWD_PROMPT "Password:" 10689994Sdes#define TERM_UNKNOWN "su" 10787173Smarkm#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 10889994Sdes#define NO_SLEEP_EXIT 0 10989994Sdes#define SLEEP_EXIT 5 1101590Srgrimes 1111590Srgrimes/* 1121590Srgrimes * This bounds the time given to login. Not a define so it can 1131590Srgrimes * be patched on machines where it's too small. 1141590Srgrimes */ 11589994Sdesstatic u_int timeout = 300; 1161590Srgrimes 11742272Seivind/* Buffer for signal handling of timeout */ 11889994Sdesstatic jmp_buf timeout_buf; 11942272Seivind 12089994Sdesstruct passwd *pwd; 12189994Sdesstatic int failures; 1221590Srgrimes 12389994Sdesstatic char *envinit[1]; /* empty environment list */ 12489994Sdes 12589994Sdes/* 12689994Sdes * Command line flags and arguments 12789994Sdes */ 12889994Sdesstatic int fflag; /* -f: do not perform authentication */ 12989994Sdesstatic int hflag; /* -h: login from remote host */ 13089994Sdesstatic char *hostname; /* hostname from command line */ 13189994Sdesstatic int pflag; /* -p: preserve environment */ 13289994Sdes 13389994Sdes/* 13489994Sdes * User name 13589994Sdes */ 13689994Sdesstatic char *username; /* user name */ 13789994Sdesstatic char *olduser; /* previous user name */ 13889994Sdes 13989994Sdes/* 14089994Sdes * Prompts 14189994Sdes */ 14289994Sdesstatic char default_prompt[] = DEFAULT_PROMPT; 14394203Srustatic const char *prompt; 14489994Sdesstatic char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT; 14594203Srustatic const char *passwd_prompt; 14689994Sdes 14789994Sdesstatic char *tty; 14889994Sdes 14989994Sdes/* 15089994Sdes * PAM data 15189994Sdes */ 15289994Sdesstatic pam_handle_t *pamh = NULL; 15391714Sdesstatic struct pam_conv pamc = { openpam_ttyconv, NULL }; 15489994Sdesstatic int pam_err; 15589994Sdesstatic int pam_silent = PAM_SILENT; 15689994Sdesstatic int pam_cred_established; 15789994Sdesstatic int pam_session_established; 15889994Sdes 1591590Srgrimesint 16089994Sdesmain(int argc, char *argv[]) 1611590Srgrimes{ 1621590Srgrimes struct group *gr; 1631590Srgrimes struct stat st; 16489994Sdes int retries, backoff; 16589994Sdes int ask, ch, cnt, quietlog, rootlogin, rval; 16635559Speter uid_t uid, euid; 16746007Sache gid_t egid; 16889994Sdes char *term; 16945431Sbrian char *p, *ttyn; 17042272Seivind char tname[sizeof(_PATH_TTY) + 10]; 17194203Sru char *arg0; 17298960Sache const char *tp; 17394203Sru const char *shell = NULL; 17421528Sdavidn login_cap_t *lc = NULL; 175146867Smaxim login_cap_t *lc_user = NULL; 17674874Smarkm pid_t pid; 177264309Sjilles sigset_t mask, omask; 178264309Sjilles struct sigaction sa; 179165152Scsjp#ifdef USE_BSM_AUDIT 180155312Swsalamon char auditsuccess = 1; 181165152Scsjp#endif 1821590Srgrimes 183264309Sjilles sa.sa_flags = SA_RESTART; 184264309Sjilles (void)sigfillset(&sa.sa_mask); 185264309Sjilles sa.sa_handler = SIG_IGN; 186264309Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 187264309Sjilles (void)sigaction(SIGINT, &sa, NULL); 188264309Sjilles (void)sigaction(SIGHUP, &sa, NULL); 18942272Seivind if (setjmp(timeout_buf)) { 19042272Seivind if (failures) 19189994Sdes badlogin(username); 19276788Sobrien (void)fprintf(stderr, "Login timed out after %d seconds\n", 19376788Sobrien timeout); 19489994Sdes bail(NO_SLEEP_EXIT, 0); 19542272Seivind } 196264309Sjilles sa.sa_handler = timedout; 197264309Sjilles (void)sigaction(SIGALRM, &sa, NULL); 1981590Srgrimes (void)alarm(timeout); 1991590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 2001590Srgrimes 2011590Srgrimes openlog("login", LOG_ODELAY, LOG_AUTH); 2021590Srgrimes 2031590Srgrimes uid = getuid(); 20435557Speter euid = geteuid(); 20546007Sache egid = getegid(); 20689994Sdes 20724360Simp while ((ch = getopt(argc, argv, "fh:p")) != -1) 2081590Srgrimes switch (ch) { 2091590Srgrimes case 'f': 2101590Srgrimes fflag = 1; 2111590Srgrimes break; 2121590Srgrimes case 'h': 21389994Sdes if (uid != 0) 2141590Srgrimes errx(1, "-h option: %s", strerror(EPERM)); 21589994Sdes if (strlen(optarg) >= MAXHOSTNAMELEN) 21681555Smike errx(1, "-h option: %s: exceeds maximum " 21781555Smike "hostname size", optarg); 21889994Sdes hflag = 1; 2191590Srgrimes hostname = optarg; 2201590Srgrimes break; 2211590Srgrimes case 'p': 2221590Srgrimes pflag = 1; 2231590Srgrimes break; 2241590Srgrimes case '?': 2251590Srgrimes default: 22689994Sdes if (uid == 0) 2271590Srgrimes syslog(LOG_ERR, "invalid flag %c", ch); 22827605Scharnier usage(); 2291590Srgrimes } 2301590Srgrimes argc -= optind; 2311590Srgrimes argv += optind; 2321590Srgrimes 23389994Sdes if (argc > 0) { 23489994Sdes username = strdup(*argv); 23589994Sdes if (username == NULL) 23689994Sdes err(1, "strdup()"); 2371590Srgrimes ask = 0; 23889994Sdes } else { 2391590Srgrimes ask = 1; 24089994Sdes } 2411590Srgrimes 242107585Sdes setproctitle("-%s", getprogname()); 243107585Sdes 244214115Sed closefrom(3); 2451590Srgrimes 24689994Sdes /* 24789994Sdes * Get current TTY 24889994Sdes */ 2491590Srgrimes ttyn = ttyname(STDIN_FILENO); 2501590Srgrimes if (ttyn == NULL || *ttyn == '\0') { 2511590Srgrimes (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 2521590Srgrimes ttyn = tname; 2531590Srgrimes } 254190474Sed if (strncmp(ttyn, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) 255190474Sed tty = ttyn + sizeof _PATH_DEV - 1; 2561590Srgrimes else 2571590Srgrimes tty = ttyn; 2581590Srgrimes 25923985Sdavidn /* 26023985Sdavidn * Get "login-retries" & "login-backoff" from default class 26123985Sdavidn */ 26223985Sdavidn lc = login_getclass(NULL); 263114010Sdes prompt = login_getcapstr(lc, "login_prompt", 26489994Sdes default_prompt, default_prompt); 26576786Sobrien passwd_prompt = login_getcapstr(lc, "passwd_prompt", 26687173Smarkm default_passwd_prompt, default_passwd_prompt); 26789994Sdes retries = login_getcapnum(lc, "login-retries", 26889994Sdes DEFAULT_RETRIES, DEFAULT_RETRIES); 26989994Sdes backoff = login_getcapnum(lc, "login-backoff", 27089994Sdes DEFAULT_BACKOFF, DEFAULT_BACKOFF); 27123985Sdavidn login_close(lc); 27223985Sdavidn lc = NULL; 27321528Sdavidn 27489994Sdes /* 27589994Sdes * Try to authenticate the user until we succeed or time out. 27689994Sdes */ 2771590Srgrimes for (cnt = 0;; ask = 1) { 2781590Srgrimes if (ask) { 2791590Srgrimes fflag = 0; 28089994Sdes if (olduser != NULL) 28189994Sdes free(olduser); 28289994Sdes olduser = username; 28389994Sdes username = getloginname(); 2841590Srgrimes } 2851590Srgrimes rootlogin = 0; 28621528Sdavidn 2871590Srgrimes /* 2881590Srgrimes * Note if trying multiple user names; log failures for 2891590Srgrimes * previous user name, but don't bother logging one failure 2901590Srgrimes * for nonexistent name (mistyped username). 2911590Srgrimes */ 29289994Sdes if (failures && strcmp(olduser, username) != 0) { 2931590Srgrimes if (failures > (pwd ? 0 : 1)) 29489994Sdes badlogin(olduser); 2951590Srgrimes } 2961590Srgrimes 29723985Sdavidn /* 29889994Sdes * Load the PAM policy and set some variables 2991590Srgrimes */ 30089994Sdes pam_err = pam_start("login", username, &pamc, &pamh); 30189994Sdes if (pam_err != PAM_SUCCESS) { 30289994Sdes pam_syslog("pam_start()"); 303165152Scsjp#ifdef USE_BSM_AUDIT 304155312Swsalamon au_login_fail("PAM Error", 1); 305165152Scsjp#endif 30689994Sdes bail(NO_SLEEP_EXIT, 1); 3073205Spst } 30889994Sdes pam_err = pam_set_item(pamh, PAM_TTY, tty); 30989994Sdes if (pam_err != PAM_SUCCESS) { 31089994Sdes pam_syslog("pam_set_item(PAM_TTY)"); 311165152Scsjp#ifdef USE_BSM_AUDIT 312155312Swsalamon au_login_fail("PAM Error", 1); 313165152Scsjp#endif 31489994Sdes bail(NO_SLEEP_EXIT, 1); 31589994Sdes } 316110966Sdes pam_err = pam_set_item(pamh, PAM_RHOST, hostname); 31789994Sdes if (pam_err != PAM_SUCCESS) { 31889994Sdes pam_syslog("pam_set_item(PAM_RHOST)"); 319165152Scsjp#ifdef USE_BSM_AUDIT 320155312Swsalamon au_login_fail("PAM Error", 1); 321165152Scsjp#endif 32289994Sdes bail(NO_SLEEP_EXIT, 1); 32389994Sdes } 32497376Sdes 32589994Sdes pwd = getpwnam(username); 32641279Sjdp if (pwd != NULL && pwd->pw_uid == 0) 32741279Sjdp rootlogin = 1; 3281590Srgrimes 3291590Srgrimes /* 33089994Sdes * If the -f option was specified and the caller is 33189994Sdes * root or the caller isn't changing their uid, don't 33289994Sdes * authenticate. 3331590Srgrimes */ 33489994Sdes if (pwd != NULL && fflag && 33589994Sdes (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) { 33689994Sdes /* already authenticated */ 33789994Sdes rval = 0; 338165152Scsjp#ifdef USE_BSM_AUDIT 339155312Swsalamon auditsuccess = 0; /* opened a terminal window only */ 340165152Scsjp#endif 34189994Sdes } else { 34289994Sdes fflag = 0; 34389994Sdes (void)setpriority(PRIO_PROCESS, 0, -4); 34489994Sdes rval = auth_pam(); 34589994Sdes (void)setpriority(PRIO_PROCESS, 0, 0); 3461590Srgrimes } 3471590Srgrimes 34889994Sdes if (pwd && rval == 0) 34989994Sdes break; 35089994Sdes 35189994Sdes pam_cleanup(); 35297376Sdes 353155312Swsalamon /* 354155312Swsalamon * We are not exiting here, but this corresponds to a failed 355155312Swsalamon * login event, so set exitstatus to 1. 356155312Swsalamon */ 357165152Scsjp#ifdef USE_BSM_AUDIT 358155312Swsalamon au_login_fail("Login incorrect", 1); 359165152Scsjp#endif 360155312Swsalamon 3611590Srgrimes (void)printf("Login incorrect\n"); 3621590Srgrimes failures++; 36323985Sdavidn 364157215Scognet pwd = NULL; 365157215Scognet 36623985Sdavidn /* 36789994Sdes * Allow up to 'retry' (10) attempts, but start 36889994Sdes * backing off after 'backoff' (3) attempts. 36923985Sdavidn */ 37023985Sdavidn if (++cnt > backoff) { 37123985Sdavidn if (cnt >= retries) { 3721590Srgrimes badlogin(username); 37389994Sdes bail(SLEEP_EXIT, 1); 3741590Srgrimes } 37538374Sjkoshy sleep((u_int)((cnt - backoff) * 5)); 3761590Srgrimes } 3771590Srgrimes } 3781590Srgrimes 3791590Srgrimes /* committed to login -- turn off timeout */ 3801590Srgrimes (void)alarm((u_int)0); 3811590Srgrimes 382264309Sjilles (void)sigemptyset(&mask); 383264309Sjilles (void)sigaddset(&mask, SIGHUP); 384264309Sjilles (void)sigaddset(&mask, SIGTERM); 385264309Sjilles (void)sigprocmask(SIG_BLOCK, &mask, &omask); 386264309Sjilles sa.sa_handler = bail_sig; 387264309Sjilles (void)sigaction(SIGHUP, &sa, NULL); 388264309Sjilles (void)sigaction(SIGTERM, &sa, NULL); 389264309Sjilles 3901590Srgrimes endpwent(); 3911590Srgrimes 392165152Scsjp#ifdef USE_BSM_AUDIT 393155312Swsalamon /* Audit successful login. */ 394155312Swsalamon if (auditsuccess) 395155312Swsalamon au_login_success(); 396165152Scsjp#endif 397155312Swsalamon 398221374Sdfr /* 399221374Sdfr * This needs to happen before login_getpwclass to support 400221374Sdfr * home directories on GSS-API authenticated NFS where the 401221374Sdfr * kerberos credentials need to be saved so that the kernel 402221374Sdfr * can authenticate to the NFS server. 403221374Sdfr */ 404221374Sdfr pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED); 405221374Sdfr if (pam_err != PAM_SUCCESS) { 406221374Sdfr pam_syslog("pam_setcred()"); 407221374Sdfr bail(NO_SLEEP_EXIT, 1); 408221374Sdfr } 409221374Sdfr pam_cred_established = 1; 410221374Sdfr 41141279Sjdp /* 41241279Sjdp * Establish the login class. 41341279Sjdp */ 41441279Sjdp lc = login_getpwclass(pwd); 415146867Smaxim lc_user = login_getuserclass(pwd); 41641279Sjdp 417146867Smaxim if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0))) 418146867Smaxim quietlog = login_getcapbool(lc, "hushlogin", 0); 41997376Sdes 42083519Srwatson /* 42183519Srwatson * Switching needed for NFS with root access disabled. 42283519Srwatson * 42383519Srwatson * XXX: This change fails to modify the additional groups for the 42483519Srwatson * process, and as such, may restrict rights normally granted 42583519Srwatson * through those groups. 42683519Srwatson */ 42746007Sache (void)setegid(pwd->pw_gid); 42835557Speter (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 42921528Sdavidn if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 43026021Spst if (login_getcapbool(lc, "requirehome", 0)) 43123985Sdavidn refused("Home directory not available", "HOMEDIR", 1); 43297376Sdes if (chdir("/") < 0) 43323985Sdavidn refused("Cannot find root directory", "ROOTDIR", 1); 43423985Sdavidn if (!quietlog || *pwd->pw_dir) 43523985Sdavidn printf("No home directory.\nLogging in with home = \"/\".\n"); 43687173Smarkm pwd->pw_dir = strdup("/"); 43787173Smarkm if (pwd->pw_dir == NULL) { 43887173Smarkm syslog(LOG_NOTICE, "strdup(): %m"); 43989994Sdes bail(SLEEP_EXIT, 1); 44087173Smarkm } 4411590Srgrimes } 44235557Speter (void)seteuid(euid); 44346007Sache (void)setegid(egid); 444125055Sfjoe if (!quietlog) { 44521528Sdavidn quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 446125055Sfjoe if (!quietlog) 447125055Sfjoe pam_silent = 0; 448125055Sfjoe } 44997376Sdes 45097376Sdes shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 45123985Sdavidn if (*pwd->pw_shell == '\0') 45287173Smarkm pwd->pw_shell = strdup(_PATH_BSHELL); 45387173Smarkm if (pwd->pw_shell == NULL) { 45487173Smarkm syslog(LOG_NOTICE, "strdup(): %m"); 45589994Sdes bail(SLEEP_EXIT, 1); 45687173Smarkm } 45723985Sdavidn if (*shell == '\0') /* Not overridden */ 45823985Sdavidn shell = pwd->pw_shell; 45923985Sdavidn if ((shell = strdup(shell)) == NULL) { 46081555Smike syslog(LOG_NOTICE, "strdup(): %m"); 46189994Sdes bail(SLEEP_EXIT, 1); 46223985Sdavidn } 46321528Sdavidn 4642224Sguido /* 4652224Sguido * Set device protections, depending on what terminal the 4662224Sguido * user is logged in. This feature is used on Suns to give 4672224Sguido * console users better privacy. 4682224Sguido */ 4692224Sguido login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 4702224Sguido 47150124Simp /* 47250124Simp * Clear flags of the tty. None should be set, and when the 47350124Simp * user sets them otherwise, this can cause the chown to fail. 47450124Simp * Since it isn't clear that flags are useful on character 47550124Simp * devices, we just clear them. 476102141Simp * 477102141Simp * We don't log in the case of EOPNOTSUPP because dev might be 478102141Simp * on NFS, which doesn't support chflags. 479102141Simp * 480102141Simp * We don't log in the EROFS because that means that /dev is on 481102141Simp * a read only file system and we assume that the permissions there 482102141Simp * are sane. 48350124Simp */ 484102141Simp if (ttyn != tname && chflags(ttyn, 0)) 485102141Simp if (errno != EOPNOTSUPP && errno != EROFS) 486102141Simp syslog(LOG_ERR, "chflags(%s): %m", ttyn); 48789994Sdes if (ttyn != tname && chown(ttyn, pwd->pw_uid, 48850124Simp (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 489102141Simp if (errno != EROFS) 490114048Srwatson syslog(LOG_ERR, "chown(%s): %m", ttyn); 4911590Srgrimes 49223985Sdavidn /* 49323985Sdavidn * Exclude cons/vt/ptys only, assume dialup otherwise 49423985Sdavidn * TODO: Make dialup tty determination a library call 49523985Sdavidn * for consistency (finger etc.) 49623985Sdavidn */ 49789994Sdes if (hflag && isdialuptty(tty)) 4981590Srgrimes syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 4991590Srgrimes 5003205Spst#ifdef LOGALL 5013205Spst /* 50289994Sdes * Syslog each successful login, so we don't have to watch 50389994Sdes * hundreds of wtmp or lastlogin files. 5043205Spst */ 50589994Sdes if (hflag) 50623985Sdavidn syslog(LOG_INFO, "login from %s on %s as %s", 50789994Sdes hostname, tty, pwd->pw_name); 50823985Sdavidn else 50923985Sdavidn syslog(LOG_INFO, "login on %s as %s", 51023985Sdavidn tty, pwd->pw_name); 51121528Sdavidn#endif 51221528Sdavidn 51323985Sdavidn /* 51489994Sdes * If fflag is on, assume caller/authenticator has logged root 51589994Sdes * login. 51623985Sdavidn */ 51789994Sdes if (rootlogin && fflag == 0) { 51889994Sdes if (hflag) 51923985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 52089994Sdes username, tty, hostname); 52123985Sdavidn else 52223985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 52376788Sobrien username, tty); 52423985Sdavidn } 52523985Sdavidn 52623985Sdavidn /* 52789994Sdes * Destroy environment unless user has requested its 52889994Sdes * preservation - but preserve TERM in all cases 52923985Sdavidn */ 53089994Sdes term = getenv("TERM"); 53121528Sdavidn if (!pflag) 53221528Sdavidn environ = envinit; 53389994Sdes if (term != NULL) 53489994Sdes setenv("TERM", term, 0); 53521528Sdavidn 53623985Sdavidn /* 53774874Smarkm * PAM modules might add supplementary groups during pam_setcred(). 53874874Smarkm */ 53974874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 54097376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 54189994Sdes bail(NO_SLEEP_EXIT, 1); 54274874Smarkm } 54374874Smarkm 544221374Sdfr pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED); 54589994Sdes if (pam_err != PAM_SUCCESS) { 54689994Sdes pam_syslog("pam_setcred()"); 54789994Sdes bail(NO_SLEEP_EXIT, 1); 54889994Sdes } 54997376Sdes 55089994Sdes pam_err = pam_open_session(pamh, pam_silent); 55189994Sdes if (pam_err != PAM_SUCCESS) { 55289994Sdes pam_syslog("pam_open_session()"); 55389994Sdes bail(NO_SLEEP_EXIT, 1); 55489994Sdes } 55589994Sdes pam_session_established = 1; 55674874Smarkm 55789994Sdes /* 55889994Sdes * We must fork() before setuid() because we need to call 55989994Sdes * pam_close_session() as root. 56089994Sdes */ 56189994Sdes pid = fork(); 56289994Sdes if (pid < 0) { 56389994Sdes err(1, "fork"); 56489994Sdes } else if (pid != 0) { 56574874Smarkm /* 56689994Sdes * Parent: wait for child to finish, then clean up 56789994Sdes * session. 568264309Sjilles * 569264309Sjilles * If we get SIGHUP or SIGTERM, clean up the session 570264309Sjilles * and exit right away. This will make the terminal 571264309Sjilles * inaccessible and send SIGHUP to the foreground 572264309Sjilles * process group. 57374874Smarkm */ 574110549Sdes int status; 575107585Sdes setproctitle("-%s [pam]", getprogname()); 576264309Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 577110549Sdes waitpid(pid, &status, 0); 578264309Sjilles (void)sigprocmask(SIG_BLOCK, &mask, NULL); 57989994Sdes bail(NO_SLEEP_EXIT, 0); 58074874Smarkm } 58174874Smarkm 58274874Smarkm /* 58389994Sdes * NOTICE: We are now in the child process! 58421528Sdavidn */ 58597376Sdes 58689994Sdes /* 58789994Sdes * Add any environment variables the PAM modules may have set. 58889994Sdes */ 58989994Sdes export_pam_environment(); 59089994Sdes 59189994Sdes /* 59289994Sdes * We're done with PAM now; our parent will deal with the rest. 59389994Sdes */ 59491714Sdes pam_end(pamh, 0); 59589994Sdes pamh = NULL; 59689994Sdes 59789994Sdes /* 59889994Sdes * We don't need to be root anymore, so set the login name and 59989994Sdes * the UID. 60089994Sdes */ 60141279Sjdp if (setlogin(username) != 0) { 60297376Sdes syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 60389994Sdes bail(NO_SLEEP_EXIT, 1); 60441279Sjdp } 60541279Sjdp if (setusercontext(lc, pwd, pwd->pw_uid, 60674874Smarkm LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 60797376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 60821528Sdavidn exit(1); 6093205Spst } 61021528Sdavidn 61123148Sache (void)setenv("SHELL", pwd->pw_shell, 1); 61221528Sdavidn (void)setenv("HOME", pwd->pw_dir, 1); 61398960Sache /* Overwrite "term" from login.conf(5) for any known TERM */ 61498990Sache if (term == NULL && (tp = stypeof(tty)) != NULL) 61598960Sache (void)setenv("TERM", tp, 1); 61698960Sache else 61798960Sache (void)setenv("TERM", TERM_UNKNOWN, 0); 61841279Sjdp (void)setenv("LOGNAME", username, 1); 61941279Sjdp (void)setenv("USER", username, 1); 62021528Sdavidn (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 62121528Sdavidn 6221590Srgrimes if (!quietlog) { 62394203Sru const char *cw; 62423985Sdavidn 62521528Sdavidn cw = login_getcapstr(lc, "welcome", NULL, NULL); 62689994Sdes if (cw != NULL && access(cw, F_OK) == 0) 62789994Sdes motd(cw); 62889994Sdes else 62989994Sdes motd(_PATH_MOTDFILE); 63023985Sdavidn 631146867Smaxim if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 && 632146867Smaxim login_getcapbool(lc, "nocheckmail", 0) == 0) { 633100825Sdwmalone char *cx; 634100825Sdwmalone 63586450Srwatson /* $MAIL may have been set by class. */ 636100825Sdwmalone cx = getenv("MAIL"); 637100825Sdwmalone if (cx == NULL) { 638100825Sdwmalone asprintf(&cx, "%s/%s", 63986450Srwatson _PATH_MAILDIR, pwd->pw_name); 64089994Sdes } 641100825Sdwmalone if (cx && stat(cx, &st) == 0 && st.st_size != 0) 64286450Srwatson (void)printf("You have %smail.\n", 64386450Srwatson (st.st_mtime > st.st_atime) ? "new " : ""); 64489994Sdes if (getenv("MAIL") == NULL) 645100825Sdwmalone free(cx); 64686450Srwatson } 6471590Srgrimes } 6481590Srgrimes 649146867Smaxim login_close(lc_user); 65021528Sdavidn login_close(lc); 6513205Spst 652264309Sjilles sa.sa_handler = SIG_DFL; 653264309Sjilles (void)sigaction(SIGALRM, &sa, NULL); 654264309Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 655264309Sjilles (void)sigaction(SIGINT, &sa, NULL); 656264309Sjilles (void)sigaction(SIGTERM, &sa, NULL); 657264309Sjilles (void)sigaction(SIGHUP, &sa, NULL); 658264309Sjilles sa.sa_handler = SIG_IGN; 659264309Sjilles (void)sigaction(SIGTSTP, &sa, NULL); 660264309Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 6611590Srgrimes 66223985Sdavidn /* 66323985Sdavidn * Login shells have a leading '-' in front of argv[0] 66423985Sdavidn */ 66589994Sdes p = strrchr(pwd->pw_shell, '/'); 66689994Sdes if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) { 66781555Smike syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 66881555Smike username); 66981555Smike errx(1, "shell exceeds maximum pathname size"); 67089994Sdes } else if (arg0 == NULL) { 67189994Sdes err(1, "asprintf()"); 67281555Smike } 67323985Sdavidn 67489994Sdes execlp(shell, arg0, (char *)0); 67521528Sdavidn err(1, "%s", shell); 67697376Sdes 67789994Sdes /* 67889994Sdes * That's it, folks! 67989994Sdes */ 6801590Srgrimes} 6811590Srgrimes 68241279Sjdp/* 68341279Sjdp * Attempt to authenticate the user using PAM. Returns 0 if the user is 68441279Sjdp * authenticated, or 1 if not authenticated. If some sort of PAM system 68541279Sjdp * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 68641279Sjdp * function returns -1. This can be used as an indication that we should 68741279Sjdp * fall back to a different authentication mechanism. 68841279Sjdp */ 68941279Sjdpstatic int 69089994Sdesauth_pam(void) 69141279Sjdp{ 69241279Sjdp const char *tmpl_user; 69341279Sjdp const void *item; 69441279Sjdp int rval; 69541279Sjdp 69689994Sdes pam_err = pam_authenticate(pamh, pam_silent); 69789994Sdes switch (pam_err) { 69841279Sjdp 69941279Sjdp case PAM_SUCCESS: 70041279Sjdp /* 70141279Sjdp * With PAM we support the concept of a "template" 70241279Sjdp * user. The user enters a login name which is 70341279Sjdp * authenticated by PAM, usually via a remote service 70441279Sjdp * such as RADIUS or TACACS+. If authentication 70541279Sjdp * succeeds, a different but related "template" name 70641279Sjdp * is used for setting the credentials, shell, and 70741279Sjdp * home directory. The name the user enters need only 70841279Sjdp * exist on the remote authentication server, but the 70941279Sjdp * template name must be present in the local password 71041279Sjdp * database. 71141279Sjdp * 71241279Sjdp * This is supported by two various mechanisms in the 71341279Sjdp * individual modules. However, from the application's 71441279Sjdp * point of view, the template user is always passed 71541279Sjdp * back as a changed value of the PAM_USER item. 71641279Sjdp */ 71789994Sdes pam_err = pam_get_item(pamh, PAM_USER, &item); 71889994Sdes if (pam_err == PAM_SUCCESS) { 71989994Sdes tmpl_user = (const char *)item; 72041279Sjdp if (strcmp(username, tmpl_user) != 0) 72141279Sjdp pwd = getpwnam(tmpl_user); 72289994Sdes } else { 72389994Sdes pam_syslog("pam_get_item(PAM_USER)"); 72489994Sdes } 72541279Sjdp rval = 0; 72641279Sjdp break; 72741279Sjdp 72841279Sjdp case PAM_AUTH_ERR: 72941279Sjdp case PAM_USER_UNKNOWN: 73041279Sjdp case PAM_MAXTRIES: 73141279Sjdp rval = 1; 73241279Sjdp break; 73341279Sjdp 73441279Sjdp default: 73589994Sdes pam_syslog("pam_authenticate()"); 73641279Sjdp rval = -1; 73741279Sjdp break; 73841279Sjdp } 73974874Smarkm 74074874Smarkm if (rval == 0) { 74189994Sdes pam_err = pam_acct_mgmt(pamh, pam_silent); 74289994Sdes switch (pam_err) { 74389994Sdes case PAM_SUCCESS: 74489994Sdes break; 74589994Sdes case PAM_NEW_AUTHTOK_REQD: 74689994Sdes pam_err = pam_chauthtok(pamh, 74789994Sdes pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK); 74889994Sdes if (pam_err != PAM_SUCCESS) { 74989994Sdes pam_syslog("pam_chauthtok()"); 75074874Smarkm rval = 1; 75174874Smarkm } 75289994Sdes break; 75389994Sdes default: 75489994Sdes pam_syslog("pam_acct_mgmt()"); 75574874Smarkm rval = 1; 75689994Sdes break; 75774874Smarkm } 75841279Sjdp } 75974874Smarkm 76074874Smarkm if (rval != 0) { 76189994Sdes pam_end(pamh, pam_err); 76274874Smarkm pamh = NULL; 76374874Smarkm } 76489994Sdes return (rval); 76541279Sjdp} 76672215Snectar 76789994Sdes/* 76889994Sdes * Export any environment variables PAM modules may have set 76989994Sdes */ 77089994Sdesstatic void 771201382Sedexport_pam_environment(void) 77272215Snectar{ 77389994Sdes char **pam_env; 77489994Sdes char **pp; 77572215Snectar 77689994Sdes pam_env = pam_getenvlist(pamh); 77789994Sdes if (pam_env != NULL) { 77889994Sdes for (pp = pam_env; *pp != NULL; pp++) { 779169177Sache (void)export(*pp); 780169177Sache free(*pp); 78189994Sdes } 78272215Snectar } 78372215Snectar} 78472215Snectar 78572215Snectar/* 78689994Sdes * Perform sanity checks on an environment variable: 78772215Snectar * - Make sure there is an '=' in the string. 78872215Snectar * - Make sure the string doesn't run on too long. 78972215Snectar * - Do not export certain variables. This list was taken from the 79072215Snectar * Solaris pam_putenv(3) man page. 79189994Sdes * Then export it. 79272215Snectar */ 79372215Snectarstatic int 79489994Sdesexport(const char *s) 79572215Snectar{ 79672215Snectar static const char *noexport[] = { 79772215Snectar "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 79872215Snectar "IFS", "PATH", NULL 79972215Snectar }; 800171195Sscf char *p; 80172215Snectar const char **pp; 80272215Snectar size_t n; 80372215Snectar 804171195Sscf if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL) 80589994Sdes return (0); 80672215Snectar if (strncmp(s, "LD_", 3) == 0) 80789994Sdes return (0); 80872215Snectar for (pp = noexport; *pp != NULL; pp++) { 80972215Snectar n = strlen(*pp); 81072215Snectar if (s[n] == '=' && strncmp(s, *pp, n) == 0) 81189994Sdes return (0); 81272215Snectar } 813171195Sscf *p = '\0'; 814171195Sscf (void)setenv(s, p + 1, 1); 815171195Sscf *p = '='; 81689994Sdes return (1); 81772215Snectar} 81841279Sjdp 81927605Scharnierstatic void 820201382Sedusage(void) 82127605Scharnier{ 82276791Sobrien 82327605Scharnier (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 82427605Scharnier exit(1); 82527605Scharnier} 8261590Srgrimes 82723985Sdavidn/* 82889994Sdes * Prompt user and read login name from stdin. 82974874Smarkm */ 83089994Sdesstatic char * 831201382Sedgetloginname(void) 8321590Srgrimes{ 83389994Sdes char *nbuf, *p; 8341590Srgrimes int ch; 8351590Srgrimes 83689994Sdes nbuf = malloc(MAXLOGNAME); 83789994Sdes if (nbuf == NULL) 83889994Sdes err(1, "malloc()"); 83989994Sdes do { 84081555Smike (void)printf("%s", prompt); 8411590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 8421590Srgrimes if (ch == EOF) { 8431590Srgrimes badlogin(username); 84489994Sdes bail(NO_SLEEP_EXIT, 0); 8451590Srgrimes } 84689994Sdes if (p < nbuf + MAXLOGNAME - 1) 8471590Srgrimes *p++ = ch; 8481590Srgrimes } 84989994Sdes } while (p == nbuf); 85097376Sdes 85189994Sdes *p = '\0'; 85289994Sdes if (nbuf[0] == '-') { 85389994Sdes pam_silent = 0; 85489994Sdes memmove(nbuf, nbuf + 1, strlen(nbuf)); 85589994Sdes } else { 85689994Sdes pam_silent = PAM_SILENT; 8571590Srgrimes } 85889994Sdes return nbuf; 8591590Srgrimes} 8601590Srgrimes 86189994Sdes/* 86289994Sdes * SIGINT handler for motd(). 86389994Sdes */ 86489994Sdesstatic volatile int motdinterrupt; 86589994Sdesstatic void 86689994Sdessigint(int signo __unused) 8671590Srgrimes{ 86821528Sdavidn motdinterrupt = 1; 86921528Sdavidn} 87021528Sdavidn 87189994Sdes/* 87289994Sdes * Display the contents of a file (such as /etc/motd). 87389994Sdes */ 87489994Sdesstatic int 87589994Sdesmotd(const char *motdfile) 87621528Sdavidn{ 877264309Sjilles struct sigaction newint, oldint; 87889994Sdes FILE *f; 87989994Sdes int ch; 8801590Srgrimes 88189994Sdes if ((f = fopen(motdfile, "r")) == NULL) 88289994Sdes return (-1); 88321528Sdavidn motdinterrupt = 0; 884264309Sjilles newint.sa_handler = sigint; 885264309Sjilles newint.sa_flags = 0; 886264309Sjilles sigfillset(&newint.sa_mask); 887264309Sjilles sigaction(SIGINT, &newint, &oldint); 88889994Sdes while ((ch = fgetc(f)) != EOF && !motdinterrupt) 88989994Sdes putchar(ch); 890264309Sjilles sigaction(SIGINT, &oldint, NULL); 89189994Sdes if (ch != EOF || ferror(f)) { 89289994Sdes fclose(f); 89389994Sdes return (-1); 89489994Sdes } 89589994Sdes fclose(f); 89689994Sdes return (0); 8971590Srgrimes} 8981590Srgrimes 89989994Sdes/* 90089994Sdes * SIGALRM handler, to enforce login prompt timeout. 90189994Sdes * 90289994Sdes * XXX This can potentially confuse the hell out of PAM. We should 90389994Sdes * XXX instead implement a conversation function that returns 90489994Sdes * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal 90589994Sdes * XXX handler just set a flag. 90689994Sdes */ 90789994Sdesstatic void 90889994Sdestimedout(int signo __unused) 9091590Srgrimes{ 91076788Sobrien 91142272Seivind longjmp(timeout_buf, signo); 9121590Srgrimes} 9131590Srgrimes 914105164Sphkstatic void 91589994Sdesbadlogin(char *name) 9161590Srgrimes{ 9171590Srgrimes 9181590Srgrimes if (failures == 0) 9191590Srgrimes return; 92089994Sdes if (hflag) { 9211590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 92289994Sdes failures, failures > 1 ? "S" : "", hostname); 9231590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9241590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 92589994Sdes failures, failures > 1 ? "S" : "", hostname, name); 9261590Srgrimes } else { 9271590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 9281590Srgrimes failures, failures > 1 ? "S" : "", tty); 9291590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9301590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 9311590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 9321590Srgrimes } 93342272Seivind failures = 0; 9341590Srgrimes} 9351590Srgrimes 93687173Smarkmconst char * 93789994Sdesstypeof(char *ttyid) 9381590Srgrimes{ 9391590Srgrimes struct ttyent *t; 94023985Sdavidn 94181555Smike if (ttyid != NULL && *ttyid != '\0') { 94281555Smike t = getttynam(ttyid); 94381555Smike if (t != NULL && t->ty_type != NULL) 94481555Smike return (t->ty_type); 94581555Smike } 94698960Sache return (NULL); 9471590Srgrimes} 9481590Srgrimes 949105164Sphkstatic void 95089994Sdesrefused(const char *msg, const char *rtype, int lout) 95123985Sdavidn{ 95223985Sdavidn 95323985Sdavidn if (msg != NULL) 95423985Sdavidn printf("%s.\n", msg); 95589994Sdes if (hflag) 95623985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 95789994Sdes pwd->pw_name, rtype, hostname, tty); 95823985Sdavidn else 95923985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 96076788Sobrien pwd->pw_name, rtype, tty); 96123985Sdavidn if (lout) 96289994Sdes bail(SLEEP_EXIT, 1); 96323985Sdavidn} 96423985Sdavidn 96589994Sdes/* 96689994Sdes * Log a PAM error 96789994Sdes */ 968105164Sphkstatic void 96989994Sdespam_syslog(const char *msg) 9701590Srgrimes{ 97189994Sdes syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); 97289994Sdes} 97323985Sdavidn 97489994Sdes/* 97589994Sdes * Shut down PAM 97689994Sdes */ 977105164Sphkstatic void 978201382Sedpam_cleanup(void) 97989994Sdes{ 98089994Sdes 98189994Sdes if (pamh != NULL) { 98289994Sdes if (pam_session_established) { 98389994Sdes pam_err = pam_close_session(pamh, 0); 98489994Sdes if (pam_err != PAM_SUCCESS) 98589994Sdes pam_syslog("pam_close_session()"); 98689994Sdes } 98789994Sdes pam_session_established = 0; 98889994Sdes if (pam_cred_established) { 98989994Sdes pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED); 99089994Sdes if (pam_err != PAM_SUCCESS) 99189994Sdes pam_syslog("pam_setcred()"); 99289994Sdes } 99389994Sdes pam_cred_established = 0; 99489994Sdes pam_end(pamh, pam_err); 99589994Sdes pamh = NULL; 99689994Sdes } 99789994Sdes} 99889994Sdes 999264309Sjillesstatic void 1000264309Sjillesbail_internal(int sec, int eval, int signo) 100189994Sdes{ 1002264309Sjilles struct sigaction sa; 100389994Sdes 100489994Sdes pam_cleanup(); 1005165152Scsjp#ifdef USE_BSM_AUDIT 1006157215Scognet if (pwd != NULL) 1007157215Scognet audit_logout(); 1008165152Scsjp#endif 100989994Sdes (void)sleep(sec); 1010264309Sjilles if (signo == 0) 1011264309Sjilles exit(eval); 1012264309Sjilles else { 1013264309Sjilles sa.sa_handler = SIG_DFL; 1014264309Sjilles sa.sa_flags = 0; 1015264309Sjilles (void)sigemptyset(&sa.sa_mask); 1016264309Sjilles (void)sigaction(signo, &sa, NULL); 1017264309Sjilles (void)sigaddset(&sa.sa_mask, signo); 1018264309Sjilles (void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); 1019264309Sjilles raise(signo); 1020264309Sjilles exit(128 + signo); 1021264309Sjilles } 10221590Srgrimes} 1023264309Sjilles 1024264309Sjilles/* 1025264309Sjilles * Exit, optionally after sleeping a few seconds 1026264309Sjilles */ 1027264309Sjillesstatic void 1028264309Sjillesbail(int sec, int eval) 1029264309Sjilles{ 1030264309Sjilles bail_internal(sec, eval, 0); 1031264309Sjilles} 1032264309Sjilles 1033264309Sjilles/* 1034264309Sjilles * Exit because of a signal. 1035264309Sjilles * This is not async-signal safe, so only call async-signal safe functions 1036264309Sjilles * while the signal is unmasked. 1037264309Sjilles */ 1038264309Sjillesstatic void 1039264309Sjillesbail_sig(int signo) 1040264309Sjilles{ 1041264309Sjilles bail_internal(NO_SLEEP_EXIT, 0, signo); 1042264309Sjilles} 1043