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: releng/11.0/usr.bin/login/login.c 287634 2015-09-10 22:25:40Z delphij $"); 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> 6641079Sjdp#include <login_cap.h> 671590Srgrimes#include <pwd.h> 681590Srgrimes#include <setjmp.h> 691590Srgrimes#include <signal.h> 701590Srgrimes#include <stdio.h> 711590Srgrimes#include <stdlib.h> 721590Srgrimes#include <string.h> 731590Srgrimes#include <syslog.h> 741590Srgrimes#include <ttyent.h> 751590Srgrimes#include <unistd.h> 761590Srgrimes 7741279Sjdp#include <security/pam_appl.h> 7891714Sdes#include <security/openpam.h> 793702Spst 8087173Smarkm#include "login.h" 811590Srgrimes#include "pathnames.h" 821590Srgrimes 8389994Sdesstatic int auth_pam(void); 8489994Sdesstatic void bail(int, int); 85261193Sjillesstatic void bail_internal(int, int, int); 8689994Sdesstatic int export(const char *); 8789994Sdesstatic void export_pam_environment(void); 8889994Sdesstatic int motd(const char *); 8989994Sdesstatic void badlogin(char *); 9089994Sdesstatic char *getloginname(void); 9189994Sdesstatic void pam_syslog(const char *); 9289994Sdesstatic void pam_cleanup(void); 9389994Sdesstatic void refused(const char *, const char *, int); 9489994Sdesstatic const char *stypeof(char *); 9589994Sdesstatic void sigint(int); 9689994Sdesstatic void timedout(int); 97261193Sjillesstatic void bail_sig(int); 9889994Sdesstatic void usage(void); 991590Srgrimes 10087173Smarkm#define TTYGRPNAME "tty" /* group to own ttys */ 10187173Smarkm#define DEFAULT_BACKOFF 3 10287173Smarkm#define DEFAULT_RETRIES 10 10376786Sobrien#define DEFAULT_PROMPT "login: " 10476786Sobrien#define DEFAULT_PASSWD_PROMPT "Password:" 10589994Sdes#define TERM_UNKNOWN "su" 10687173Smarkm#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 107258105Sed#define NO_SLEEP_EXIT 0 108258105Sed#define SLEEP_EXIT 5 1091590Srgrimes 1101590Srgrimes/* 1111590Srgrimes * This bounds the time given to login. Not a define so it can 1121590Srgrimes * be patched on machines where it's too small. 1131590Srgrimes */ 11489994Sdesstatic u_int timeout = 300; 1151590Srgrimes 11642272Seivind/* Buffer for signal handling of timeout */ 11789994Sdesstatic jmp_buf timeout_buf; 11842272Seivind 11989994Sdesstruct passwd *pwd; 12089994Sdesstatic int failures; 1211590Srgrimes 12289994Sdesstatic char *envinit[1]; /* empty environment list */ 12389994Sdes 12489994Sdes/* 12589994Sdes * Command line flags and arguments 12689994Sdes */ 12789994Sdesstatic int fflag; /* -f: do not perform authentication */ 12889994Sdesstatic int hflag; /* -h: login from remote host */ 12989994Sdesstatic char *hostname; /* hostname from command line */ 13089994Sdesstatic int pflag; /* -p: preserve environment */ 13189994Sdes 13289994Sdes/* 13389994Sdes * User name 13489994Sdes */ 13589994Sdesstatic char *username; /* user name */ 13689994Sdesstatic char *olduser; /* previous user name */ 13789994Sdes 13889994Sdes/* 13989994Sdes * Prompts 14089994Sdes */ 14189994Sdesstatic char default_prompt[] = DEFAULT_PROMPT; 14294203Srustatic const char *prompt; 14389994Sdesstatic char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT; 14494203Srustatic const char *passwd_prompt; 14589994Sdes 14689994Sdesstatic char *tty; 14789994Sdes 14889994Sdes/* 14989994Sdes * PAM data 15089994Sdes */ 15189994Sdesstatic pam_handle_t *pamh = NULL; 15291714Sdesstatic struct pam_conv pamc = { openpam_ttyconv, NULL }; 15389994Sdesstatic int pam_err; 15489994Sdesstatic int pam_silent = PAM_SILENT; 15589994Sdesstatic int pam_cred_established; 15689994Sdesstatic int pam_session_established; 15789994Sdes 1581590Srgrimesint 15989994Sdesmain(int argc, char *argv[]) 1601590Srgrimes{ 1611590Srgrimes struct group *gr; 1621590Srgrimes struct stat st; 16389994Sdes int retries, backoff; 16489994Sdes int ask, ch, cnt, quietlog, rootlogin, rval; 16535559Speter uid_t uid, euid; 16646007Sache gid_t egid; 16789994Sdes char *term; 16845431Sbrian char *p, *ttyn; 16942272Seivind char tname[sizeof(_PATH_TTY) + 10]; 17094203Sru char *arg0; 17198960Sache const char *tp; 17294203Sru const char *shell = NULL; 17321528Sdavidn login_cap_t *lc = NULL; 174146867Smaxim login_cap_t *lc_user = NULL; 17574874Smarkm pid_t pid; 176261193Sjilles sigset_t mask, omask; 177261193Sjilles struct sigaction sa; 178165152Scsjp#ifdef USE_BSM_AUDIT 179155312Swsalamon char auditsuccess = 1; 180165152Scsjp#endif 1811590Srgrimes 182261193Sjilles sa.sa_flags = SA_RESTART; 183261193Sjilles (void)sigfillset(&sa.sa_mask); 184261193Sjilles sa.sa_handler = SIG_IGN; 185261193Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 186261193Sjilles (void)sigaction(SIGINT, &sa, NULL); 187261193Sjilles (void)sigaction(SIGHUP, &sa, NULL); 18842272Seivind if (setjmp(timeout_buf)) { 18942272Seivind if (failures) 19089994Sdes badlogin(username); 19176788Sobrien (void)fprintf(stderr, "Login timed out after %d seconds\n", 19276788Sobrien timeout); 19389994Sdes bail(NO_SLEEP_EXIT, 0); 19442272Seivind } 195261193Sjilles sa.sa_handler = timedout; 196261193Sjilles (void)sigaction(SIGALRM, &sa, NULL); 1971590Srgrimes (void)alarm(timeout); 1981590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 1991590Srgrimes 200270111Sneel openlog("login", 0, LOG_AUTH); 2011590Srgrimes 2021590Srgrimes uid = getuid(); 20335557Speter euid = geteuid(); 20446007Sache egid = getegid(); 20589994Sdes 20624360Simp while ((ch = getopt(argc, argv, "fh:p")) != -1) 2071590Srgrimes switch (ch) { 2081590Srgrimes case 'f': 2091590Srgrimes fflag = 1; 2101590Srgrimes break; 2111590Srgrimes case 'h': 21289994Sdes if (uid != 0) 2131590Srgrimes errx(1, "-h option: %s", strerror(EPERM)); 21489994Sdes if (strlen(optarg) >= MAXHOSTNAMELEN) 21581555Smike errx(1, "-h option: %s: exceeds maximum " 21681555Smike "hostname size", optarg); 21789994Sdes hflag = 1; 2181590Srgrimes hostname = optarg; 2191590Srgrimes break; 2201590Srgrimes case 'p': 2211590Srgrimes pflag = 1; 2221590Srgrimes break; 2231590Srgrimes case '?': 2241590Srgrimes default: 22589994Sdes if (uid == 0) 2261590Srgrimes syslog(LOG_ERR, "invalid flag %c", ch); 22727605Scharnier usage(); 2281590Srgrimes } 2291590Srgrimes argc -= optind; 2301590Srgrimes argv += optind; 2311590Srgrimes 23289994Sdes if (argc > 0) { 23389994Sdes username = strdup(*argv); 23489994Sdes if (username == NULL) 23589994Sdes err(1, "strdup()"); 2361590Srgrimes ask = 0; 23789994Sdes } else { 2381590Srgrimes ask = 1; 23989994Sdes } 2401590Srgrimes 241107585Sdes setproctitle("-%s", getprogname()); 242107585Sdes 243214115Sed closefrom(3); 2441590Srgrimes 24589994Sdes /* 24689994Sdes * Get current TTY 24789994Sdes */ 2481590Srgrimes ttyn = ttyname(STDIN_FILENO); 2491590Srgrimes if (ttyn == NULL || *ttyn == '\0') { 2501590Srgrimes (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 2511590Srgrimes ttyn = tname; 2521590Srgrimes } 253190474Sed if (strncmp(ttyn, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) 254190474Sed tty = ttyn + sizeof _PATH_DEV - 1; 2551590Srgrimes else 2561590Srgrimes tty = ttyn; 2571590Srgrimes 25823985Sdavidn /* 25923985Sdavidn * Get "login-retries" & "login-backoff" from default class 26023985Sdavidn */ 26123985Sdavidn lc = login_getclass(NULL); 262114010Sdes prompt = login_getcapstr(lc, "login_prompt", 26389994Sdes default_prompt, default_prompt); 26476786Sobrien passwd_prompt = login_getcapstr(lc, "passwd_prompt", 26587173Smarkm default_passwd_prompt, default_passwd_prompt); 26689994Sdes retries = login_getcapnum(lc, "login-retries", 26789994Sdes DEFAULT_RETRIES, DEFAULT_RETRIES); 26889994Sdes backoff = login_getcapnum(lc, "login-backoff", 26989994Sdes DEFAULT_BACKOFF, DEFAULT_BACKOFF); 27023985Sdavidn login_close(lc); 27123985Sdavidn lc = NULL; 27221528Sdavidn 27389994Sdes /* 27489994Sdes * Try to authenticate the user until we succeed or time out. 27589994Sdes */ 2761590Srgrimes for (cnt = 0;; ask = 1) { 2771590Srgrimes if (ask) { 2781590Srgrimes fflag = 0; 27989994Sdes if (olduser != NULL) 28089994Sdes free(olduser); 28189994Sdes olduser = username; 28289994Sdes username = getloginname(); 2831590Srgrimes } 2841590Srgrimes rootlogin = 0; 28521528Sdavidn 2861590Srgrimes /* 2871590Srgrimes * Note if trying multiple user names; log failures for 2881590Srgrimes * previous user name, but don't bother logging one failure 2891590Srgrimes * for nonexistent name (mistyped username). 2901590Srgrimes */ 29189994Sdes if (failures && strcmp(olduser, username) != 0) { 2921590Srgrimes if (failures > (pwd ? 0 : 1)) 29389994Sdes badlogin(olduser); 2941590Srgrimes } 2951590Srgrimes 29623985Sdavidn /* 29789994Sdes * Load the PAM policy and set some variables 2981590Srgrimes */ 29989994Sdes pam_err = pam_start("login", username, &pamc, &pamh); 30089994Sdes if (pam_err != PAM_SUCCESS) { 30189994Sdes pam_syslog("pam_start()"); 302165152Scsjp#ifdef USE_BSM_AUDIT 303155312Swsalamon au_login_fail("PAM Error", 1); 304165152Scsjp#endif 30589994Sdes bail(NO_SLEEP_EXIT, 1); 3063205Spst } 30789994Sdes pam_err = pam_set_item(pamh, PAM_TTY, tty); 30889994Sdes if (pam_err != PAM_SUCCESS) { 30989994Sdes pam_syslog("pam_set_item(PAM_TTY)"); 310165152Scsjp#ifdef USE_BSM_AUDIT 311155312Swsalamon au_login_fail("PAM Error", 1); 312165152Scsjp#endif 31389994Sdes bail(NO_SLEEP_EXIT, 1); 31489994Sdes } 315110966Sdes pam_err = pam_set_item(pamh, PAM_RHOST, hostname); 31689994Sdes if (pam_err != PAM_SUCCESS) { 31789994Sdes pam_syslog("pam_set_item(PAM_RHOST)"); 318165152Scsjp#ifdef USE_BSM_AUDIT 319155312Swsalamon au_login_fail("PAM Error", 1); 320165152Scsjp#endif 32189994Sdes bail(NO_SLEEP_EXIT, 1); 32289994Sdes } 32397376Sdes 32489994Sdes pwd = getpwnam(username); 32541279Sjdp if (pwd != NULL && pwd->pw_uid == 0) 32641279Sjdp rootlogin = 1; 3271590Srgrimes 3281590Srgrimes /* 32989994Sdes * If the -f option was specified and the caller is 33089994Sdes * root or the caller isn't changing their uid, don't 33189994Sdes * authenticate. 3321590Srgrimes */ 33389994Sdes if (pwd != NULL && fflag && 33489994Sdes (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) { 33589994Sdes /* already authenticated */ 33689994Sdes rval = 0; 337165152Scsjp#ifdef USE_BSM_AUDIT 338155312Swsalamon auditsuccess = 0; /* opened a terminal window only */ 339165152Scsjp#endif 34089994Sdes } else { 34189994Sdes fflag = 0; 34289994Sdes (void)setpriority(PRIO_PROCESS, 0, -4); 34389994Sdes rval = auth_pam(); 34489994Sdes (void)setpriority(PRIO_PROCESS, 0, 0); 3451590Srgrimes } 3461590Srgrimes 34789994Sdes if (pwd && rval == 0) 34889994Sdes break; 34989994Sdes 35089994Sdes pam_cleanup(); 35197376Sdes 352155312Swsalamon /* 353155312Swsalamon * We are not exiting here, but this corresponds to a failed 354155312Swsalamon * login event, so set exitstatus to 1. 355155312Swsalamon */ 356165152Scsjp#ifdef USE_BSM_AUDIT 357155312Swsalamon au_login_fail("Login incorrect", 1); 358165152Scsjp#endif 359155312Swsalamon 3601590Srgrimes (void)printf("Login incorrect\n"); 3611590Srgrimes failures++; 36223985Sdavidn 363157215Scognet pwd = NULL; 364157215Scognet 36523985Sdavidn /* 36689994Sdes * Allow up to 'retry' (10) attempts, but start 36789994Sdes * backing off after 'backoff' (3) attempts. 36823985Sdavidn */ 36923985Sdavidn if (++cnt > backoff) { 37023985Sdavidn if (cnt >= retries) { 3711590Srgrimes badlogin(username); 37289994Sdes bail(SLEEP_EXIT, 1); 3731590Srgrimes } 37438374Sjkoshy sleep((u_int)((cnt - backoff) * 5)); 3751590Srgrimes } 3761590Srgrimes } 3771590Srgrimes 3781590Srgrimes /* committed to login -- turn off timeout */ 3791590Srgrimes (void)alarm((u_int)0); 3801590Srgrimes 381261193Sjilles (void)sigemptyset(&mask); 382261193Sjilles (void)sigaddset(&mask, SIGHUP); 383261193Sjilles (void)sigaddset(&mask, SIGTERM); 384261193Sjilles (void)sigprocmask(SIG_BLOCK, &mask, &omask); 385261193Sjilles sa.sa_handler = bail_sig; 386261193Sjilles (void)sigaction(SIGHUP, &sa, NULL); 387261193Sjilles (void)sigaction(SIGTERM, &sa, NULL); 388261193Sjilles 3891590Srgrimes endpwent(); 3901590Srgrimes 391165152Scsjp#ifdef USE_BSM_AUDIT 392155312Swsalamon /* Audit successful login. */ 393155312Swsalamon if (auditsuccess) 394155312Swsalamon au_login_success(); 395165152Scsjp#endif 396155312Swsalamon 397258105Sed /* 398258105Sed * This needs to happen before login_getpwclass to support 399258105Sed * home directories on GSS-API authenticated NFS where the 400258105Sed * kerberos credentials need to be saved so that the kernel 401258105Sed * can authenticate to the NFS server. 402258105Sed */ 403221374Sdfr pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED); 404221374Sdfr if (pam_err != PAM_SUCCESS) { 405221374Sdfr pam_syslog("pam_setcred()"); 406221374Sdfr bail(NO_SLEEP_EXIT, 1); 407221374Sdfr } 408221374Sdfr pam_cred_established = 1; 409221374Sdfr 41041279Sjdp /* 41141279Sjdp * Establish the login class. 41241279Sjdp */ 41341279Sjdp lc = login_getpwclass(pwd); 414146867Smaxim lc_user = login_getuserclass(pwd); 41541279Sjdp 416146867Smaxim if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0))) 417146867Smaxim quietlog = login_getcapbool(lc, "hushlogin", 0); 41897376Sdes 41983519Srwatson /* 42083519Srwatson * Switching needed for NFS with root access disabled. 42183519Srwatson * 42283519Srwatson * XXX: This change fails to modify the additional groups for the 42383519Srwatson * process, and as such, may restrict rights normally granted 42483519Srwatson * through those groups. 42583519Srwatson */ 42646007Sache (void)setegid(pwd->pw_gid); 42735557Speter (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 42821528Sdavidn if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 42926021Spst if (login_getcapbool(lc, "requirehome", 0)) 43023985Sdavidn refused("Home directory not available", "HOMEDIR", 1); 43197376Sdes if (chdir("/") < 0) 43223985Sdavidn refused("Cannot find root directory", "ROOTDIR", 1); 43323985Sdavidn if (!quietlog || *pwd->pw_dir) 43423985Sdavidn printf("No home directory.\nLogging in with home = \"/\".\n"); 43587173Smarkm pwd->pw_dir = strdup("/"); 43687173Smarkm if (pwd->pw_dir == NULL) { 43787173Smarkm syslog(LOG_NOTICE, "strdup(): %m"); 43889994Sdes bail(SLEEP_EXIT, 1); 43987173Smarkm } 4401590Srgrimes } 44135557Speter (void)seteuid(euid); 44246007Sache (void)setegid(egid); 443125055Sfjoe if (!quietlog) { 44421528Sdavidn quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 445125055Sfjoe if (!quietlog) 446125055Sfjoe pam_silent = 0; 447125055Sfjoe } 44897376Sdes 44997376Sdes shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 45023985Sdavidn if (*pwd->pw_shell == '\0') 45187173Smarkm pwd->pw_shell = strdup(_PATH_BSHELL); 45287173Smarkm if (pwd->pw_shell == NULL) { 45387173Smarkm syslog(LOG_NOTICE, "strdup(): %m"); 45489994Sdes bail(SLEEP_EXIT, 1); 45587173Smarkm } 45623985Sdavidn if (*shell == '\0') /* Not overridden */ 45723985Sdavidn shell = pwd->pw_shell; 45823985Sdavidn if ((shell = strdup(shell)) == NULL) { 45981555Smike syslog(LOG_NOTICE, "strdup(): %m"); 46089994Sdes bail(SLEEP_EXIT, 1); 46123985Sdavidn } 46221528Sdavidn 4632224Sguido /* 4642224Sguido * Set device protections, depending on what terminal the 4652224Sguido * user is logged in. This feature is used on Suns to give 4662224Sguido * console users better privacy. 4672224Sguido */ 4682224Sguido login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 4692224Sguido 47050124Simp /* 47150124Simp * Clear flags of the tty. None should be set, and when the 47250124Simp * user sets them otherwise, this can cause the chown to fail. 47350124Simp * Since it isn't clear that flags are useful on character 47450124Simp * devices, we just clear them. 475102141Simp * 476102141Simp * We don't log in the case of EOPNOTSUPP because dev might be 477102141Simp * on NFS, which doesn't support chflags. 478102141Simp * 479102141Simp * We don't log in the EROFS because that means that /dev is on 480102141Simp * a read only file system and we assume that the permissions there 481102141Simp * are sane. 48250124Simp */ 483102141Simp if (ttyn != tname && chflags(ttyn, 0)) 484102141Simp if (errno != EOPNOTSUPP && errno != EROFS) 485102141Simp syslog(LOG_ERR, "chflags(%s): %m", ttyn); 48689994Sdes if (ttyn != tname && chown(ttyn, pwd->pw_uid, 48750124Simp (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 488102141Simp if (errno != EROFS) 489114048Srwatson syslog(LOG_ERR, "chown(%s): %m", ttyn); 4901590Srgrimes 4913205Spst#ifdef LOGALL 4923205Spst /* 49389994Sdes * Syslog each successful login, so we don't have to watch 49489994Sdes * hundreds of wtmp or lastlogin files. 4953205Spst */ 49689994Sdes if (hflag) 49723985Sdavidn syslog(LOG_INFO, "login from %s on %s as %s", 49889994Sdes hostname, tty, pwd->pw_name); 49923985Sdavidn else 50023985Sdavidn syslog(LOG_INFO, "login on %s as %s", 50123985Sdavidn tty, pwd->pw_name); 50221528Sdavidn#endif 50321528Sdavidn 50423985Sdavidn /* 50589994Sdes * If fflag is on, assume caller/authenticator has logged root 50689994Sdes * login. 50723985Sdavidn */ 50889994Sdes if (rootlogin && fflag == 0) { 50989994Sdes if (hflag) 51023985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 51189994Sdes username, tty, hostname); 51223985Sdavidn else 51323985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 51476788Sobrien username, tty); 51523985Sdavidn } 51623985Sdavidn 51723985Sdavidn /* 51889994Sdes * Destroy environment unless user has requested its 51989994Sdes * preservation - but preserve TERM in all cases 52023985Sdavidn */ 52189994Sdes term = getenv("TERM"); 52221528Sdavidn if (!pflag) 52321528Sdavidn environ = envinit; 52489994Sdes if (term != NULL) 52589994Sdes setenv("TERM", term, 0); 52621528Sdavidn 52723985Sdavidn /* 52874874Smarkm * PAM modules might add supplementary groups during pam_setcred(). 52974874Smarkm */ 53074874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 53197376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 53289994Sdes bail(NO_SLEEP_EXIT, 1); 53374874Smarkm } 53474874Smarkm 535221374Sdfr pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED); 53689994Sdes if (pam_err != PAM_SUCCESS) { 53789994Sdes pam_syslog("pam_setcred()"); 53889994Sdes bail(NO_SLEEP_EXIT, 1); 53989994Sdes } 54097376Sdes 54189994Sdes pam_err = pam_open_session(pamh, pam_silent); 54289994Sdes if (pam_err != PAM_SUCCESS) { 54389994Sdes pam_syslog("pam_open_session()"); 54489994Sdes bail(NO_SLEEP_EXIT, 1); 54589994Sdes } 54689994Sdes pam_session_established = 1; 54774874Smarkm 54889994Sdes /* 54989994Sdes * We must fork() before setuid() because we need to call 55089994Sdes * pam_close_session() as root. 55189994Sdes */ 55289994Sdes pid = fork(); 55389994Sdes if (pid < 0) { 55489994Sdes err(1, "fork"); 55589994Sdes } else if (pid != 0) { 55674874Smarkm /* 55789994Sdes * Parent: wait for child to finish, then clean up 55889994Sdes * session. 559261193Sjilles * 560261193Sjilles * If we get SIGHUP or SIGTERM, clean up the session 561261193Sjilles * and exit right away. This will make the terminal 562261193Sjilles * inaccessible and send SIGHUP to the foreground 563261193Sjilles * process group. 56474874Smarkm */ 565110549Sdes int status; 566107585Sdes setproctitle("-%s [pam]", getprogname()); 567261193Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 568110549Sdes waitpid(pid, &status, 0); 569261193Sjilles (void)sigprocmask(SIG_BLOCK, &mask, NULL); 57089994Sdes bail(NO_SLEEP_EXIT, 0); 57174874Smarkm } 57274874Smarkm 57374874Smarkm /* 57489994Sdes * NOTICE: We are now in the child process! 57521528Sdavidn */ 57697376Sdes 57789994Sdes /* 57889994Sdes * Add any environment variables the PAM modules may have set. 57989994Sdes */ 58089994Sdes export_pam_environment(); 58189994Sdes 58289994Sdes /* 58389994Sdes * We're done with PAM now; our parent will deal with the rest. 58489994Sdes */ 58591714Sdes pam_end(pamh, 0); 58689994Sdes pamh = NULL; 58789994Sdes 58889994Sdes /* 58989994Sdes * We don't need to be root anymore, so set the login name and 59089994Sdes * the UID. 59189994Sdes */ 59241279Sjdp if (setlogin(username) != 0) { 59397376Sdes syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 59489994Sdes bail(NO_SLEEP_EXIT, 1); 59541279Sjdp } 59641279Sjdp if (setusercontext(lc, pwd, pwd->pw_uid, 59774874Smarkm LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 59897376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 59921528Sdavidn exit(1); 6003205Spst } 60121528Sdavidn 60223148Sache (void)setenv("SHELL", pwd->pw_shell, 1); 60321528Sdavidn (void)setenv("HOME", pwd->pw_dir, 1); 60498960Sache /* Overwrite "term" from login.conf(5) for any known TERM */ 60598990Sache if (term == NULL && (tp = stypeof(tty)) != NULL) 60698960Sache (void)setenv("TERM", tp, 1); 60798960Sache else 60898960Sache (void)setenv("TERM", TERM_UNKNOWN, 0); 60941279Sjdp (void)setenv("LOGNAME", username, 1); 61041279Sjdp (void)setenv("USER", username, 1); 61121528Sdavidn (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 61221528Sdavidn 6131590Srgrimes if (!quietlog) { 61494203Sru const char *cw; 61523985Sdavidn 61621528Sdavidn cw = login_getcapstr(lc, "welcome", NULL, NULL); 61789994Sdes if (cw != NULL && access(cw, F_OK) == 0) 61889994Sdes motd(cw); 61989994Sdes else 62089994Sdes motd(_PATH_MOTDFILE); 62123985Sdavidn 622146867Smaxim if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 && 623146867Smaxim login_getcapbool(lc, "nocheckmail", 0) == 0) { 624100825Sdwmalone char *cx; 625100825Sdwmalone 62686450Srwatson /* $MAIL may have been set by class. */ 627100825Sdwmalone cx = getenv("MAIL"); 628100825Sdwmalone if (cx == NULL) { 629100825Sdwmalone asprintf(&cx, "%s/%s", 63086450Srwatson _PATH_MAILDIR, pwd->pw_name); 63189994Sdes } 632100825Sdwmalone if (cx && stat(cx, &st) == 0 && st.st_size != 0) 63386450Srwatson (void)printf("You have %smail.\n", 63486450Srwatson (st.st_mtime > st.st_atime) ? "new " : ""); 63589994Sdes if (getenv("MAIL") == NULL) 636100825Sdwmalone free(cx); 63786450Srwatson } 6381590Srgrimes } 6391590Srgrimes 640146867Smaxim login_close(lc_user); 64121528Sdavidn login_close(lc); 6423205Spst 643261193Sjilles sa.sa_handler = SIG_DFL; 644261193Sjilles (void)sigaction(SIGALRM, &sa, NULL); 645261193Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 646261193Sjilles (void)sigaction(SIGINT, &sa, NULL); 647261193Sjilles (void)sigaction(SIGTERM, &sa, NULL); 648261193Sjilles (void)sigaction(SIGHUP, &sa, NULL); 649261193Sjilles sa.sa_handler = SIG_IGN; 650261193Sjilles (void)sigaction(SIGTSTP, &sa, NULL); 651261193Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 6521590Srgrimes 65323985Sdavidn /* 65423985Sdavidn * Login shells have a leading '-' in front of argv[0] 65523985Sdavidn */ 65689994Sdes p = strrchr(pwd->pw_shell, '/'); 65789994Sdes if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) { 65881555Smike syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 65981555Smike username); 66081555Smike errx(1, "shell exceeds maximum pathname size"); 66189994Sdes } else if (arg0 == NULL) { 66289994Sdes err(1, "asprintf()"); 66381555Smike } 66423985Sdavidn 66589994Sdes execlp(shell, arg0, (char *)0); 66621528Sdavidn err(1, "%s", shell); 66797376Sdes 66889994Sdes /* 66989994Sdes * That's it, folks! 67089994Sdes */ 6711590Srgrimes} 6721590Srgrimes 67341279Sjdp/* 67441279Sjdp * Attempt to authenticate the user using PAM. Returns 0 if the user is 67541279Sjdp * authenticated, or 1 if not authenticated. If some sort of PAM system 67641279Sjdp * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 67741279Sjdp * function returns -1. This can be used as an indication that we should 67841279Sjdp * fall back to a different authentication mechanism. 67941279Sjdp */ 68041279Sjdpstatic int 68189994Sdesauth_pam(void) 68241279Sjdp{ 68341279Sjdp const char *tmpl_user; 68441279Sjdp const void *item; 68541279Sjdp int rval; 68641279Sjdp 68789994Sdes pam_err = pam_authenticate(pamh, pam_silent); 68889994Sdes switch (pam_err) { 68941279Sjdp 69041279Sjdp case PAM_SUCCESS: 69141279Sjdp /* 69241279Sjdp * With PAM we support the concept of a "template" 69341279Sjdp * user. The user enters a login name which is 69441279Sjdp * authenticated by PAM, usually via a remote service 69541279Sjdp * such as RADIUS or TACACS+. If authentication 69641279Sjdp * succeeds, a different but related "template" name 69741279Sjdp * is used for setting the credentials, shell, and 69841279Sjdp * home directory. The name the user enters need only 69941279Sjdp * exist on the remote authentication server, but the 70041279Sjdp * template name must be present in the local password 70141279Sjdp * database. 70241279Sjdp * 70341279Sjdp * This is supported by two various mechanisms in the 70441279Sjdp * individual modules. However, from the application's 70541279Sjdp * point of view, the template user is always passed 70641279Sjdp * back as a changed value of the PAM_USER item. 70741279Sjdp */ 70889994Sdes pam_err = pam_get_item(pamh, PAM_USER, &item); 70989994Sdes if (pam_err == PAM_SUCCESS) { 71089994Sdes tmpl_user = (const char *)item; 71141279Sjdp if (strcmp(username, tmpl_user) != 0) 71241279Sjdp pwd = getpwnam(tmpl_user); 71389994Sdes } else { 71489994Sdes pam_syslog("pam_get_item(PAM_USER)"); 71589994Sdes } 71641279Sjdp rval = 0; 71741279Sjdp break; 71841279Sjdp 71941279Sjdp case PAM_AUTH_ERR: 72041279Sjdp case PAM_USER_UNKNOWN: 72141279Sjdp case PAM_MAXTRIES: 72241279Sjdp rval = 1; 72341279Sjdp break; 72441279Sjdp 72541279Sjdp default: 72689994Sdes pam_syslog("pam_authenticate()"); 72741279Sjdp rval = -1; 72841279Sjdp break; 72941279Sjdp } 73074874Smarkm 73174874Smarkm if (rval == 0) { 73289994Sdes pam_err = pam_acct_mgmt(pamh, pam_silent); 73389994Sdes switch (pam_err) { 73489994Sdes case PAM_SUCCESS: 73589994Sdes break; 73689994Sdes case PAM_NEW_AUTHTOK_REQD: 73789994Sdes pam_err = pam_chauthtok(pamh, 73889994Sdes pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK); 73989994Sdes if (pam_err != PAM_SUCCESS) { 74089994Sdes pam_syslog("pam_chauthtok()"); 74174874Smarkm rval = 1; 74274874Smarkm } 74389994Sdes break; 74489994Sdes default: 74589994Sdes pam_syslog("pam_acct_mgmt()"); 74674874Smarkm rval = 1; 74789994Sdes break; 74874874Smarkm } 74941279Sjdp } 75074874Smarkm 75174874Smarkm if (rval != 0) { 75289994Sdes pam_end(pamh, pam_err); 75374874Smarkm pamh = NULL; 75474874Smarkm } 75589994Sdes return (rval); 75641279Sjdp} 75772215Snectar 75889994Sdes/* 75989994Sdes * Export any environment variables PAM modules may have set 76089994Sdes */ 76189994Sdesstatic void 762201382Sedexport_pam_environment(void) 76372215Snectar{ 76489994Sdes char **pam_env; 76589994Sdes char **pp; 76672215Snectar 76789994Sdes pam_env = pam_getenvlist(pamh); 76889994Sdes if (pam_env != NULL) { 76989994Sdes for (pp = pam_env; *pp != NULL; pp++) { 770169177Sache (void)export(*pp); 771169177Sache free(*pp); 77289994Sdes } 77372215Snectar } 77472215Snectar} 77572215Snectar 77672215Snectar/* 77789994Sdes * Perform sanity checks on an environment variable: 77872215Snectar * - Make sure there is an '=' in the string. 77972215Snectar * - Make sure the string doesn't run on too long. 78072215Snectar * - Do not export certain variables. This list was taken from the 78172215Snectar * Solaris pam_putenv(3) man page. 78289994Sdes * Then export it. 78372215Snectar */ 78472215Snectarstatic int 78589994Sdesexport(const char *s) 78672215Snectar{ 78772215Snectar static const char *noexport[] = { 78872215Snectar "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 78972215Snectar "IFS", "PATH", NULL 79072215Snectar }; 791171195Sscf char *p; 79272215Snectar const char **pp; 79372215Snectar size_t n; 79472215Snectar 795171195Sscf if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL) 79689994Sdes return (0); 79772215Snectar if (strncmp(s, "LD_", 3) == 0) 79889994Sdes return (0); 79972215Snectar for (pp = noexport; *pp != NULL; pp++) { 80072215Snectar n = strlen(*pp); 80172215Snectar if (s[n] == '=' && strncmp(s, *pp, n) == 0) 80289994Sdes return (0); 80372215Snectar } 804171195Sscf *p = '\0'; 805171195Sscf (void)setenv(s, p + 1, 1); 806171195Sscf *p = '='; 80789994Sdes return (1); 80872215Snectar} 80941279Sjdp 81027605Scharnierstatic void 811201382Sedusage(void) 81227605Scharnier{ 81376791Sobrien 81427605Scharnier (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 81527605Scharnier exit(1); 81627605Scharnier} 8171590Srgrimes 81823985Sdavidn/* 81989994Sdes * Prompt user and read login name from stdin. 82074874Smarkm */ 82189994Sdesstatic char * 822201382Sedgetloginname(void) 8231590Srgrimes{ 82489994Sdes char *nbuf, *p; 8251590Srgrimes int ch; 8261590Srgrimes 82789994Sdes nbuf = malloc(MAXLOGNAME); 82889994Sdes if (nbuf == NULL) 82989994Sdes err(1, "malloc()"); 83089994Sdes do { 83181555Smike (void)printf("%s", prompt); 8321590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 8331590Srgrimes if (ch == EOF) { 8341590Srgrimes badlogin(username); 83589994Sdes bail(NO_SLEEP_EXIT, 0); 8361590Srgrimes } 83789994Sdes if (p < nbuf + MAXLOGNAME - 1) 8381590Srgrimes *p++ = ch; 8391590Srgrimes } 84089994Sdes } while (p == nbuf); 84197376Sdes 84289994Sdes *p = '\0'; 84389994Sdes if (nbuf[0] == '-') { 84489994Sdes pam_silent = 0; 84589994Sdes memmove(nbuf, nbuf + 1, strlen(nbuf)); 84689994Sdes } else { 84789994Sdes pam_silent = PAM_SILENT; 8481590Srgrimes } 84989994Sdes return nbuf; 8501590Srgrimes} 8511590Srgrimes 85289994Sdes/* 85389994Sdes * SIGINT handler for motd(). 85489994Sdes */ 85589994Sdesstatic volatile int motdinterrupt; 85689994Sdesstatic void 85789994Sdessigint(int signo __unused) 8581590Srgrimes{ 85921528Sdavidn motdinterrupt = 1; 86021528Sdavidn} 86121528Sdavidn 86289994Sdes/* 86389994Sdes * Display the contents of a file (such as /etc/motd). 86489994Sdes */ 86589994Sdesstatic int 86689994Sdesmotd(const char *motdfile) 86721528Sdavidn{ 868261193Sjilles struct sigaction newint, oldint; 86989994Sdes FILE *f; 87089994Sdes int ch; 8711590Srgrimes 87289994Sdes if ((f = fopen(motdfile, "r")) == NULL) 87389994Sdes return (-1); 87421528Sdavidn motdinterrupt = 0; 875261193Sjilles newint.sa_handler = sigint; 876261193Sjilles newint.sa_flags = 0; 877261193Sjilles sigfillset(&newint.sa_mask); 878261193Sjilles sigaction(SIGINT, &newint, &oldint); 87989994Sdes while ((ch = fgetc(f)) != EOF && !motdinterrupt) 88089994Sdes putchar(ch); 881261193Sjilles sigaction(SIGINT, &oldint, NULL); 88289994Sdes if (ch != EOF || ferror(f)) { 88389994Sdes fclose(f); 88489994Sdes return (-1); 88589994Sdes } 88689994Sdes fclose(f); 88789994Sdes return (0); 8881590Srgrimes} 8891590Srgrimes 89089994Sdes/* 89189994Sdes * SIGALRM handler, to enforce login prompt timeout. 89289994Sdes * 89389994Sdes * XXX This can potentially confuse the hell out of PAM. We should 89489994Sdes * XXX instead implement a conversation function that returns 89589994Sdes * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal 89689994Sdes * XXX handler just set a flag. 89789994Sdes */ 89889994Sdesstatic void 89989994Sdestimedout(int signo __unused) 9001590Srgrimes{ 90176788Sobrien 90242272Seivind longjmp(timeout_buf, signo); 9031590Srgrimes} 9041590Srgrimes 905105164Sphkstatic void 90689994Sdesbadlogin(char *name) 9071590Srgrimes{ 9081590Srgrimes 9091590Srgrimes if (failures == 0) 9101590Srgrimes return; 91189994Sdes if (hflag) { 9121590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 91389994Sdes failures, failures > 1 ? "S" : "", hostname); 9141590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9151590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 91689994Sdes failures, failures > 1 ? "S" : "", hostname, name); 9171590Srgrimes } else { 9181590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 9191590Srgrimes failures, failures > 1 ? "S" : "", tty); 9201590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9211590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 9221590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 9231590Srgrimes } 92442272Seivind failures = 0; 9251590Srgrimes} 9261590Srgrimes 92787173Smarkmconst char * 92889994Sdesstypeof(char *ttyid) 9291590Srgrimes{ 9301590Srgrimes struct ttyent *t; 93123985Sdavidn 93281555Smike if (ttyid != NULL && *ttyid != '\0') { 93381555Smike t = getttynam(ttyid); 93481555Smike if (t != NULL && t->ty_type != NULL) 93581555Smike return (t->ty_type); 93681555Smike } 93798960Sache return (NULL); 9381590Srgrimes} 9391590Srgrimes 940105164Sphkstatic void 94189994Sdesrefused(const char *msg, const char *rtype, int lout) 94223985Sdavidn{ 94323985Sdavidn 94423985Sdavidn if (msg != NULL) 94523985Sdavidn printf("%s.\n", msg); 94689994Sdes if (hflag) 94723985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 94889994Sdes pwd->pw_name, rtype, hostname, tty); 94923985Sdavidn else 95023985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 95176788Sobrien pwd->pw_name, rtype, tty); 95223985Sdavidn if (lout) 95389994Sdes bail(SLEEP_EXIT, 1); 95423985Sdavidn} 95523985Sdavidn 95689994Sdes/* 95789994Sdes * Log a PAM error 95889994Sdes */ 959105164Sphkstatic void 96089994Sdespam_syslog(const char *msg) 9611590Srgrimes{ 96289994Sdes syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); 96389994Sdes} 96423985Sdavidn 96589994Sdes/* 96689994Sdes * Shut down PAM 96789994Sdes */ 968105164Sphkstatic void 969201382Sedpam_cleanup(void) 97089994Sdes{ 97189994Sdes 97289994Sdes if (pamh != NULL) { 97389994Sdes if (pam_session_established) { 97489994Sdes pam_err = pam_close_session(pamh, 0); 97589994Sdes if (pam_err != PAM_SUCCESS) 97689994Sdes pam_syslog("pam_close_session()"); 97789994Sdes } 97889994Sdes pam_session_established = 0; 97989994Sdes if (pam_cred_established) { 98089994Sdes pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED); 98189994Sdes if (pam_err != PAM_SUCCESS) 98289994Sdes pam_syslog("pam_setcred()"); 98389994Sdes } 98489994Sdes pam_cred_established = 0; 98589994Sdes pam_end(pamh, pam_err); 98689994Sdes pamh = NULL; 98789994Sdes } 98889994Sdes} 98989994Sdes 990261193Sjillesstatic void 991261193Sjillesbail_internal(int sec, int eval, int signo) 99289994Sdes{ 993261193Sjilles struct sigaction sa; 99489994Sdes 99589994Sdes pam_cleanup(); 996165152Scsjp#ifdef USE_BSM_AUDIT 997157215Scognet if (pwd != NULL) 998157215Scognet audit_logout(); 999165152Scsjp#endif 100089994Sdes (void)sleep(sec); 1001261193Sjilles if (signo == 0) 1002261193Sjilles exit(eval); 1003261193Sjilles else { 1004261193Sjilles sa.sa_handler = SIG_DFL; 1005261193Sjilles sa.sa_flags = 0; 1006261193Sjilles (void)sigemptyset(&sa.sa_mask); 1007261193Sjilles (void)sigaction(signo, &sa, NULL); 1008261193Sjilles (void)sigaddset(&sa.sa_mask, signo); 1009261193Sjilles (void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); 1010261193Sjilles raise(signo); 1011261193Sjilles exit(128 + signo); 1012261193Sjilles } 10131590Srgrimes} 1014261193Sjilles 1015261193Sjilles/* 1016261193Sjilles * Exit, optionally after sleeping a few seconds 1017261193Sjilles */ 1018261193Sjillesstatic void 1019261193Sjillesbail(int sec, int eval) 1020261193Sjilles{ 1021261193Sjilles bail_internal(sec, eval, 0); 1022261193Sjilles} 1023261193Sjilles 1024261193Sjilles/* 1025261193Sjilles * Exit because of a signal. 1026261193Sjilles * This is not async-signal safe, so only call async-signal safe functions 1027261193Sjilles * while the signal is unmasked. 1028261193Sjilles */ 1029261193Sjillesstatic void 1030261193Sjillesbail_sig(int signo) 1031261193Sjilles{ 1032261193Sjilles bail_internal(NO_SLEEP_EXIT, 0, signo); 1033261193Sjilles} 1034