login.c revision 23246
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
3423246Swosch#if 0
351590Srgrimesstatic char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
3823246Swosch#endif
391590Srgrimes
401590Srgrimes#ifndef lint
411590Srgrimesstatic char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
421590Srgrimes#endif /* not lint */
431590Srgrimes
441590Srgrimes/*
451590Srgrimes * login [ name ]
461590Srgrimes * login -h hostname	(for telnetd, etc.)
471590Srgrimes * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
481590Srgrimes */
491590Srgrimes
5023246Swosch#include <sys/copyright.h>
511590Srgrimes#include <sys/param.h>
521590Srgrimes#include <sys/stat.h>
531590Srgrimes#include <sys/time.h>
541590Srgrimes#include <sys/resource.h>
551590Srgrimes#include <sys/file.h>
5616423Sache#include <netinet/in.h>
5716423Sache#include <arpa/inet.h>
581590Srgrimes
591590Srgrimes#include <err.h>
601590Srgrimes#include <errno.h>
611590Srgrimes#include <grp.h>
6216423Sache#include <netdb.h>
631590Srgrimes#include <pwd.h>
641590Srgrimes#include <setjmp.h>
651590Srgrimes#include <signal.h>
661590Srgrimes#include <stdio.h>
671590Srgrimes#include <stdlib.h>
681590Srgrimes#include <string.h>
691590Srgrimes#include <syslog.h>
701590Srgrimes#include <ttyent.h>
711590Srgrimes#include <unistd.h>
721590Srgrimes#include <utmp.h>
731590Srgrimes
7421528Sdavidn#ifdef LOGIN_CAP
7521528Sdavidn#include <login_cap.h>
7621528Sdavidn#else /* Undef AUTH as well */
7721528Sdavidn#undef LOGIN_CAP_AUTH
7821528Sdavidn#endif
7921528Sdavidn
8021528Sdavidn/* If LOGIN_CAP_AUTH is activated:
8121528Sdavidn * kerberose & skey logins are runtime selected via login
8221528Sdavidn * login_getstyle() and authentication types for login classes
8321528Sdavidn * The actual login itself is handled via /usr/libexec/login_<style>
8421528Sdavidn * Valid styles are determined by the auth-type=style,style entries
8521528Sdavidn * in the login class.
8621528Sdavidn */
8721528Sdavidn#ifdef LOGIN_CAP_AUTH
8821528Sdavidn#undef KERBEROS
8921528Sdavidn#undef SKEY
9021528Sdavidn#else
913702Spst#ifdef	SKEY
923702Spst#include <skey.h>
9321528Sdavidn#endif /* SKEY */
9421528Sdavidn#endif /* LOGIN_CAP_AUTH */
953702Spst
961590Srgrimes#include "pathnames.h"
971590Srgrimes
981590Srgrimesvoid	 badlogin __P((char *));
991590Srgrimesvoid	 checknologin __P((void));
1001590Srgrimesvoid	 dolastlog __P((int));
1011590Srgrimesvoid	 getloginname __P((void));
10221528Sdavidnvoid	 motd __P((char *));
1031590Srgrimesint	 rootterm __P((char *));
1041590Srgrimesvoid	 sigint __P((int));
1051590Srgrimesvoid	 sleepexit __P((int));
1061590Srgrimeschar	*stypeof __P((char *));
1071590Srgrimesvoid	 timedout __P((int));
1082224Sguidovoid     login_fbtab __P((char *, uid_t, gid_t));
1091590Srgrimes#ifdef KERBEROS
1101590Srgrimesint	 klogin __P((struct passwd *, char *, char *, char *));
1111590Srgrimes#endif
1121590Srgrimes
1131590Srgrimesextern void login __P((struct utmp *));
1141590Srgrimes
1151590Srgrimes#define	TTYGRPNAME	"tty"		/* name of group to own ttys */
1161590Srgrimes
1171590Srgrimes/*
1181590Srgrimes * This bounds the time given to login.  Not a define so it can
1191590Srgrimes * be patched on machines where it's too small.
1201590Srgrimes */
1211590Srgrimesu_int	timeout = 300;
1221590Srgrimes
1231590Srgrimes#ifdef KERBEROS
1241590Srgrimesint	notickets = 1;
1255627Swollmanint	noticketsdontcomplain = 1;
1261590Srgrimeschar	*instance;
1271590Srgrimeschar	*krbtkfile_env;
1281590Srgrimesint	authok;
1291590Srgrimes#endif
1301590Srgrimes
1311590Srgrimesstruct	passwd *pwd;
1321590Srgrimesint	failures;
1331590Srgrimeschar	term[64], *envinit[1], *hostname, *username, *tty;
13416423Sachechar    full_hostname[MAXHOSTNAMELEN];
1351590Srgrimes
1361590Srgrimesint
1371590Srgrimesmain(argc, argv)
1381590Srgrimes	int argc;
1391590Srgrimes	char *argv[];
1401590Srgrimes{
1411590Srgrimes	extern char **environ;
1421590Srgrimes	struct group *gr;
1431590Srgrimes	struct stat st;
1441590Srgrimes	struct timeval tp;
1451590Srgrimes	struct utmp utmp;
14621528Sdavidn	int rootok;
1471590Srgrimes	int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
1484878Sugen	int changepass;
1491590Srgrimes	uid_t uid;
1503205Spst	char *domain, *p, *ep, *salt, *ttyn;
1511590Srgrimes	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
1521590Srgrimes	char localhost[MAXHOSTNAMELEN];
15321528Sdavidn	char shell[MAXPATHLEN];
15421528Sdavidn#ifdef LOGIN_CAP
15521528Sdavidn	login_cap_t *lc = NULL;
15621528Sdavidn#ifdef LOGIN_CAP_AUTH
15721528Sdavidn	char *style, *authtype;
15821528Sdavidn	char *auth_method = NULL;
15921528Sdavidn	char *instance = NULL;
16021528Sdavidn	int authok;
16121528Sdavidn#else /* !LOGIN_CAP_AUTH */
16221528Sdavidn#ifdef SKEY
1633205Spst	int permit_passwd = 0;
16421528Sdavidn#endif /* SKEY */
16521528Sdavidn#endif /* LOGIN_CAP_AUTH */
16621528Sdavidn#endif /* LOGIN_CAP */
1671590Srgrimes
1681590Srgrimes	(void)signal(SIGALRM, timedout);
1691590Srgrimes	(void)alarm(timeout);
1701590Srgrimes	(void)signal(SIGQUIT, SIG_IGN);
1711590Srgrimes	(void)signal(SIGINT, SIG_IGN);
1721590Srgrimes	(void)setpriority(PRIO_PROCESS, 0, 0);
1731590Srgrimes
1741590Srgrimes	openlog("login", LOG_ODELAY, LOG_AUTH);
1751590Srgrimes
1761590Srgrimes	/*
1771590Srgrimes	 * -p is used by getty to tell login not to destroy the environment
1781590Srgrimes	 * -f is used to skip a second login authentication
1791590Srgrimes	 * -h is used by other servers to pass the name of the remote
1801590Srgrimes	 *    host to login so that it may be placed in utmp and wtmp
1811590Srgrimes	 */
1823205Spst	*full_hostname = '\0';
1831590Srgrimes	domain = NULL;
1841590Srgrimes	if (gethostname(localhost, sizeof(localhost)) < 0)
1851590Srgrimes		syslog(LOG_ERR, "couldn't get local hostname: %m");
1861590Srgrimes	else
1871590Srgrimes		domain = strchr(localhost, '.');
1881590Srgrimes
1891590Srgrimes	fflag = hflag = pflag = 0;
1901590Srgrimes	uid = getuid();
1911590Srgrimes	while ((ch = getopt(argc, argv, "fh:p")) != EOF)
1921590Srgrimes		switch (ch) {
1931590Srgrimes		case 'f':
1941590Srgrimes			fflag = 1;
1951590Srgrimes			break;
1961590Srgrimes		case 'h':
1971590Srgrimes			if (uid)
1981590Srgrimes				errx(1, "-h option: %s", strerror(EPERM));
1991590Srgrimes			hflag = 1;
2003205Spst			strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
2011590Srgrimes			if (domain && (p = strchr(optarg, '.')) &&
2021590Srgrimes			    strcasecmp(p, domain) == 0)
2031590Srgrimes				*p = 0;
20416423Sache			if (strlen(optarg) > UT_HOSTSIZE) {
20516423Sache				struct hostent *hp = gethostbyname(optarg);
20616423Sache
20716423Sache				if (hp != NULL) {
20816423Sache					struct in_addr in;
20916423Sache
21016423Sache					memmove(&in, hp->h_addr, sizeof(in));
21116423Sache					optarg = strdup(inet_ntoa(in));
21216423Sache				} else
21316423Sache					optarg = "invalid hostname";
21416423Sache			}
2151590Srgrimes			hostname = optarg;
2161590Srgrimes			break;
2171590Srgrimes		case 'p':
2181590Srgrimes			pflag = 1;
2191590Srgrimes			break;
2201590Srgrimes		case '?':
2211590Srgrimes		default:
2221590Srgrimes			if (!uid)
2231590Srgrimes				syslog(LOG_ERR, "invalid flag %c", ch);
2241590Srgrimes			(void)fprintf(stderr,
2251590Srgrimes			    "usage: login [-fp] [-h hostname] [username]\n");
2261590Srgrimes			exit(1);
2271590Srgrimes		}
2281590Srgrimes	argc -= optind;
2291590Srgrimes	argv += optind;
2301590Srgrimes
2311590Srgrimes	if (*argv) {
2321590Srgrimes		username = *argv;
2331590Srgrimes		ask = 0;
2341590Srgrimes	} else
2351590Srgrimes		ask = 1;
2361590Srgrimes
2371590Srgrimes	for (cnt = getdtablesize(); cnt > 2; cnt--)
2381590Srgrimes		(void)close(cnt);
2391590Srgrimes
2401590Srgrimes	ttyn = ttyname(STDIN_FILENO);
2411590Srgrimes	if (ttyn == NULL || *ttyn == '\0') {
2421590Srgrimes		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
2431590Srgrimes		ttyn = tname;
2441590Srgrimes	}
2451590Srgrimes	if (tty = strrchr(ttyn, '/'))
2461590Srgrimes		++tty;
2471590Srgrimes	else
2481590Srgrimes		tty = ttyn;
2491590Srgrimes
25021528Sdavidn#ifdef LOGIN_CAP_AUTH
25121528Sdavidn	authtype = hostname ? "rlogin" : "login";
25221528Sdavidn#endif
25321528Sdavidn
2541590Srgrimes	for (cnt = 0;; ask = 1) {
2551590Srgrimes		if (ask) {
2561590Srgrimes			fflag = 0;
2571590Srgrimes			getloginname();
2581590Srgrimes		}
2591590Srgrimes		rootlogin = 0;
26021528Sdavidn		rootok = rootterm(tty); /* Default (auth may change) */
26121528Sdavidn#ifdef LOGIN_CAP_AUTH
26221528Sdavidn		authok = 0;
26321528Sdavidn		if (auth_method = strchr(username, ':')) {
26421528Sdavidn			*auth_method = '\0';
26521528Sdavidn			auth_method++;
26621528Sdavidn			if (*auth_method == '\0')
26721528Sdavidn				auth_method = NULL;
26821528Sdavidn		}
26921528Sdavidn		/*
27021528Sdavidn		 * We need to do this regardless of whether
27121528Sdavidn		 * kerberos is available.
27221528Sdavidn		 */
2731590Srgrimes		if ((instance = strchr(username, '.')) != NULL) {
2741590Srgrimes			if (strncmp(instance, ".root", 5) == 0)
2751590Srgrimes				rootlogin = 1;
2761590Srgrimes			*instance++ = '\0';
2771590Srgrimes		} else
2781590Srgrimes			instance = "";
27921528Sdavidn#else /* !LOGIN_CAP_AUTH */
28021528Sdavidn#ifdef KERBEROS
28121528Sdavidn		if ((instance = strchr(username, '.')) != NULL) {
28221528Sdavidn			if (strncmp(instance, ".root", 5) == 0)
28321528Sdavidn				rootlogin = 1;
28421528Sdavidn			*instance++ = '\0';
28521528Sdavidn		} else
28621528Sdavidn			instance = "";
28721528Sdavidn#endif /* KERBEROS */
28821528Sdavidn#endif /* LOGIN_CAP_AUTH */
28921528Sdavidn
2901590Srgrimes		if (strlen(username) > UT_NAMESIZE)
2911590Srgrimes			username[UT_NAMESIZE] = '\0';
2921590Srgrimes
2931590Srgrimes		/*
2941590Srgrimes		 * Note if trying multiple user names; log failures for
2951590Srgrimes		 * previous user name, but don't bother logging one failure
2961590Srgrimes		 * for nonexistent name (mistyped username).
2971590Srgrimes		 */
2981590Srgrimes		if (failures && strcmp(tbuf, username)) {
2991590Srgrimes			if (failures > (pwd ? 0 : 1))
3001590Srgrimes				badlogin(tbuf);
3011590Srgrimes			failures = 0;
3021590Srgrimes		}
3031590Srgrimes		(void)strcpy(tbuf, username);
3041590Srgrimes
30521528Sdavidn		pwd = getpwnam(username);
30621528Sdavidn#ifdef LOGIN_CAP
30721528Sdavidn		/* Establish the class now, before we might goto
30821528Sdavidn		 * within the next block. pwd can be NULL since it
30921528Sdavidn		 * falls back to the "default" class if it is.
31021528Sdavidn		 */
31121528Sdavidn		lc = login_getclass(pwd);
31221528Sdavidn#endif /* LOGIN_CAP */
3131590Srgrimes
3141590Srgrimes		/*
3151590Srgrimes		 * if we have a valid account name, and it doesn't have a
3161590Srgrimes		 * password, or the -f option was specified and the caller
3171590Srgrimes		 * is root or the caller isn't changing their uid, don't
3181590Srgrimes		 * authenticate.
3191590Srgrimes		 */
32021528Sdavidn		if (pwd != NULL) {
32121528Sdavidn			salt = pwd->pw_passwd;
3223205Spst			if (pwd->pw_uid == 0)
3233205Spst				rootlogin = 1;
3243205Spst
3253205Spst			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
3263205Spst				/* already authenticated */
3273205Spst				break;
3283205Spst			} else if (pwd->pw_passwd[0] == '\0') {
3293205Spst				/* pretend password okay */
3303205Spst				rval = 0;
3313205Spst				goto ttycheck;
3323205Spst			}
3333205Spst		}
33421528Sdavidn		else
33521528Sdavidn			salt = "xx";
3363205Spst
3371590Srgrimes		fflag = 0;
3381590Srgrimes
3391590Srgrimes		(void)setpriority(PRIO_PROCESS, 0, -4);
3401590Srgrimes
34121528Sdavidn#ifdef LOGIN_CAP_AUTH
34221528Sdavidn		/*
34321528Sdavidn		 * This hands off authorisation to an authorisation program,
34421528Sdavidn		 * depending on the styles available for the "auth-login",
34521528Sdavidn		 * auth-rlogin (or default) authorisation styles.
34621528Sdavidn		 * We do this regardless of whether an account exists so that
34721528Sdavidn		 * the remote user cannot tell a "real" from an invented
34821528Sdavidn		 * account name. If we don't have an account we just fall
34921528Sdavidn		 * back to the first method for the "default" class.
35021528Sdavidn		 */
35121528Sdavidn		if ((style = login_getstyle(lc, auth_method, authtype)) == NULL) {
35221528Sdavidn			rval = 1; /* No available authorisation method */
35321528Sdavidn			(void)printf("No auth method available for %s.\n", authtype);
35421528Sdavidn		} else {
35521528Sdavidn			/* Put back the kerberos instance, if any was given.
35621528Sdavidn			 * Don't worry about the non-kerberos case here, since
35721528Sdavidn			 * if kerberos is not available or not selected and an
35821528Sdavidn			 * instance is given at the login prompt, su or rlogin -l,
35921528Sdavidn			 * then anything else should fail as well.
36021528Sdavidn			 */
36121528Sdavidn			if (*instance)
36221528Sdavidn				*(instance - 1) = '.';
36321528Sdavidn			rval = authenticate(username, lc ? lc->lc_class : "default", style, authtype);
36421528Sdavidn			/* Junk it again */
36521528Sdavidn			if (*instance)
36621528Sdavidn				*(instance - 1) = '\0';
36721528Sdavidn		}
36821528Sdavidn
36921528Sdavidn		if (!rval) {
37021528Sdavidn			/*
37121528Sdavidn			 * If authentication succeeds, run any approval
37221528Sdavidn			 * program, if applicable for this class.
37321528Sdavidn			 */
37421528Sdavidn			char *approvep = login_getcapstr(lc, "approve", NULL, NULL);
37521528Sdavidn			rval = 1; /* Assume bad login again */
37621528Sdavidn			if (approvep==NULL || auth_script(approvep, approvep, username, lc->lc_class, 0) == 0) {
37721528Sdavidn				int     r = auth_scan(AUTH_OKAY);
37821528Sdavidn				/* See what the authorise program says */
37921528Sdavidn				if (r != AUTH_NONE) {
38021528Sdavidn					rval = 0;
38121528Sdavidn					if (!rootok && (r & AUTH_ROOTOKAY))
38221528Sdavidn						rootok = 1; /* root approved */
38321528Sdavidn					else rootlogin = 0;
38421528Sdavidn					if (!authok && (r & AUTH_SECURE))
38521528Sdavidn						authok = 1; /* secure */
38621528Sdavidn				}
38721528Sdavidn			}
38821528Sdavidn		}
38921528Sdavidn#else /* !LOGIN_CAP_AUTH */
39021528Sdavidn#ifdef SKEY
39121528Sdavidn		permit_passwd = skeyaccess(username, tty, hostname ? full_hostname : NULL, NULL);
3923205Spst		p = skey_getpass("Password:", pwd, permit_passwd);
3933205Spst		ep = skey_crypt(p, salt, pwd, permit_passwd);
39421528Sdavidn#else /* !SKEY */
3951590Srgrimes		p = getpass("Password:");
3963205Spst		ep = crypt(p, salt);
39721528Sdavidn#endif/* SKEY */
3981590Srgrimes#ifdef KERBEROS
3997800Swollman#ifdef SKEY
40021528Sdavidn		if (pwd) {
40121528Sdavidn			/* Do not allow user to type in kerberos password
4027800Swollman			 * over the net (actually, this is ok for encrypted
4037800Swollman			 * links, but we have no way of determining if the
4047800Swollman			 * link is encrypted.
4057800Swollman			 */
4067893Srgrimes			if (!permit_passwd) {
40721528Sdavidn				rval = 1;		/* force failure */
4087800Swollman			} else
40921528Sdavidn#endif /* SKEY */
4101590Srgrimes			rval = klogin(pwd, instance, localhost, p);
4111590Srgrimes			if (rval != 0 && rootlogin && pwd->pw_uid != 0)
4121590Srgrimes				rootlogin = 0;
4131590Srgrimes			if (rval == 0)
41421528Sdavidn				authok = 1; /* kerberos authenticated ok */
41521528Sdavidn			else if (rval == 1) /* fallback to unix passwd */
4163205Spst				rval = strcmp(ep, pwd->pw_passwd);
41721528Sdavidn#ifdef SKEY
4181590Srgrimes		}
41921528Sdavidn#endif /* SKEY */
42021528Sdavidn#else /* !KERBEROS */
42121950Sjkh		if (pwd)
42221950Sjkh		    rval = strcmp(ep, pwd->pw_passwd);
42321528Sdavidn#endif /* KERBEROS */
42421528Sdavidn		/* clear entered password */
4251590Srgrimes		memset(p, 0, strlen(p));
42621528Sdavidn#endif /* LOGIN_CAP_AUTH */
4271590Srgrimes
4281590Srgrimes		(void)setpriority(PRIO_PROCESS, 0, 0);
42921528Sdavidn#ifdef LOGIN_CAP
43021528Sdavidn		if (rval)
43121528Sdavidn			auth_rmfiles();
43221528Sdavidn#endif
4333205Spst	ttycheck:
4341590Srgrimes		/*
4351590Srgrimes		 * If trying to log in as root without Kerberos,
4361590Srgrimes		 * but with insecure terminal, refuse the login attempt.
4371590Srgrimes		 */
43821528Sdavidn#if defined(KERBEROS) || defined(LOGIN_CAP_AUTH)
4391590Srgrimes		if (authok == 0)
4401590Srgrimes#endif
44121528Sdavidn		if (pwd && !rval && rootlogin && !rootok) {
44221528Sdavidn			(void)fprintf(stderr, "%s login refused on this terminal.\n", pwd->pw_name);
4431590Srgrimes			if (hostname)
44421528Sdavidn				syslog(LOG_NOTICE, "LOGIN %s REFUSED FROM %s ON TTY %s", pwd->pw_name, full_hostname, tty);
4451590Srgrimes			else
44621528Sdavidn				syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", pwd->pw_name, tty);
4471590Srgrimes			continue;
4481590Srgrimes		}
4491590Srgrimes
45021528Sdavidn		if (pwd && !rval) /* valid password & authenticated */
4511590Srgrimes			break;
4521590Srgrimes
4531590Srgrimes		(void)printf("Login incorrect\n");
4541590Srgrimes		failures++;
4551590Srgrimes		/* we allow 10 tries, but after 3 we start backing off */
4561590Srgrimes		if (++cnt > 3) {
4571590Srgrimes			if (cnt >= 10) {
4581590Srgrimes				badlogin(username);
4591590Srgrimes				sleepexit(1);
4601590Srgrimes			}
4611590Srgrimes			sleep((u_int)((cnt - 3) * 5));
4621590Srgrimes		}
4631590Srgrimes	}
4641590Srgrimes
4651590Srgrimes	/* committed to login -- turn off timeout */
4661590Srgrimes	(void)alarm((u_int)0);
4671590Srgrimes
4681590Srgrimes	endpwent();
4691590Srgrimes
4701590Srgrimes	/* if user not super-user, check for disabled logins */
47121528Sdavidn#ifdef LOGIN_CAP
4721590Srgrimes	if (!rootlogin)
47321528Sdavidn		auth_checknologin(lc);
47421528Sdavidn#else
47521528Sdavidn	if (!rootlogin)
4761590Srgrimes		checknologin();
47721528Sdavidn#endif
4781590Srgrimes
47921528Sdavidn#ifdef LOGIN_CAP
48021528Sdavidn	quietlog = login_getcapbool(lc, "hushlogin", 0);
48121528Sdavidn#else
48221528Sdavidn	quietlog = 0;
48321528Sdavidn#endif
48421528Sdavidn	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
48521528Sdavidn#ifdef LOGIN_CAP
48621528Sdavidn		if (login_getcapbool(lc, "requirehome", !rootlogin) || chdir("/") < 0) {
48721528Sdavidn			(void)printf("No home directory %s!\n", pwd->pw_dir);
48821528Sdavidn			sleepexit(1);
48921528Sdavidn		}
49021528Sdavidn#else
49121528Sdavidn		if (chdir("/") < 0) {
49221528Sdavidn			(void)printf("No home directory %s!\n", pwd->pw_dir);
49321528Sdavidn			sleepexit(1);
49421528Sdavidn		}
49521528Sdavidn#endif
4961590Srgrimes		pwd->pw_dir = "/";
49721528Sdavidn		if (!quietlog)
49821528Sdavidn			(void)printf("No home directory.\nLogging in with home = \"/\".\n");
4991590Srgrimes	}
50021528Sdavidn	if (!quietlog)
50121528Sdavidn		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
5021590Srgrimes
5031590Srgrimes	if (pwd->pw_change || pwd->pw_expire)
5041590Srgrimes		(void)gettimeofday(&tp, (struct timezone *)NULL);
5052532Sjkh
50621528Sdavidn#define DEFAULT_WARN  (2L * 7L & 86400L)  /* Two weeks */
50721528Sdavidn
5084878Sugen	changepass=0;
50921528Sdavidn	if (pwd->pw_change) {
5101590Srgrimes		if (tp.tv_sec >= pwd->pw_change) {
5111590Srgrimes			(void)printf("Sorry -- your password has expired.\n");
51221528Sdavidn			syslog(LOG_NOTICE, "%s Password expired - forcing change", pwd->pw_name);
5134878Sugen			changepass=1;
51421528Sdavidn#ifdef LOGIN_CAP
51521528Sdavidn		} else {
51621528Sdavidn			time_t warntime = (time_t)login_getcaptime(lc, "warnpassword", DEFAULT_WARN, DEFAULT_WARN);
51721528Sdavidn			if (pwd->pw_change - tp.tv_sec < warntime && !quietlog)
51821528Sdavidn				(void)printf("Warning: your password expires on %s", ctime(&pwd->pw_change));
51921528Sdavidn		}
52021528Sdavidn#else
52121528Sdavidn		} else if (pwd->pw_change - tp.tv_sec < DEFAULT_WARN && !quietlog) {
52221528Sdavidn			(void)printf("Warning: your password expires on %s", ctime(&pwd->pw_change));
52321528Sdavidn		}
52421528Sdavidn#endif
52521528Sdavidn	}
52621528Sdavidn	if (pwd->pw_expire) {
5271590Srgrimes		if (tp.tv_sec >= pwd->pw_expire) {
5281590Srgrimes			(void)printf("Sorry -- your account has expired.\n");
52921528Sdavidn			syslog(LOG_NOTICE, "%s Account expired - login refused", pwd->pw_name);
5301590Srgrimes			sleepexit(1);
53121528Sdavidn#ifdef LOGIN_CAP
53221528Sdavidn		} else {
53321528Sdavidn			time_t warntime = (time_t)login_getcaptime(lc, "warnexpire", DEFAULT_WARN, DEFAULT_WARN);
53421528Sdavidn			if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
53521528Sdavidn				(void)printf("Warning: your account expires on %s",
53621528Sdavidn					    ctime(&pwd->pw_expire));
53721528Sdavidn		}
53821528Sdavidn#else
53921528Sdavidn		} else if (pwd->pw_expire - tp.tv_sec < DEFAULT_WARN && !quietlog) {
5401590Srgrimes			(void)printf("Warning: your account expires on %s",
54121528Sdavidn				    ctime(&pwd->pw_expire));
54221528Sdavidn		}
54321528Sdavidn#endif
54421528Sdavidn	}
5451590Srgrimes
54621528Sdavidn#ifdef LOGIN_CAP
54721528Sdavidn	if (lc != NULL) {
54821528Sdavidn		char  *msg = NULL;
54921528Sdavidn
55021528Sdavidn		if (hostname) {
55121528Sdavidn			struct hostent *hp = gethostbyname(full_hostname);
55221528Sdavidn
55321528Sdavidn			if (hp == NULL)
55421528Sdavidn				optarg = NULL;
55521528Sdavidn			else {
55621528Sdavidn				struct in_addr in;
55721528Sdavidn				memmove(&in, hp->h_addr, sizeof(in));
55821528Sdavidn				optarg = strdup(inet_ntoa(in));
55921528Sdavidn			}
56021528Sdavidn			if (!auth_hostok(lc, full_hostname, optarg)) {
56121528Sdavidn				syslog(LOG_NOTICE, "%s LOGIN REFUSED (HOST) FROM %s", pwd->pw_name, full_hostname);
56221528Sdavidn				msg = "Permission denied";
56321528Sdavidn			}
56421528Sdavidn		}
56521528Sdavidn
56621528Sdavidn		if (msg == NULL && !auth_ttyok(lc, tty)) {
56721528Sdavidn			syslog(LOG_NOTICE, "%s LOGIN REFUSED (TTY) ON %s", pwd->pw_name, tty);
56821528Sdavidn			msg = "Permission denied";
56921528Sdavidn		}
57021528Sdavidn
57121528Sdavidn		if (msg == NULL && !auth_timeok(lc, time(NULL))) {
57221528Sdavidn			syslog(LOG_NOTICE, "%s LOGIN REFUSED (TIME) %s %s", pwd->pw_name, hostname?"FROM":"ON", hostname?full_hostname:tty);
57321528Sdavidn			msg = "Logins not available right now";
57421528Sdavidn		}
57521528Sdavidn
57621528Sdavidn		if (msg != NULL) {
57721528Sdavidn			printf("%s.\n", msg);
57821528Sdavidn			sleepexit(1);
57921528Sdavidn		}
58021528Sdavidn	}
58121528Sdavidn	strncpy(shell, login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell), sizeof shell);
58221528Sdavidn#else /* !LOGIN_CAP */
58321528Sdavidn	strncpy(shell, pwd->pw_shell, sizeof shell);
58421528Sdavidn#endif /* LOGIN_CAP */
58521528Sdavidn	shell[sizeof shell - 1] = '\0';
58621528Sdavidn
58721528Sdavidn#ifdef LOGIN_ACCESS
58821528Sdavidn	if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) {
58921528Sdavidn		printf("Permission denied\n");
59021528Sdavidn		syslog(LOG_NOTICE, "%s LOGIN REFUSED (ACCESS) %s %s", pwd->pw_name, hostname?"FROM":"ON", hostname?full_hostname:tty);
59121528Sdavidn		sleepexit(1);
59221528Sdavidn	}
59321528Sdavidn#endif /* LOGIN_ACCESS */
59421528Sdavidn
5951590Srgrimes	/* Nothing else left to fail -- really log in. */
5961590Srgrimes	memset((void *)&utmp, 0, sizeof(utmp));
5971590Srgrimes	(void)time(&utmp.ut_time);
5981590Srgrimes	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
5991590Srgrimes	if (hostname)
6001590Srgrimes		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
6011590Srgrimes	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
6021590Srgrimes	login(&utmp);
6031590Srgrimes
6041590Srgrimes	dolastlog(quietlog);
6051590Srgrimes
6062224Sguido	/*
6072224Sguido	 * Set device protections, depending on what terminal the
6082224Sguido	 * user is logged in. This feature is used on Suns to give
6092224Sguido	 * console users better privacy.
6102224Sguido	 */
6112224Sguido	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
6122224Sguido
61321528Sdavidn	(void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
6141590Srgrimes
61521528Sdavidn	/* Preserve TERM if it happens to be already set */
61621528Sdavidn	if ((p = getenv("TERM")) != NULL) {
61721528Sdavidn		(void)strncpy(term, p, sizeof(term));
61821528Sdavidn		term[sizeof(term)-1] = '\0';
61921528Sdavidn	}
6201590Srgrimes
62121528Sdavidn	/* Exclude cons/vt/ptys only, assume dialup otherwise */
62221528Sdavidn	if (hostname==NULL && strchr("vpqstPQST", tty[sizeof("tty")-1]) == NULL)
6231590Srgrimes		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
6241590Srgrimes
6251590Srgrimes	/* If fflag is on, assume caller/authenticator has logged root login. */
6261590Srgrimes	if (rootlogin && fflag == 0)
62721528Sdavidn		syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s%s%s", username, tty, hostname?" FROM ":"", hostname?full_hostname:"");
6281590Srgrimes
6291590Srgrimes#ifdef KERBEROS
6305627Swollman	if (!quietlog && notickets == 1 && !noticketsdontcomplain)
6311590Srgrimes		(void)printf("Warning: no Kerberos tickets issued.\n");
6321590Srgrimes#endif
6331590Srgrimes
6343205Spst#ifdef LOGALL
6353205Spst	/*
6363205Spst	 * Syslog each successful login, so we don't have to watch hundreds
6373205Spst	 * of wtmp or lastlogin files.
6383205Spst	 */
63921528Sdavidn	syslog(LOG_INFO, "login %s %s as %s", hostname?"from":"on", hostname?full_hostname:tty, pwd->pw_name);
64021528Sdavidn#endif
64121528Sdavidn
64221528Sdavidn	/* Destroy environment unless user has requested its preservation. */
64321528Sdavidn	if (!pflag)
64421528Sdavidn		environ = envinit;
64521528Sdavidn
64621528Sdavidn	/* We don't need to be root anymore, so
64721528Sdavidn	 * set the user and session context
64821528Sdavidn	 */
64921528Sdavidn#ifdef LOGIN_CAP
65021528Sdavidn	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
65121528Sdavidn                syslog(LOG_ERR, "setusercontext() failed - exiting");
65221528Sdavidn		exit(1);
6533205Spst	}
65421528Sdavidn#else
65521528Sdavidn     	if (setlogin(pwd->pw_name) < 0)
65621528Sdavidn                syslog(LOG_ERR, "setlogin() failure: %m");
65721528Sdavidn
65821528Sdavidn	(void)setgid(pwd->pw_gid);
65921528Sdavidn	initgroups(username, pwd->pw_gid);
66021528Sdavidn	(void)setuid(rootlogin ? 0 : pwd->pw_uid);
6613205Spst#endif
6623205Spst
66323148Sache	if (*pwd->pw_shell == '\0') {
66423148Sache		pwd->pw_shell = _PATH_BSHELL;
66523148Sache		if (*shell == '\0')   /* Not overridden */
66623148Sache			strcpy(shell, pwd->pw_shell);
66723148Sache	}
66823148Sache	(void)setenv("SHELL", pwd->pw_shell, 1);
66921528Sdavidn	(void)setenv("HOME", pwd->pw_dir, 1);
67021528Sdavidn	if (term[0] != '\0')
67121528Sdavidn		(void)setenv("TERM", term, 1);	/* Preset overrides */
67221528Sdavidn	else {
67321528Sdavidn		(void)strncpy(term, stypeof(tty), sizeof(term));
67421528Sdavidn		term[sizeof(term)-1] = '\0';
67521528Sdavidn		(void)setenv("TERM", term, 0);	/* Fallback doesn't */
67621528Sdavidn	}
67721528Sdavidn	(void)setenv("LOGNAME", pwd->pw_name, 1);
67821528Sdavidn	(void)setenv("USER", pwd->pw_name, 1);
67921528Sdavidn	(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
68021528Sdavidn#if LOGIN_CAP_AUTH
68121528Sdavidn	auth_env();
68221528Sdavidn#else
68321528Sdavidn#ifdef KERBEROS
68421528Sdavidn	if (krbtkfile_env)
68521528Sdavidn		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
68621528Sdavidn#endif
68721528Sdavidn#endif
68821528Sdavidn
6891590Srgrimes	if (!quietlog) {
69021528Sdavidn#ifdef LOGIN_CAP
69121528Sdavidn		char *cw = login_getcapstr(lc, "copyright", NULL, NULL);
69221528Sdavidn		if (cw != NULL && access(cw, F_OK) == 0)
69321528Sdavidn			motd(cw);
69421528Sdavidn		else
69521528Sdavidn#endif
69623246Swosch		(void)printf("%s\n", copyright);
69721528Sdavidn#ifdef LOGIN_CAP
69821528Sdavidn		cw = login_getcapstr(lc, "welcome", NULL, NULL);
69921528Sdavidn		if (cw == NULL || access(cw, F_OK) != 0)
70021528Sdavidn			cw = _PATH_MOTDFILE;
70121528Sdavidn		motd(cw);
70221528Sdavidn		cw = getenv("MAIL");	/* $MAIL may have been set by class */
70321528Sdavidn		if (cw != NULL) {
70421528Sdavidn			strncpy(tbuf, cw, sizeof(tbuf));
70521528Sdavidn			tbuf[sizeof(tbuf)-1] = '\0';
70621528Sdavidn		} else
70721528Sdavidn			snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
70821528Sdavidn#else
70921528Sdavidn		motd(_PATH_MOTDFILE);
71021528Sdavidn		snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
71121528Sdavidn#endif
7121590Srgrimes		if (stat(tbuf, &st) == 0 && st.st_size != 0)
71321528Sdavidn			(void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : "");
7141590Srgrimes	}
7151590Srgrimes
71621528Sdavidn	/* Login shells have a leading '-' in front of argv[0] */
71721528Sdavidn	tbuf[0] = '-';
71823148Sache	(void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell);
71921528Sdavidn
72021528Sdavidn#ifdef LOGIN_CAP
72121528Sdavidn	login_close(lc);
7223205Spst#endif
7233205Spst
7241590Srgrimes	(void)signal(SIGALRM, SIG_DFL);
7251590Srgrimes	(void)signal(SIGQUIT, SIG_DFL);
7261590Srgrimes	(void)signal(SIGINT, SIG_DFL);
7271590Srgrimes	(void)signal(SIGTSTP, SIG_IGN);
7281590Srgrimes
7294878Sugen	if (changepass) {
73021528Sdavidn		if (system(_PATH_CHPASS) != 0)
7314878Sugen			sleepexit(1);
7324878Sugen	}
7334878Sugen
73421528Sdavidn	execlp(shell, tbuf, 0);
73521528Sdavidn	err(1, "%s", shell);
7361590Srgrimes}
7371590Srgrimes
7381590Srgrimes
73921528Sdavidn/* Allow for authentication style and/or kerberos instance */
74021528Sdavidn
74121528Sdavidn#define	NBUFSIZ		UT_NAMESIZE + 64
74221528Sdavidn
7431590Srgrimesvoid
7441590Srgrimesgetloginname()
7451590Srgrimes{
7461590Srgrimes	int ch;
7471590Srgrimes	char *p;
7481590Srgrimes	static char nbuf[NBUFSIZ];
7491590Srgrimes
7501590Srgrimes	for (;;) {
7511590Srgrimes		(void)printf("login: ");
7521590Srgrimes		for (p = nbuf; (ch = getchar()) != '\n'; ) {
7531590Srgrimes			if (ch == EOF) {
7541590Srgrimes				badlogin(username);
7551590Srgrimes				exit(0);
7561590Srgrimes			}
7571590Srgrimes			if (p < nbuf + (NBUFSIZ - 1))
7581590Srgrimes				*p++ = ch;
7591590Srgrimes		}
7601590Srgrimes		if (p > nbuf)
7611590Srgrimes			if (nbuf[0] == '-')
7621590Srgrimes				(void)fprintf(stderr,
7631590Srgrimes				    "login names may not start with '-'.\n");
7641590Srgrimes			else {
7651590Srgrimes				*p = '\0';
7661590Srgrimes				username = nbuf;
7671590Srgrimes				break;
7681590Srgrimes			}
7691590Srgrimes	}
7701590Srgrimes}
7711590Srgrimes
7721590Srgrimesint
7731590Srgrimesrootterm(ttyn)
7741590Srgrimes	char *ttyn;
7751590Srgrimes{
7761590Srgrimes	struct ttyent *t;
7771590Srgrimes	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
7781590Srgrimes}
7791590Srgrimes
78021528Sdavidnvolatile int motdinterrupt;
7811590Srgrimes
78221528Sdavidn/* ARGSUSED */
7831590Srgrimesvoid
78421528Sdavidnsigint(signo)
78521528Sdavidn	int signo;
7861590Srgrimes{
78721528Sdavidn	motdinterrupt = 1;
78821528Sdavidn}
78921528Sdavidn
79021528Sdavidnvoid
79121528Sdavidnmotd(motdfile)
79221528Sdavidn	char *motdfile;
79321528Sdavidn{
7941590Srgrimes	int fd, nchars;
7951590Srgrimes	sig_t oldint;
79621528Sdavidn	char tbuf[256];
7971590Srgrimes
79821528Sdavidn	if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
7991590Srgrimes		return;
80021528Sdavidn	motdinterrupt = 0;
8011590Srgrimes	oldint = signal(SIGINT, sigint);
80221528Sdavidn	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
80321528Sdavidn		(void)write(fileno(stdout), tbuf, nchars);
8041590Srgrimes	(void)signal(SIGINT, oldint);
8051590Srgrimes	(void)close(fd);
8061590Srgrimes}
8071590Srgrimes
8081590Srgrimes/* ARGSUSED */
8091590Srgrimesvoid
8101590Srgrimestimedout(signo)
8111590Srgrimes	int signo;
8121590Srgrimes{
8131590Srgrimes	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
8141590Srgrimes	exit(0);
8151590Srgrimes}
8161590Srgrimes
81721528Sdavidn#ifndef LOGIN_CAP
8181590Srgrimesvoid
8191590Srgrimeschecknologin()
8201590Srgrimes{
8211590Srgrimes	int fd, nchars;
8221590Srgrimes	char tbuf[8192];
8231590Srgrimes
8241590Srgrimes	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
8251590Srgrimes		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
8261590Srgrimes			(void)write(fileno(stdout), tbuf, nchars);
8271590Srgrimes		sleepexit(0);
8281590Srgrimes	}
8291590Srgrimes}
83021528Sdavidn#endif
8311590Srgrimes
8321590Srgrimesvoid
8331590Srgrimesdolastlog(quiet)
8341590Srgrimes	int quiet;
8351590Srgrimes{
8361590Srgrimes	struct lastlog ll;
8371590Srgrimes	int fd;
8381590Srgrimes
8391590Srgrimes	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
8401590Srgrimes		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
8411590Srgrimes		if (!quiet) {
8421590Srgrimes			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
8431590Srgrimes			    ll.ll_time != 0) {
8441590Srgrimes				(void)printf("Last login: %.*s ",
8451590Srgrimes				    24-5, (char *)ctime(&ll.ll_time));
8461590Srgrimes				if (*ll.ll_host != '\0')
8471590Srgrimes					(void)printf("from %.*s\n",
8481590Srgrimes					    (int)sizeof(ll.ll_host),
8491590Srgrimes					    ll.ll_host);
8501590Srgrimes				else
8511590Srgrimes					(void)printf("on %.*s\n",
8521590Srgrimes					    (int)sizeof(ll.ll_line),
8531590Srgrimes					    ll.ll_line);
8541590Srgrimes			}
8551590Srgrimes			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
8561590Srgrimes		}
8571590Srgrimes		memset((void *)&ll, 0, sizeof(ll));
8581590Srgrimes		(void)time(&ll.ll_time);
8591590Srgrimes		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
8601590Srgrimes		if (hostname)
8611590Srgrimes			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
8621590Srgrimes		(void)write(fd, (char *)&ll, sizeof(ll));
8631590Srgrimes		(void)close(fd);
8641590Srgrimes	}
8651590Srgrimes}
8661590Srgrimes
8671590Srgrimesvoid
8681590Srgrimesbadlogin(name)
8691590Srgrimes	char *name;
8701590Srgrimes{
8711590Srgrimes
8721590Srgrimes	if (failures == 0)
8731590Srgrimes		return;
8741590Srgrimes	if (hostname) {
8751590Srgrimes		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
87616423Sache		    failures, failures > 1 ? "S" : "", full_hostname);
8771590Srgrimes		syslog(LOG_AUTHPRIV|LOG_NOTICE,
8781590Srgrimes		    "%d LOGIN FAILURE%s FROM %s, %s",
87916423Sache		    failures, failures > 1 ? "S" : "", full_hostname, name);
8801590Srgrimes	} else {
8811590Srgrimes		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
8821590Srgrimes		    failures, failures > 1 ? "S" : "", tty);
8831590Srgrimes		syslog(LOG_AUTHPRIV|LOG_NOTICE,
8841590Srgrimes		    "%d LOGIN FAILURE%s ON %s, %s",
8851590Srgrimes		    failures, failures > 1 ? "S" : "", tty, name);
8861590Srgrimes	}
8871590Srgrimes}
8881590Srgrimes
8891590Srgrimes#undef	UNKNOWN
8901590Srgrimes#define	UNKNOWN	"su"
8911590Srgrimes
8921590Srgrimeschar *
8931590Srgrimesstypeof(ttyid)
8941590Srgrimes	char *ttyid;
8951590Srgrimes{
8961590Srgrimes	struct ttyent *t;
8971590Srgrimes	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
8981590Srgrimes}
8991590Srgrimes
9001590Srgrimesvoid
9011590Srgrimessleepexit(eval)
9021590Srgrimes	int eval;
9031590Srgrimes{
9041590Srgrimes	(void)sleep(5);
9051590Srgrimes	exit(eval);
9061590Srgrimes}
9072532Sjkh
9082532Sjkh
909