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> 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); 85264192Sjillesstatic 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); 97264192Sjillesstatic 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 */ 10789994Sdes#define NO_SLEEP_EXIT 0 10889994Sdes#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; 176264192Sjilles sigset_t mask, omask; 177264192Sjilles struct sigaction sa; 178165152Scsjp#ifdef USE_BSM_AUDIT 179155312Swsalamon char auditsuccess = 1; 180165152Scsjp#endif 1811590Srgrimes 182264192Sjilles sa.sa_flags = SA_RESTART; 183264192Sjilles (void)sigfillset(&sa.sa_mask); 184264192Sjilles sa.sa_handler = SIG_IGN; 185264192Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 186264192Sjilles (void)sigaction(SIGINT, &sa, NULL); 187264192Sjilles (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 } 195264192Sjilles sa.sa_handler = timedout; 196264192Sjilles (void)sigaction(SIGALRM, &sa, NULL); 1971590Srgrimes (void)alarm(timeout); 1981590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 1991590Srgrimes 2001590Srgrimes openlog("login", LOG_ODELAY, 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 381264192Sjilles (void)sigemptyset(&mask); 382264192Sjilles (void)sigaddset(&mask, SIGHUP); 383264192Sjilles (void)sigaddset(&mask, SIGTERM); 384264192Sjilles (void)sigprocmask(SIG_BLOCK, &mask, &omask); 385264192Sjilles sa.sa_handler = bail_sig; 386264192Sjilles (void)sigaction(SIGHUP, &sa, NULL); 387264192Sjilles (void)sigaction(SIGTERM, &sa, NULL); 388264192Sjilles 3891590Srgrimes endpwent(); 3901590Srgrimes 391165152Scsjp#ifdef USE_BSM_AUDIT 392155312Swsalamon /* Audit successful login. */ 393155312Swsalamon if (auditsuccess) 394155312Swsalamon au_login_success(); 395165152Scsjp#endif 396155312Swsalamon 397221374Sdfr /* 398221374Sdfr * This needs to happen before login_getpwclass to support 399221374Sdfr * home directories on GSS-API authenticated NFS where the 400221374Sdfr * kerberos credentials need to be saved so that the kernel 401221374Sdfr * can authenticate to the NFS server. 402221374Sdfr */ 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 49123985Sdavidn /* 49223985Sdavidn * Exclude cons/vt/ptys only, assume dialup otherwise 49323985Sdavidn * TODO: Make dialup tty determination a library call 49423985Sdavidn * for consistency (finger etc.) 49523985Sdavidn */ 49689994Sdes if (hflag && isdialuptty(tty)) 4971590Srgrimes syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 4981590Srgrimes 4993205Spst#ifdef LOGALL 5003205Spst /* 50189994Sdes * Syslog each successful login, so we don't have to watch 50289994Sdes * hundreds of wtmp or lastlogin files. 5033205Spst */ 50489994Sdes if (hflag) 50523985Sdavidn syslog(LOG_INFO, "login from %s on %s as %s", 50689994Sdes hostname, tty, pwd->pw_name); 50723985Sdavidn else 50823985Sdavidn syslog(LOG_INFO, "login on %s as %s", 50923985Sdavidn tty, pwd->pw_name); 51021528Sdavidn#endif 51121528Sdavidn 51223985Sdavidn /* 51389994Sdes * If fflag is on, assume caller/authenticator has logged root 51489994Sdes * login. 51523985Sdavidn */ 51689994Sdes if (rootlogin && fflag == 0) { 51789994Sdes if (hflag) 51823985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 51989994Sdes username, tty, hostname); 52023985Sdavidn else 52123985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 52276788Sobrien username, tty); 52323985Sdavidn } 52423985Sdavidn 52523985Sdavidn /* 52689994Sdes * Destroy environment unless user has requested its 52789994Sdes * preservation - but preserve TERM in all cases 52823985Sdavidn */ 52989994Sdes term = getenv("TERM"); 53021528Sdavidn if (!pflag) 53121528Sdavidn environ = envinit; 53289994Sdes if (term != NULL) 53389994Sdes setenv("TERM", term, 0); 53421528Sdavidn 53523985Sdavidn /* 53674874Smarkm * PAM modules might add supplementary groups during pam_setcred(). 53774874Smarkm */ 53874874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 53997376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 54089994Sdes bail(NO_SLEEP_EXIT, 1); 54174874Smarkm } 54274874Smarkm 543221374Sdfr pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED); 54489994Sdes if (pam_err != PAM_SUCCESS) { 54589994Sdes pam_syslog("pam_setcred()"); 54689994Sdes bail(NO_SLEEP_EXIT, 1); 54789994Sdes } 54897376Sdes 54989994Sdes pam_err = pam_open_session(pamh, pam_silent); 55089994Sdes if (pam_err != PAM_SUCCESS) { 55189994Sdes pam_syslog("pam_open_session()"); 55289994Sdes bail(NO_SLEEP_EXIT, 1); 55389994Sdes } 55489994Sdes pam_session_established = 1; 55574874Smarkm 55689994Sdes /* 55789994Sdes * We must fork() before setuid() because we need to call 55889994Sdes * pam_close_session() as root. 55989994Sdes */ 56089994Sdes pid = fork(); 56189994Sdes if (pid < 0) { 56289994Sdes err(1, "fork"); 56389994Sdes } else if (pid != 0) { 56474874Smarkm /* 56589994Sdes * Parent: wait for child to finish, then clean up 56689994Sdes * session. 567264192Sjilles * 568264192Sjilles * If we get SIGHUP or SIGTERM, clean up the session 569264192Sjilles * and exit right away. This will make the terminal 570264192Sjilles * inaccessible and send SIGHUP to the foreground 571264192Sjilles * process group. 57274874Smarkm */ 573110549Sdes int status; 574107585Sdes setproctitle("-%s [pam]", getprogname()); 575264192Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 576110549Sdes waitpid(pid, &status, 0); 577264192Sjilles (void)sigprocmask(SIG_BLOCK, &mask, NULL); 57889994Sdes bail(NO_SLEEP_EXIT, 0); 57974874Smarkm } 58074874Smarkm 58174874Smarkm /* 58289994Sdes * NOTICE: We are now in the child process! 58321528Sdavidn */ 58497376Sdes 58589994Sdes /* 58689994Sdes * Add any environment variables the PAM modules may have set. 58789994Sdes */ 58889994Sdes export_pam_environment(); 58989994Sdes 59089994Sdes /* 59189994Sdes * We're done with PAM now; our parent will deal with the rest. 59289994Sdes */ 59391714Sdes pam_end(pamh, 0); 59489994Sdes pamh = NULL; 59589994Sdes 59689994Sdes /* 59789994Sdes * We don't need to be root anymore, so set the login name and 59889994Sdes * the UID. 59989994Sdes */ 60041279Sjdp if (setlogin(username) != 0) { 60197376Sdes syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 60289994Sdes bail(NO_SLEEP_EXIT, 1); 60341279Sjdp } 60441279Sjdp if (setusercontext(lc, pwd, pwd->pw_uid, 60574874Smarkm LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 60697376Sdes syslog(LOG_ERR, "setusercontext() failed - exiting"); 60721528Sdavidn exit(1); 6083205Spst } 60921528Sdavidn 61023148Sache (void)setenv("SHELL", pwd->pw_shell, 1); 61121528Sdavidn (void)setenv("HOME", pwd->pw_dir, 1); 61298960Sache /* Overwrite "term" from login.conf(5) for any known TERM */ 61398990Sache if (term == NULL && (tp = stypeof(tty)) != NULL) 61498960Sache (void)setenv("TERM", tp, 1); 61598960Sache else 61698960Sache (void)setenv("TERM", TERM_UNKNOWN, 0); 61741279Sjdp (void)setenv("LOGNAME", username, 1); 61841279Sjdp (void)setenv("USER", username, 1); 61921528Sdavidn (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 62021528Sdavidn 6211590Srgrimes if (!quietlog) { 62294203Sru const char *cw; 62323985Sdavidn 62421528Sdavidn cw = login_getcapstr(lc, "welcome", NULL, NULL); 62589994Sdes if (cw != NULL && access(cw, F_OK) == 0) 62689994Sdes motd(cw); 62789994Sdes else 62889994Sdes motd(_PATH_MOTDFILE); 62923985Sdavidn 630146867Smaxim if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 && 631146867Smaxim login_getcapbool(lc, "nocheckmail", 0) == 0) { 632100825Sdwmalone char *cx; 633100825Sdwmalone 63486450Srwatson /* $MAIL may have been set by class. */ 635100825Sdwmalone cx = getenv("MAIL"); 636100825Sdwmalone if (cx == NULL) { 637100825Sdwmalone asprintf(&cx, "%s/%s", 63886450Srwatson _PATH_MAILDIR, pwd->pw_name); 63989994Sdes } 640100825Sdwmalone if (cx && stat(cx, &st) == 0 && st.st_size != 0) 64186450Srwatson (void)printf("You have %smail.\n", 64286450Srwatson (st.st_mtime > st.st_atime) ? "new " : ""); 64389994Sdes if (getenv("MAIL") == NULL) 644100825Sdwmalone free(cx); 64586450Srwatson } 6461590Srgrimes } 6471590Srgrimes 648146867Smaxim login_close(lc_user); 64921528Sdavidn login_close(lc); 6503205Spst 651264192Sjilles sa.sa_handler = SIG_DFL; 652264192Sjilles (void)sigaction(SIGALRM, &sa, NULL); 653264192Sjilles (void)sigaction(SIGQUIT, &sa, NULL); 654264192Sjilles (void)sigaction(SIGINT, &sa, NULL); 655264192Sjilles (void)sigaction(SIGTERM, &sa, NULL); 656264192Sjilles (void)sigaction(SIGHUP, &sa, NULL); 657264192Sjilles sa.sa_handler = SIG_IGN; 658264192Sjilles (void)sigaction(SIGTSTP, &sa, NULL); 659264192Sjilles (void)sigprocmask(SIG_SETMASK, &omask, NULL); 6601590Srgrimes 66123985Sdavidn /* 66223985Sdavidn * Login shells have a leading '-' in front of argv[0] 66323985Sdavidn */ 66489994Sdes p = strrchr(pwd->pw_shell, '/'); 66589994Sdes if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) { 66681555Smike syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 66781555Smike username); 66881555Smike errx(1, "shell exceeds maximum pathname size"); 66989994Sdes } else if (arg0 == NULL) { 67089994Sdes err(1, "asprintf()"); 67181555Smike } 67223985Sdavidn 67389994Sdes execlp(shell, arg0, (char *)0); 67421528Sdavidn err(1, "%s", shell); 67597376Sdes 67689994Sdes /* 67789994Sdes * That's it, folks! 67889994Sdes */ 6791590Srgrimes} 6801590Srgrimes 68141279Sjdp/* 68241279Sjdp * Attempt to authenticate the user using PAM. Returns 0 if the user is 68341279Sjdp * authenticated, or 1 if not authenticated. If some sort of PAM system 68441279Sjdp * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 68541279Sjdp * function returns -1. This can be used as an indication that we should 68641279Sjdp * fall back to a different authentication mechanism. 68741279Sjdp */ 68841279Sjdpstatic int 68989994Sdesauth_pam(void) 69041279Sjdp{ 69141279Sjdp const char *tmpl_user; 69241279Sjdp const void *item; 69341279Sjdp int rval; 69441279Sjdp 69589994Sdes pam_err = pam_authenticate(pamh, pam_silent); 69689994Sdes switch (pam_err) { 69741279Sjdp 69841279Sjdp case PAM_SUCCESS: 69941279Sjdp /* 70041279Sjdp * With PAM we support the concept of a "template" 70141279Sjdp * user. The user enters a login name which is 70241279Sjdp * authenticated by PAM, usually via a remote service 70341279Sjdp * such as RADIUS or TACACS+. If authentication 70441279Sjdp * succeeds, a different but related "template" name 70541279Sjdp * is used for setting the credentials, shell, and 70641279Sjdp * home directory. The name the user enters need only 70741279Sjdp * exist on the remote authentication server, but the 70841279Sjdp * template name must be present in the local password 70941279Sjdp * database. 71041279Sjdp * 71141279Sjdp * This is supported by two various mechanisms in the 71241279Sjdp * individual modules. However, from the application's 71341279Sjdp * point of view, the template user is always passed 71441279Sjdp * back as a changed value of the PAM_USER item. 71541279Sjdp */ 71689994Sdes pam_err = pam_get_item(pamh, PAM_USER, &item); 71789994Sdes if (pam_err == PAM_SUCCESS) { 71889994Sdes tmpl_user = (const char *)item; 71941279Sjdp if (strcmp(username, tmpl_user) != 0) 72041279Sjdp pwd = getpwnam(tmpl_user); 72189994Sdes } else { 72289994Sdes pam_syslog("pam_get_item(PAM_USER)"); 72389994Sdes } 72441279Sjdp rval = 0; 72541279Sjdp break; 72641279Sjdp 72741279Sjdp case PAM_AUTH_ERR: 72841279Sjdp case PAM_USER_UNKNOWN: 72941279Sjdp case PAM_MAXTRIES: 73041279Sjdp rval = 1; 73141279Sjdp break; 73241279Sjdp 73341279Sjdp default: 73489994Sdes pam_syslog("pam_authenticate()"); 73541279Sjdp rval = -1; 73641279Sjdp break; 73741279Sjdp } 73874874Smarkm 73974874Smarkm if (rval == 0) { 74089994Sdes pam_err = pam_acct_mgmt(pamh, pam_silent); 74189994Sdes switch (pam_err) { 74289994Sdes case PAM_SUCCESS: 74389994Sdes break; 74489994Sdes case PAM_NEW_AUTHTOK_REQD: 74589994Sdes pam_err = pam_chauthtok(pamh, 74689994Sdes pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK); 74789994Sdes if (pam_err != PAM_SUCCESS) { 74889994Sdes pam_syslog("pam_chauthtok()"); 74974874Smarkm rval = 1; 75074874Smarkm } 75189994Sdes break; 75289994Sdes default: 75389994Sdes pam_syslog("pam_acct_mgmt()"); 75474874Smarkm rval = 1; 75589994Sdes break; 75674874Smarkm } 75741279Sjdp } 75874874Smarkm 75974874Smarkm if (rval != 0) { 76089994Sdes pam_end(pamh, pam_err); 76174874Smarkm pamh = NULL; 76274874Smarkm } 76389994Sdes return (rval); 76441279Sjdp} 76572215Snectar 76689994Sdes/* 76789994Sdes * Export any environment variables PAM modules may have set 76889994Sdes */ 76989994Sdesstatic void 770201382Sedexport_pam_environment(void) 77172215Snectar{ 77289994Sdes char **pam_env; 77389994Sdes char **pp; 77472215Snectar 77589994Sdes pam_env = pam_getenvlist(pamh); 77689994Sdes if (pam_env != NULL) { 77789994Sdes for (pp = pam_env; *pp != NULL; pp++) { 778169177Sache (void)export(*pp); 779169177Sache free(*pp); 78089994Sdes } 78172215Snectar } 78272215Snectar} 78372215Snectar 78472215Snectar/* 78589994Sdes * Perform sanity checks on an environment variable: 78672215Snectar * - Make sure there is an '=' in the string. 78772215Snectar * - Make sure the string doesn't run on too long. 78872215Snectar * - Do not export certain variables. This list was taken from the 78972215Snectar * Solaris pam_putenv(3) man page. 79089994Sdes * Then export it. 79172215Snectar */ 79272215Snectarstatic int 79389994Sdesexport(const char *s) 79472215Snectar{ 79572215Snectar static const char *noexport[] = { 79672215Snectar "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 79772215Snectar "IFS", "PATH", NULL 79872215Snectar }; 799171195Sscf char *p; 80072215Snectar const char **pp; 80172215Snectar size_t n; 80272215Snectar 803171195Sscf if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL) 80489994Sdes return (0); 80572215Snectar if (strncmp(s, "LD_", 3) == 0) 80689994Sdes return (0); 80772215Snectar for (pp = noexport; *pp != NULL; pp++) { 80872215Snectar n = strlen(*pp); 80972215Snectar if (s[n] == '=' && strncmp(s, *pp, n) == 0) 81089994Sdes return (0); 81172215Snectar } 812171195Sscf *p = '\0'; 813171195Sscf (void)setenv(s, p + 1, 1); 814171195Sscf *p = '='; 81589994Sdes return (1); 81672215Snectar} 81741279Sjdp 81827605Scharnierstatic void 819201382Sedusage(void) 82027605Scharnier{ 82176791Sobrien 82227605Scharnier (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 82327605Scharnier exit(1); 82427605Scharnier} 8251590Srgrimes 82623985Sdavidn/* 82789994Sdes * Prompt user and read login name from stdin. 82874874Smarkm */ 82989994Sdesstatic char * 830201382Sedgetloginname(void) 8311590Srgrimes{ 83289994Sdes char *nbuf, *p; 8331590Srgrimes int ch; 8341590Srgrimes 83589994Sdes nbuf = malloc(MAXLOGNAME); 83689994Sdes if (nbuf == NULL) 83789994Sdes err(1, "malloc()"); 83889994Sdes do { 83981555Smike (void)printf("%s", prompt); 8401590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 8411590Srgrimes if (ch == EOF) { 8421590Srgrimes badlogin(username); 84389994Sdes bail(NO_SLEEP_EXIT, 0); 8441590Srgrimes } 84589994Sdes if (p < nbuf + MAXLOGNAME - 1) 8461590Srgrimes *p++ = ch; 8471590Srgrimes } 84889994Sdes } while (p == nbuf); 84997376Sdes 85089994Sdes *p = '\0'; 85189994Sdes if (nbuf[0] == '-') { 85289994Sdes pam_silent = 0; 85389994Sdes memmove(nbuf, nbuf + 1, strlen(nbuf)); 85489994Sdes } else { 85589994Sdes pam_silent = PAM_SILENT; 8561590Srgrimes } 85789994Sdes return nbuf; 8581590Srgrimes} 8591590Srgrimes 86089994Sdes/* 86189994Sdes * SIGINT handler for motd(). 86289994Sdes */ 86389994Sdesstatic volatile int motdinterrupt; 86489994Sdesstatic void 86589994Sdessigint(int signo __unused) 8661590Srgrimes{ 86721528Sdavidn motdinterrupt = 1; 86821528Sdavidn} 86921528Sdavidn 87089994Sdes/* 87189994Sdes * Display the contents of a file (such as /etc/motd). 87289994Sdes */ 87389994Sdesstatic int 87489994Sdesmotd(const char *motdfile) 87521528Sdavidn{ 876264192Sjilles struct sigaction newint, oldint; 87789994Sdes FILE *f; 87889994Sdes int ch; 8791590Srgrimes 88089994Sdes if ((f = fopen(motdfile, "r")) == NULL) 88189994Sdes return (-1); 88221528Sdavidn motdinterrupt = 0; 883264192Sjilles newint.sa_handler = sigint; 884264192Sjilles newint.sa_flags = 0; 885264192Sjilles sigfillset(&newint.sa_mask); 886264192Sjilles sigaction(SIGINT, &newint, &oldint); 88789994Sdes while ((ch = fgetc(f)) != EOF && !motdinterrupt) 88889994Sdes putchar(ch); 889264192Sjilles sigaction(SIGINT, &oldint, NULL); 89089994Sdes if (ch != EOF || ferror(f)) { 89189994Sdes fclose(f); 89289994Sdes return (-1); 89389994Sdes } 89489994Sdes fclose(f); 89589994Sdes return (0); 8961590Srgrimes} 8971590Srgrimes 89889994Sdes/* 89989994Sdes * SIGALRM handler, to enforce login prompt timeout. 90089994Sdes * 90189994Sdes * XXX This can potentially confuse the hell out of PAM. We should 90289994Sdes * XXX instead implement a conversation function that returns 90389994Sdes * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal 90489994Sdes * XXX handler just set a flag. 90589994Sdes */ 90689994Sdesstatic void 90789994Sdestimedout(int signo __unused) 9081590Srgrimes{ 90976788Sobrien 91042272Seivind longjmp(timeout_buf, signo); 9111590Srgrimes} 9121590Srgrimes 913105164Sphkstatic void 91489994Sdesbadlogin(char *name) 9151590Srgrimes{ 9161590Srgrimes 9171590Srgrimes if (failures == 0) 9181590Srgrimes return; 91989994Sdes if (hflag) { 9201590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 92189994Sdes failures, failures > 1 ? "S" : "", hostname); 9221590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9231590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 92489994Sdes failures, failures > 1 ? "S" : "", hostname, name); 9251590Srgrimes } else { 9261590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 9271590Srgrimes failures, failures > 1 ? "S" : "", tty); 9281590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 9291590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 9301590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 9311590Srgrimes } 93242272Seivind failures = 0; 9331590Srgrimes} 9341590Srgrimes 93587173Smarkmconst char * 93689994Sdesstypeof(char *ttyid) 9371590Srgrimes{ 9381590Srgrimes struct ttyent *t; 93923985Sdavidn 94081555Smike if (ttyid != NULL && *ttyid != '\0') { 94181555Smike t = getttynam(ttyid); 94281555Smike if (t != NULL && t->ty_type != NULL) 94381555Smike return (t->ty_type); 94481555Smike } 94598960Sache return (NULL); 9461590Srgrimes} 9471590Srgrimes 948105164Sphkstatic void 94989994Sdesrefused(const char *msg, const char *rtype, int lout) 95023985Sdavidn{ 95123985Sdavidn 95223985Sdavidn if (msg != NULL) 95323985Sdavidn printf("%s.\n", msg); 95489994Sdes if (hflag) 95523985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 95689994Sdes pwd->pw_name, rtype, hostname, tty); 95723985Sdavidn else 95823985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 95976788Sobrien pwd->pw_name, rtype, tty); 96023985Sdavidn if (lout) 96189994Sdes bail(SLEEP_EXIT, 1); 96223985Sdavidn} 96323985Sdavidn 96489994Sdes/* 96589994Sdes * Log a PAM error 96689994Sdes */ 967105164Sphkstatic void 96889994Sdespam_syslog(const char *msg) 9691590Srgrimes{ 97089994Sdes syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); 97189994Sdes} 97223985Sdavidn 97389994Sdes/* 97489994Sdes * Shut down PAM 97589994Sdes */ 976105164Sphkstatic void 977201382Sedpam_cleanup(void) 97889994Sdes{ 97989994Sdes 98089994Sdes if (pamh != NULL) { 98189994Sdes if (pam_session_established) { 98289994Sdes pam_err = pam_close_session(pamh, 0); 98389994Sdes if (pam_err != PAM_SUCCESS) 98489994Sdes pam_syslog("pam_close_session()"); 98589994Sdes } 98689994Sdes pam_session_established = 0; 98789994Sdes if (pam_cred_established) { 98889994Sdes pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED); 98989994Sdes if (pam_err != PAM_SUCCESS) 99089994Sdes pam_syslog("pam_setcred()"); 99189994Sdes } 99289994Sdes pam_cred_established = 0; 99389994Sdes pam_end(pamh, pam_err); 99489994Sdes pamh = NULL; 99589994Sdes } 99689994Sdes} 99789994Sdes 998264192Sjillesstatic void 999264192Sjillesbail_internal(int sec, int eval, int signo) 100089994Sdes{ 1001264192Sjilles struct sigaction sa; 100289994Sdes 100389994Sdes pam_cleanup(); 1004165152Scsjp#ifdef USE_BSM_AUDIT 1005157215Scognet if (pwd != NULL) 1006157215Scognet audit_logout(); 1007165152Scsjp#endif 100889994Sdes (void)sleep(sec); 1009264192Sjilles if (signo == 0) 1010264192Sjilles exit(eval); 1011264192Sjilles else { 1012264192Sjilles sa.sa_handler = SIG_DFL; 1013264192Sjilles sa.sa_flags = 0; 1014264192Sjilles (void)sigemptyset(&sa.sa_mask); 1015264192Sjilles (void)sigaction(signo, &sa, NULL); 1016264192Sjilles (void)sigaddset(&sa.sa_mask, signo); 1017264192Sjilles (void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); 1018264192Sjilles raise(signo); 1019264192Sjilles exit(128 + signo); 1020264192Sjilles } 10211590Srgrimes} 1022264192Sjilles 1023264192Sjilles/* 1024264192Sjilles * Exit, optionally after sleeping a few seconds 1025264192Sjilles */ 1026264192Sjillesstatic void 1027264192Sjillesbail(int sec, int eval) 1028264192Sjilles{ 1029264192Sjilles bail_internal(sec, eval, 0); 1030264192Sjilles} 1031264192Sjilles 1032264192Sjilles/* 1033264192Sjilles * Exit because of a signal. 1034264192Sjilles * This is not async-signal safe, so only call async-signal safe functions 1035264192Sjilles * while the signal is unmasked. 1036264192Sjilles */ 1037264192Sjillesstatic void 1038264192Sjillesbail_sig(int signo) 1039264192Sjilles{ 1040264192Sjilles bail_internal(NO_SLEEP_EXIT, 0, signo); 1041264192Sjilles} 1042