xref: /netbsd-src/libexec/getty/main.c (revision caba86e5d2c05a270b81d3bcd9151d74997e8104)
1*caba86e5Sjmcneill /*	$NetBSD: main.c,v 1.68 2021/10/12 23:40:38 jmcneill Exp $	*/
23ff0b1a7Sthorpej 
361f28255Scgd /*-
4fe822416Spk  * Copyright (c) 1980, 1993
5fe822416Spk  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
158e6ab883Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
3264521eb3Smikel #include <sys/cdefs.h>
3364521eb3Smikel 
3461f28255Scgd #ifndef lint
350c4ddb15Slukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
360c4ddb15Slukem  The Regents of the University of California.  All rights reserved.");
3761f28255Scgd #endif /* not lint */
3861f28255Scgd 
3961f28255Scgd #ifndef lint
403ff0b1a7Sthorpej #if 0
413ff0b1a7Sthorpej static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";
423ff0b1a7Sthorpej #else
43*caba86e5Sjmcneill __RCSID("$NetBSD: main.c,v 1.68 2021/10/12 23:40:38 jmcneill Exp $");
443ff0b1a7Sthorpej #endif
4561f28255Scgd #endif /* not lint */
4661f28255Scgd 
4761f28255Scgd #include <sys/param.h>
487243f6f6Spk #include <sys/ioctl.h>
49fe822416Spk #include <sys/resource.h>
507d85ef5cSchristos #include <sys/stat.h>
51cea87043Smycroft #include <sys/utsname.h>
52a6da6f65Smikel 
536c41aa55Sdholland #include <ctype.h>
546c5f1488Scgd #include <errno.h>
5561f28255Scgd #include <fcntl.h>
566c41aa55Sdholland #include <limits.h>
57fd97c4a9Scjs #include <pwd.h>
5861f28255Scgd #include <setjmp.h>
59fe822416Spk #include <signal.h>
6092227bd1Schristos #include <stdio.h>
6161f28255Scgd #include <stdlib.h>
6261f28255Scgd #include <string.h>
63fe822416Spk #include <syslog.h>
6498eb8895Sroy #include <term.h>
6592227bd1Schristos #include <termios.h>
66fe822416Spk #include <time.h>
676c41aa55Sdholland #include <ttyent.h>
68fe822416Spk #include <unistd.h>
6901120f44Sjtc #include <util.h>
70fe822416Spk 
7161f28255Scgd #include "gettytab.h"
7261f28255Scgd #include "pathnames.h"
73fe822416Spk #include "extern.h"
7461f28255Scgd 
75c6a0145eSchristos extern char editedhost[];
76fd97c4a9Scjs 
77fe822416Spk /*
78fe822416Spk  * Set the amount of running time that getty should accumulate
79fe822416Spk  * before deciding that something is wrong and exit.
80fe822416Spk  */
81fe822416Spk #define GETTY_TIMEOUT	60 /* seconds */
82fe822416Spk 
8313b21dc1Stsarna /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
8413b21dc1Stsarna 
8513b21dc1Stsarna #define PPP_FRAME           0x7e  /* PPP Framing character */
8613b21dc1Stsarna #define PPP_STATION         0xff  /* "All Station" character */
8713b21dc1Stsarna #define PPP_ESCAPE          0x7d  /* Escape Character */
8813b21dc1Stsarna #define PPP_CONTROL         0x03  /* PPP Control Field */
8913b21dc1Stsarna #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
9013b21dc1Stsarna #define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
9113b21dc1Stsarna #define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
9213b21dc1Stsarna 
93fe822416Spk struct termios tmode, omode;
9461f28255Scgd 
956fc636d8Sdholland int crmod, digit_or_punc, lower, upper;
9661f28255Scgd 
972beab49aSmrg char	hostname[MAXHOSTNAMELEN + 1];
98cea87043Smycroft struct	utsname kerninfo;
99d46a0af8Sdrochner char	name[LOGIN_NAME_MAX];
10061f28255Scgd char	dev[] = _PATH_DEV;
10161f28255Scgd char	ttyn[32];
102fcfd8038Sriastradh uid_t	ttyowner = 0;
103ac8e2453Ssommerfeld char	*rawttyn;
10461f28255Scgd 
10561f28255Scgd #define	OBUFSIZ		128
10661f28255Scgd #define	TABBUFSIZ	512
10761f28255Scgd 
10861f28255Scgd char	defent[TABBUFSIZ];
10961f28255Scgd char	tabent[TABBUFSIZ];
11061f28255Scgd 
11161f28255Scgd char	*env[128];
11261f28255Scgd 
11323431545Schristos const unsigned char partab[] = {
11461f28255Scgd 	0001,0201,0201,0001,0201,0001,0001,0201,
11561f28255Scgd 	0202,0004,0003,0205,0005,0206,0201,0001,
11661f28255Scgd 	0201,0001,0001,0201,0001,0201,0201,0001,
11761f28255Scgd 	0001,0201,0201,0001,0201,0001,0001,0201,
11861f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
11961f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0200,
12061f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0200,
12161f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
12261f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
12361f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0200,
12461f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0200,
12561f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
12661f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0200,
12761f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
12861f28255Scgd 	0200,0000,0000,0200,0000,0200,0200,0000,
12961f28255Scgd 	0000,0200,0200,0000,0200,0000,0000,0201
13061f28255Scgd };
13161f28255Scgd 
1327243f6f6Spk #define	ERASE	tmode.c_cc[VERASE]
1337243f6f6Spk #define	KILL	tmode.c_cc[VKILL]
1347243f6f6Spk #define	EOT	tmode.c_cc[VEOF]
13561f28255Scgd 
1365648feb3Sthorpej static void	clearscreen(void);
13764521eb3Smikel 
13827c14eadSdholland sigjmp_buf timeout;
13961f28255Scgd 
140fabae2a4Sjoerg __dead static void
14123431545Schristos /*ARGSUSED*/
dingdong(int signo)1425648feb3Sthorpej dingdong(int signo)
14361f28255Scgd {
14461f28255Scgd 
14523431545Schristos 	(void)alarm(0);
14623431545Schristos 	(void)signal(SIGALRM, SIG_DFL);
14727c14eadSdholland 	siglongjmp(timeout, 1);
14861f28255Scgd }
14961f28255Scgd 
15027c14eadSdholland sigjmp_buf intrupt;
15161f28255Scgd 
152fabae2a4Sjoerg __dead static void
15323431545Schristos /*ARGSUSED*/
interrupt(int signo)1545648feb3Sthorpej interrupt(int signo)
15561f28255Scgd {
15661f28255Scgd 
15723431545Schristos 	(void)signal(SIGINT, interrupt);
15827c14eadSdholland 	siglongjmp(intrupt, 1);
15961f28255Scgd }
16061f28255Scgd 
161fe822416Spk /*
162fe822416Spk  * Action to take when getty is running too long.
163fe822416Spk  */
164fabae2a4Sjoerg __dead static void
16523431545Schristos /*ARGSUSED*/
timeoverrun(int signo)1665648feb3Sthorpej timeoverrun(int signo)
167fe822416Spk {
168fe822416Spk 
16913b21dc1Stsarna 	syslog(LOG_ERR, "getty exiting due to excessive running time");
170fe822416Spk 	exit(1);
171fe822416Spk }
172fe822416Spk 
1735648feb3Sthorpej static int	getname(void);
1745648feb3Sthorpej static void	oflush(void);
1755648feb3Sthorpej static void	prompt(void);
176d56846afSroy static int	putchr(int);
1775648feb3Sthorpej static void	putf(const char *);
1785648feb3Sthorpej static void	xputs(const char *);
179fe822416Spk 
180d56846afSroy #define putpad(s) tputs(s, 1, putchr)
181d56846afSroy 
182fe822416Spk int
main(int argc,char * argv[],char * envp[])18323431545Schristos main(int argc, char *argv[], char *envp[])
18461f28255Scgd {
18543c3c3f7Schristos 	int repcnt = 0, failopenlogged = 0;
18643c3c3f7Schristos 	volatile int first_time = 1;
187fe822416Spk 	struct rlimit limit;
18813b21dc1Stsarna 	int rval;
18900b8abd4Smartin 	/* this is used past the siglongjmp, so make sure it is not cached
19000b8abd4Smartin 	   in registers that might become invalid. */
19100b8abd4Smartin 	const char * volatile tname = "default";
19261f28255Scgd 
19323431545Schristos 	(void)signal(SIGINT, SIG_IGN);
19423e33516Slukem 	openlog("getty", LOG_PID, LOG_AUTH);
19523431545Schristos 	(void)gethostname(hostname, sizeof(hostname));
1962beab49aSmrg 	hostname[sizeof(hostname) - 1] = '\0';
19761f28255Scgd 	if (hostname[0] == '\0')
19823431545Schristos 		(void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
19923431545Schristos 	(void)uname(&kerninfo);
200fe822416Spk 
201fe822416Spk 	/*
202fe822416Spk 	 * Limit running time to deal with broken or dead lines.
203fe822416Spk 	 */
204fe822416Spk 	(void)signal(SIGXCPU, timeoverrun);
205fe822416Spk 	limit.rlim_max = RLIM_INFINITY;
206fe822416Spk 	limit.rlim_cur = GETTY_TIMEOUT;
207fe822416Spk 	(void)setrlimit(RLIMIT_CPU, &limit);
208fe822416Spk 
20961f28255Scgd 	/*
21061f28255Scgd 	 * The following is a work around for vhangup interactions
21161f28255Scgd 	 * which cause great problems getting window systems started.
21261f28255Scgd 	 * If the tty line is "-", we do the old style getty presuming
21361f28255Scgd 	 * that the file descriptors are already set up for us.
21461f28255Scgd 	 * J. Gettys - MIT Project Athena.
21561f28255Scgd 	 */
21680eef670Stls 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
21723431545Schristos 		(void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
21880eef670Stls 	}
21961f28255Scgd 	else {
22061f28255Scgd 		int i;
22161f28255Scgd 
222ac8e2453Ssommerfeld 		rawttyn = argv[2];
22323431545Schristos 		(void)strlcpy(ttyn, dev, sizeof(ttyn));
22423431545Schristos 		(void)strlcat(ttyn, argv[2], sizeof(ttyn));
22561f28255Scgd 		if (strcmp(argv[0], "+") != 0) {
22623431545Schristos 			(void)chown(ttyn, ttyowner, 0);
22723431545Schristos 			(void)chmod(ttyn, 0600);
22823431545Schristos 			(void)revoke(ttyn);
229d2ae1a2cSgwr 			if (ttyaction(ttyn, "getty", "root"))
23023431545Schristos 				syslog(LOG_WARNING, "%s: ttyaction failed",
23123431545Schristos 					ttyn);
23261f28255Scgd 			while ((i = open(ttyn, O_RDWR)) == -1) {
2336c5f1488Scgd 				if ((repcnt % 10 == 0) &&
2346c5f1488Scgd 				    (errno != ENXIO || !failopenlogged)) {
23523e33516Slukem 					syslog(LOG_WARNING, "%s: %m", ttyn);
23661f28255Scgd 					closelog();
2376c5f1488Scgd 					failopenlogged = 1;
23861f28255Scgd 				}
23961f28255Scgd 				repcnt++;
24023431545Schristos 				(void)sleep(60);
24161f28255Scgd 			}
24223431545Schristos 			(void)login_tty(i);
24361f28255Scgd 		}
24461f28255Scgd 	}
24561f28255Scgd 
2467243f6f6Spk 	/* Start with default tty settings */
2477243f6f6Spk 	if (tcgetattr(0, &tmode) < 0) {
2487243f6f6Spk 		syslog(LOG_ERR, "%s: %m", ttyn);
2497243f6f6Spk 		exit(1);
2507243f6f6Spk 	}
251fe822416Spk 	omode = tmode;
2527243f6f6Spk 
25303fe423bScgd 	gettable("default", defent);
25461f28255Scgd 	gendefaults();
25561f28255Scgd 	if (argc > 1)
25661f28255Scgd 		tname = argv[1];
25761f28255Scgd 	for (;;) {
258fe822416Spk 		int off;
25961f28255Scgd 
260a8ce8744Slukem 		rval = 0;
26103fe423bScgd 		gettable(tname, tabent);
26261f28255Scgd 		if (OPset || EPset || APset)
26361f28255Scgd 			APset++, OPset++, EPset++;
26461f28255Scgd 		setdefaults();
265fe822416Spk 		off = 0;
2666b619f18Spk 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
26723431545Schristos 		(void)ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
26823431545Schristos 		(void)ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
2697243f6f6Spk 
27061f28255Scgd 		if (IS)
27123431545Schristos 			(void)cfsetispeed(&tmode, (speed_t)IS);
27261f28255Scgd 		else if (SP)
27323431545Schristos 			(void)cfsetispeed(&tmode, (speed_t)SP);
27461f28255Scgd 		if (OS)
27523431545Schristos 			(void)cfsetospeed(&tmode, (speed_t)OS);
27661f28255Scgd 		else if (SP)
27723431545Schristos 			(void)cfsetospeed(&tmode, (speed_t)SP);
2787243f6f6Spk 		setflags(0);
27961f28255Scgd 		setchars();
2807243f6f6Spk 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
2817243f6f6Spk 			syslog(LOG_ERR, "%s: %m", ttyn);
2827243f6f6Spk 			exit(1);
2837243f6f6Spk 		}
28461f28255Scgd 		if (AB) {
28561f28255Scgd 			tname = autobaud();
28661f28255Scgd 			continue;
28761f28255Scgd 		}
28861f28255Scgd 		if (PS) {
28961f28255Scgd 			tname = portselector();
29061f28255Scgd 			continue;
29161f28255Scgd 		}
292ac8e2453Ssommerfeld 		if (CS)
293ac8e2453Ssommerfeld 			clearscreen();
29461f28255Scgd 		if (CL && *CL)
29561f28255Scgd 			putpad(CL);
29661f28255Scgd 		edithost(HE);
2972a1297dbSad 
2982a1297dbSad 		/*
2992a1297dbSad 		 * If this is the first time through this, and an
3002a1297dbSad 		 * issue file has been given, then send it.
3012a1297dbSad 		 */
3026aa5f514Sad 		if (first_time != 0 && IF != NULL) {
3032a1297dbSad 			char buf[_POSIX2_LINE_MAX];
30423431545Schristos 			FILE *fp;
3052a1297dbSad 
30623431545Schristos 			if ((fp = fopen(IF, "r")) != NULL) {
30723431545Schristos 				while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
3082a1297dbSad 					putf(buf);
30923431545Schristos 				(void)fclose(fp);
3102a1297dbSad 			}
3112a1297dbSad 		}
3122a1297dbSad 		first_time = 0;
3132a1297dbSad 
31461f28255Scgd 		if (IM && *IM)
31561f28255Scgd 			putf(IM);
316ca59ae7cSkml 		oflush();
31727c14eadSdholland 		if (sigsetjmp(timeout, 1)) {
3187243f6f6Spk 			tmode.c_ispeed = tmode.c_ospeed = 0;
3197243f6f6Spk 			(void)tcsetattr(0, TCSANOW, &tmode);
32061f28255Scgd 			exit(1);
32161f28255Scgd 		}
32261f28255Scgd 		if (TO) {
32323431545Schristos 			(void)signal(SIGALRM, dingdong);
32423431545Schristos 			(void)alarm((unsigned int)TO);
32561f28255Scgd 		}
3262c1e4826Sthorpej 		if (NN) {
3272c1e4826Sthorpej 			name[0] = '\0';
3282c1e4826Sthorpej 			lower = 1;
3296fc636d8Sdholland 			upper = digit_or_punc = 0;
3302c1e4826Sthorpej 		} else if (AL) {
3312a1297dbSad 			const char *p = AL;
3322a1297dbSad 			char *q = name;
3332a1297dbSad 
3342a1297dbSad 			while (*p && q < &name[sizeof name - 1]) {
33555d39107Sdsl 				if (isupper((unsigned char)*p))
3362a1297dbSad 					upper = 1;
33755d39107Sdsl 				else if (islower((unsigned char)*p))
3382a1297dbSad 					lower = 1;
33955d39107Sdsl 				else if (isdigit((unsigned char)*p))
3406fc636d8Sdholland 					digit_or_punc = 1;
3412a1297dbSad 				*q++ = *p++;
3422a1297dbSad 			}
3432a1297dbSad 		} else if ((rval = getname()) == 2) {
3447f94fc6dSchristos 			setflags(2);
34523431545Schristos 			(void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
34613b21dc1Stsarna 			syslog(LOG_ERR, "%s: %m", PP);
34713b21dc1Stsarna 			exit(1);
3482a1297dbSad 		}
3492a1297dbSad 
3502c1e4826Sthorpej 		if (rval || AL || NN) {
351d5088f6aSmrg 			int i;
35261f28255Scgd 
35361f28255Scgd 			oflush();
35423431545Schristos 			(void)alarm(0);
35523431545Schristos 			(void)signal(SIGALRM, SIG_DFL);
35661f28255Scgd 			if (name[0] == '-') {
3578cbf1ce9Sthorpej 				xputs("user names may not start with '-'.");
35861f28255Scgd 				continue;
35961f28255Scgd 			}
3606fc636d8Sdholland 			if (!(upper || lower || digit_or_punc))
36161f28255Scgd 				continue;
3627243f6f6Spk 			setflags(2);
3637243f6f6Spk 			if (crmod) {
3647243f6f6Spk 				tmode.c_iflag |= ICRNL;
3657243f6f6Spk 				tmode.c_oflag |= ONLCR;
3667243f6f6Spk 			}
3677243f6f6Spk #if XXX
36861f28255Scgd 			if (upper || UC)
36961f28255Scgd 				tmode.sg_flags |= LCASE;
37061f28255Scgd 			if (lower || LC)
37161f28255Scgd 				tmode.sg_flags &= ~LCASE;
3727243f6f6Spk #endif
3737243f6f6Spk 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
3747243f6f6Spk 				syslog(LOG_ERR, "%s: %m", ttyn);
3757243f6f6Spk 				exit(1);
3767243f6f6Spk 			}
37723431545Schristos 			(void)signal(SIGINT, SIG_DFL);
37823431545Schristos 			for (i = 0; envp[i] != NULL; i++)
37923431545Schristos 				env[i] = envp[i];
38061f28255Scgd 			makeenv(&env[i]);
381fe822416Spk 
382fe822416Spk 			limit.rlim_max = RLIM_INFINITY;
383fe822416Spk 			limit.rlim_cur = RLIM_INFINITY;
384fe822416Spk 			(void)setrlimit(RLIMIT_CPU, &limit);
3852c1e4826Sthorpej 			if (NN)
38623431545Schristos 				(void)execle(LO, "login", AL ? "-fp" : "-p",
3872c1e4826Sthorpej 				    NULL, env);
3882c1e4826Sthorpej 			else
38923431545Schristos 				(void)execle(LO, "login", AL ? "-fp" : "-p",
3902c1e4826Sthorpej 				    "--", name, NULL, env);
39161f28255Scgd 			syslog(LOG_ERR, "%s: %m", LO);
39261f28255Scgd 			exit(1);
39361f28255Scgd 		}
39423431545Schristos 		(void)alarm(0);
39523431545Schristos 		(void)signal(SIGALRM, SIG_DFL);
39623431545Schristos 		(void)signal(SIGINT, SIG_IGN);
39761f28255Scgd 		if (NX && *NX)
39861f28255Scgd 			tname = NX;
39961f28255Scgd 	}
40061f28255Scgd }
40161f28255Scgd 
402fe822416Spk static int
getname(void)4035648feb3Sthorpej getname(void)
40461f28255Scgd {
405d5088f6aSmrg 	int c;
406d5088f6aSmrg 	char *np;
40713b21dc1Stsarna 	unsigned char cs;
40813b21dc1Stsarna 	int ppp_state, ppp_connection;
40961f28255Scgd 
41061f28255Scgd 	/*
41161f28255Scgd 	 * Interrupt may happen if we use CBREAK mode
41261f28255Scgd 	 */
41327c14eadSdholland 	if (sigsetjmp(intrupt, 1)) {
41423431545Schristos 		(void)signal(SIGINT, SIG_IGN);
41561f28255Scgd 		return (0);
41661f28255Scgd 	}
41723431545Schristos 	(void)signal(SIGINT, interrupt);
4187243f6f6Spk 	setflags(1);
41961f28255Scgd 	prompt();
42061f28255Scgd 	if (PF > 0) {
42161f28255Scgd 		oflush();
42223431545Schristos 		(void)sleep((unsigned int)PF);
42361f28255Scgd 		PF = 0;
42461f28255Scgd 	}
4257243f6f6Spk 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
4267243f6f6Spk 		syslog(LOG_ERR, "%s: %m", ttyn);
4277243f6f6Spk 		exit(1);
4287243f6f6Spk 	}
4296fc636d8Sdholland 	crmod = digit_or_punc = lower = upper = 0;
43013b21dc1Stsarna 	ppp_state = ppp_connection = 0;
43161f28255Scgd 	np = name;
43261f28255Scgd 	for (;;) {
43361f28255Scgd 		oflush();
43461f28255Scgd 		if (read(STDIN_FILENO, &cs, 1) <= 0)
43561f28255Scgd 			exit(0);
43661f28255Scgd 		if ((c = cs&0177) == 0)
43761f28255Scgd 			return (0);
43813b21dc1Stsarna 
43913b21dc1Stsarna 		/*
44013b21dc1Stsarna 		 * PPP detection state machine..
44113b21dc1Stsarna 		 * Look for sequences:
44213b21dc1Stsarna 		 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
44313b21dc1Stsarna 		 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
44413b21dc1Stsarna 		 * See RFC1662.
44513b21dc1Stsarna 		 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
44613b21dc1Stsarna 		 * and Erik 'PPP' Olson <eriko@wrq.com>
44713b21dc1Stsarna 		 */
44813b21dc1Stsarna 		if (PP && cs == PPP_FRAME) {
44913b21dc1Stsarna 			ppp_state = 1;
45013b21dc1Stsarna 		} else if (ppp_state == 1 && cs == PPP_STATION) {
45113b21dc1Stsarna 			ppp_state = 2;
45213b21dc1Stsarna 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
45313b21dc1Stsarna 			ppp_state = 3;
45413b21dc1Stsarna 		} else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
45513b21dc1Stsarna 		    (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
45613b21dc1Stsarna 			ppp_state = 4;
45713b21dc1Stsarna 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
45813b21dc1Stsarna 			ppp_state = 5;
45913b21dc1Stsarna 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
46013b21dc1Stsarna 			ppp_connection = 1;
46113b21dc1Stsarna 			break;
46213b21dc1Stsarna 		} else {
46313b21dc1Stsarna 			ppp_state = 0;
46413b21dc1Stsarna 		}
46513b21dc1Stsarna 
46661f28255Scgd 		if (c == EOT)
46761f28255Scgd 			exit(1);
468d46a0af8Sdrochner 		if (c == '\r' || c == '\n' ||
469d46a0af8Sdrochner 		    np >= &name[LOGIN_NAME_MAX - 1]) {
470d46a0af8Sdrochner 			*np = '\0';
47161f28255Scgd 			putf("\r\n");
47261f28255Scgd 			break;
47361f28255Scgd 		}
47461f28255Scgd 		if (islower(c))
47561f28255Scgd 			lower = 1;
47661f28255Scgd 		else if (isupper(c))
47761f28255Scgd 			upper = 1;
47861f28255Scgd 		else if (c == ERASE || c == '#' || c == '\b') {
47961f28255Scgd 			if (np > name) {
48061f28255Scgd 				np--;
4812f65aa5dSmycroft 				if (cfgetospeed(&tmode) >= 1200)
4828cbf1ce9Sthorpej 					xputs("\b \b");
48361f28255Scgd 				else
48461f28255Scgd 					putchr(cs);
48561f28255Scgd 			}
48661f28255Scgd 			continue;
48761f28255Scgd 		} else if (c == KILL || c == '@') {
48861f28255Scgd 			putchr(cs);
48961f28255Scgd 			putchr('\r');
4902f65aa5dSmycroft 			if (cfgetospeed(&tmode) < 1200)
49161f28255Scgd 				putchr('\n');
49261f28255Scgd 			/* this is the way they do it down under ... */
49361f28255Scgd 			else if (np > name)
4948cbf1ce9Sthorpej 				xputs(
4958cbf1ce9Sthorpej 				    "                                     \r");
49661f28255Scgd 			prompt();
49761f28255Scgd 			np = name;
49861f28255Scgd 			continue;
4996fc636d8Sdholland 		} else if (isdigit(c) || c == '_')
5006fc636d8Sdholland 			digit_or_punc = 1;
50161f28255Scgd 		if (IG && (c <= ' ' || c > 0176))
50261f28255Scgd 			continue;
50361f28255Scgd 		*np++ = c;
50461f28255Scgd 		putchr(cs);
5056b9ab756Schristos 
5066b9ab756Schristos 		/*
5076b9ab756Schristos 		 * An MS-Windows direct connect PPP "client" won't send its
5086b9ab756Schristos 		 * first PPP packet until we respond to its "CLIENT" poll
5096b9ab756Schristos 		 * with a CRLF sequence.  We cater to yet another broken
5106b9ab756Schristos 		 * implementation of a previously-standard protocol...
5116b9ab756Schristos 		 */
5126b9ab756Schristos 		*np = '\0';
5136b9ab756Schristos 		if (strstr(name, "CLIENT"))
5146b9ab756Schristos 			putf("\r\n");
51561f28255Scgd 	}
51623431545Schristos 	(void)signal(SIGINT, SIG_IGN);
51761f28255Scgd 	*np = 0;
51861f28255Scgd 	if (c == '\r')
51961f28255Scgd 		crmod = 1;
52064521eb3Smikel 	if ((upper && !lower && !LC) || UC)
52161f28255Scgd 		for (np = name; *np; np++)
52255d39107Sdsl 			*np = tolower((unsigned char)*np);
52313b21dc1Stsarna 	return (1 + ppp_connection);
52461f28255Scgd }
52561f28255Scgd 
526fe822416Spk static void
xputs(const char * s)5275648feb3Sthorpej xputs(const char *s)
52861f28255Scgd {
52961f28255Scgd 	while (*s)
53061f28255Scgd 		putchr(*s++);
53161f28255Scgd }
53261f28255Scgd 
53361f28255Scgd char	outbuf[OBUFSIZ];
53423431545Schristos size_t	obufcnt = 0;
53561f28255Scgd 
536d56846afSroy static int
putchr(int cc)5375648feb3Sthorpej putchr(int cc)
53861f28255Scgd {
53923431545Schristos 	unsigned char c;
54061f28255Scgd 
54161f28255Scgd 	c = cc;
54261f28255Scgd 	if (!NP) {
54361f28255Scgd 		c |= partab[c&0177] & 0200;
54461f28255Scgd 		if (OP)
54561f28255Scgd 			c ^= 0200;
54661f28255Scgd 	}
54761f28255Scgd 	if (!UB) {
54861f28255Scgd 		outbuf[obufcnt++] = c;
54961f28255Scgd 		if (obufcnt >= OBUFSIZ)
55061f28255Scgd 			oflush();
551d56846afSroy 		return 1;
552d56846afSroy 	}
553d56846afSroy 	return write(STDOUT_FILENO, &c, 1);
55461f28255Scgd }
55561f28255Scgd 
556fe822416Spk static void
oflush(void)5575648feb3Sthorpej oflush(void)
55861f28255Scgd {
55961f28255Scgd 	if (obufcnt)
56023431545Schristos 		(void)write(STDOUT_FILENO, outbuf, obufcnt);
56161f28255Scgd 	obufcnt = 0;
56261f28255Scgd }
56361f28255Scgd 
564fe822416Spk static void
prompt(void)5655648feb3Sthorpej prompt(void)
56661f28255Scgd {
56761f28255Scgd 
56861f28255Scgd 	putf(LM);
56961f28255Scgd 	if (CO)
57061f28255Scgd 		putchr('\n');
57161f28255Scgd }
57261f28255Scgd 
573fe822416Spk static void
putf(const char * cp)5745648feb3Sthorpej putf(const char *cp)
57561f28255Scgd {
57661f28255Scgd 	time_t t;
57761f28255Scgd 	char *slash, db[100];
57861f28255Scgd 
57961f28255Scgd 	while (*cp) {
58061f28255Scgd 		if (*cp != '%') {
58161f28255Scgd 			putchr(*cp++);
58261f28255Scgd 			continue;
58361f28255Scgd 		}
58461f28255Scgd 		switch (*++cp) {
58561f28255Scgd 
58661f28255Scgd 		case 't':
58700e4cd7dSchristos 			if ((slash = strstr(ttyn, "/pts/")) == NULL)
588fe822416Spk 				slash = strrchr(ttyn, '/');
5894fdc2599Smjl 			if (slash == NULL)
5908cbf1ce9Sthorpej 				xputs(ttyn);
59161f28255Scgd 			else
5928cbf1ce9Sthorpej 				xputs(&slash[1]);
59361f28255Scgd 			break;
59461f28255Scgd 
59561f28255Scgd 		case 'h':
5968cbf1ce9Sthorpej 			xputs(editedhost);
59761f28255Scgd 			break;
59861f28255Scgd 
599d657c604Sbjh21 		case 'd':
60061f28255Scgd 			(void)time(&t);
601d657c604Sbjh21 			(void)strftime(db, sizeof(db),
602bf31e2abSmbalmer 			    "%l:%M%p on %A, %d %B %Y", localtime(&t));
6038cbf1ce9Sthorpej 			xputs(db);
60461f28255Scgd 			break;
605cea87043Smycroft 
606cea87043Smycroft 		case 's':
6078cbf1ce9Sthorpej 			xputs(kerninfo.sysname);
608cea87043Smycroft 			break;
609cea87043Smycroft 
610cea87043Smycroft 		case 'm':
6118cbf1ce9Sthorpej 			xputs(kerninfo.machine);
612cea87043Smycroft 			break;
613cea87043Smycroft 
614cea87043Smycroft 		case 'r':
6158cbf1ce9Sthorpej 			xputs(kerninfo.release);
616cea87043Smycroft 			break;
617cea87043Smycroft 
618cea87043Smycroft 		case 'v':
6198cbf1ce9Sthorpej 			xputs(kerninfo.version);
620cea87043Smycroft 			break;
62161f28255Scgd 
62261f28255Scgd 		case '%':
62361f28255Scgd 			putchr('%');
62461f28255Scgd 			break;
62561f28255Scgd 		}
626c10e6676Sbjh21 		if (*cp)
62761f28255Scgd 			cp++;
62861f28255Scgd 	}
62961f28255Scgd }
630ac8e2453Ssommerfeld 
631ac8e2453Ssommerfeld static void
clearscreen(void)6325648feb3Sthorpej clearscreen(void)
633ac8e2453Ssommerfeld {
634ac8e2453Ssommerfeld 	struct ttyent *typ;
63598eb8895Sroy 	int err;
636ac8e2453Ssommerfeld 
637ac8e2453Ssommerfeld 	if (rawttyn == NULL)
638ac8e2453Ssommerfeld 		return;
639ac8e2453Ssommerfeld 
640ac8e2453Ssommerfeld 	typ = getttynam(rawttyn);
641ac8e2453Ssommerfeld 
642ac8e2453Ssommerfeld 	if ((typ == NULL) || (typ->ty_type == NULL) ||
643ac8e2453Ssommerfeld 	    (typ->ty_type[0] == 0))
644ac8e2453Ssommerfeld 		return;
645ac8e2453Ssommerfeld 
64698eb8895Sroy 	if (setupterm(typ->ty_type, 0, &err) == ERR)
647ac8e2453Ssommerfeld 		return;
648ac8e2453Ssommerfeld 
64998eb8895Sroy 	if (clear_screen)
65098eb8895Sroy 		putpad(clear_screen);
651ac8e2453Ssommerfeld 
65298eb8895Sroy 	del_curterm(cur_term);
65398eb8895Sroy 	cur_term = NULL;
654ac8e2453Ssommerfeld }
655