main.c revision 21120
1/*-
2 * Copyright (c) 1980, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41/*static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";*/
42static char rcsid[] = "$Id: main.c,v 1.11 1996/11/13 01:06:40 pst Exp $";
43#endif /* not lint */
44
45#include <sys/param.h>
46#include <sys/stat.h>
47#include <sys/ioctl.h>
48#include <sys/resource.h>
49#include <sys/ttydefaults.h>
50#include <sys/utsname.h>
51#include <errno.h>
52#include <signal.h>
53#include <fcntl.h>
54#include <time.h>
55#include <ctype.h>
56#include <fcntl.h>
57#include <libutil.h>
58#include <locale.h>
59#include <setjmp.h>
60#include <signal.h>
61#include <stdlib.h>
62#include <string.h>
63#include <syslog.h>
64#include <termios.h>
65#include <time.h>
66#include <unistd.h>
67
68#include "gettytab.h"
69#include "pathnames.h"
70#include "extern.h"
71
72/*
73 * Set the amount of running time that getty should accumulate
74 * before deciding that something is wrong and exit.
75 */
76#define GETTY_TIMEOUT	60 /* seconds */
77
78#undef CTRL
79#define CTRL(x)  (x&037)
80
81/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
82
83#define PPP_FRAME           0x7e  /* PPP Framing character */
84#define PPP_STATION         0xff  /* "All Station" character */
85#define PPP_ESCAPE          0x7d  /* Escape Character */
86#define PPP_CONTROL         0x03  /* PPP Control Field */
87#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
88#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
89#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
90
91struct termios tmode, omode;
92
93int crmod, digit, lower, upper;
94
95char	hostname[MAXHOSTNAMELEN];
96struct utsname kerninfo;
97char	name[16];
98char	dev[] = _PATH_DEV;
99char	ttyn[32];
100
101#define	OBUFSIZ		128
102#define	TABBUFSIZ	512
103
104char	defent[TABBUFSIZ];
105char	tabent[TABBUFSIZ];
106
107char	*env[128];
108
109char partab[] = {
110	0001,0201,0201,0001,0201,0001,0001,0201,
111	0202,0004,0003,0205,0005,0206,0201,0001,
112	0201,0001,0001,0201,0001,0201,0201,0001,
113	0001,0201,0201,0001,0201,0001,0001,0201,
114	0200,0000,0000,0200,0000,0200,0200,0000,
115	0000,0200,0200,0000,0200,0000,0000,0200,
116	0000,0200,0200,0000,0200,0000,0000,0200,
117	0200,0000,0000,0200,0000,0200,0200,0000,
118	0200,0000,0000,0200,0000,0200,0200,0000,
119	0000,0200,0200,0000,0200,0000,0000,0200,
120	0000,0200,0200,0000,0200,0000,0000,0200,
121	0200,0000,0000,0200,0000,0200,0200,0000,
122	0000,0200,0200,0000,0200,0000,0000,0200,
123	0200,0000,0000,0200,0000,0200,0200,0000,
124	0200,0000,0000,0200,0000,0200,0200,0000,
125	0000,0200,0200,0000,0200,0000,0000,0201
126};
127
128#define	ERASE	tmode.c_cc[VERASE]
129#define	KILL	tmode.c_cc[VKILL]
130#define	EOT	tmode.c_cc[VEOF]
131
132jmp_buf timeout;
133
134static void	dingdong __P((int));
135static int	getname __P((void));
136static void	interrupt __P((int));
137static void	oflush __P((void));
138static void	prompt __P((void));
139static void	putchr __P((int));
140static void	putf __P((const char *));
141static void	putpad __P((const char *));
142static void	puts __P((const char *));
143static void	timeoverrun __P((int));
144
145int		main __P((int, char **));
146
147static void
148dingdong(signo)
149	int signo;
150{
151	alarm(0);
152	longjmp(timeout, 1);
153}
154
155jmp_buf	intrupt;
156
157static void
158interrupt(signo)
159	int signo;
160{
161	longjmp(intrupt, 1);
162}
163
164/*
165 * Action to take when getty is running too long.
166 */
167static void
168timeoverrun(signo)
169	int signo;
170{
171
172	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
173	exit(1);
174}
175
176int
177main(argc, argv)
178	int argc;
179	char **argv;
180{
181	extern	char **environ;
182	const char *tname;
183	int repcnt = 0, failopenlogged = 0;
184	struct rlimit limit;
185	int rval;
186
187	signal(SIGINT, SIG_IGN);
188	signal(SIGQUIT, SIG_IGN);
189
190	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
191	gethostname(hostname, sizeof(hostname));
192	if (hostname[0] == '\0')
193		strcpy(hostname, "Amnesiac");
194
195	/*
196	 * Limit running time to deal with broken or dead lines.
197	 */
198	(void)signal(SIGXCPU, timeoverrun);
199	limit.rlim_max = RLIM_INFINITY;
200	limit.rlim_cur = GETTY_TIMEOUT;
201	(void)setrlimit(RLIMIT_CPU, &limit);
202
203	/*
204	 * The following is a work around for vhangup interactions
205	 * which cause great problems getting window systems started.
206	 * If the tty line is "-", we do the old style getty presuming
207	 * that the file descriptors are already set up for us.
208	 * J. Gettys - MIT Project Athena.
209	 */
210	if (argc <= 2 || strcmp(argv[2], "-") == 0)
211	    strcpy(ttyn, ttyname(0));
212	else {
213	    int i;
214
215	    strcpy(ttyn, dev);
216	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
217	    if (strcmp(argv[0], "+") != 0) {
218		chown(ttyn, 0, 0);
219		chmod(ttyn, 0600);
220		revoke(ttyn);
221		while ((i = open(ttyn, O_RDWR)) == -1) {
222			if ((repcnt % 10 == 0) &&
223			    (errno != ENXIO || !failopenlogged)) {
224				syslog(LOG_ERR, "%s: %m", ttyn);
225				closelog();
226				failopenlogged = 1;
227			}
228			repcnt++;
229			sleep(60);
230		}
231		login_tty(i);
232	    }
233	}
234
235	/* Start with default tty settings */
236	if (tcgetattr(0, &tmode) < 0) {
237		syslog(LOG_ERR, "%s: %m", ttyn);
238		exit(1);
239	}
240	/*
241	 * Don't rely on the driver too much, and initialize crucial
242	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
243	 * the c_cc[] settings however, the console drivers might wish
244	 * to leave their idea of the preferred VERASE key value
245	 * there.
246	 */
247	tmode.c_iflag = TTYDEF_IFLAG;
248	tmode.c_oflag = TTYDEF_OFLAG;
249	tmode.c_lflag = TTYDEF_LFLAG;
250	tmode.c_cflag = TTYDEF_CFLAG;
251	omode = tmode;
252
253	gettable("default", defent);
254	gendefaults();
255	tname = "default";
256	if (argc > 1)
257		tname = argv[1];
258	for (;;) {
259		int off = 0;
260
261		gettable(tname, tabent);
262		if (OPset || EPset || APset)
263			APset++, OPset++, EPset++;
264		setdefaults();
265		off = 0;
266		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
267		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
268		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
269
270		if (IS)
271			cfsetispeed(&tmode, speed(IS));
272		else if (SP)
273			cfsetispeed(&tmode, speed(SP));
274		if (OS)
275			cfsetospeed(&tmode, speed(OS));
276		else if (SP)
277			cfsetospeed(&tmode, speed(SP));
278		setflags(0);
279		setchars();
280		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
281			syslog(LOG_ERR, "%s: %m", ttyn);
282			exit(1);
283		}
284		if (AB) {
285			tname = autobaud();
286			continue;
287		}
288		if (PS) {
289			tname = portselector();
290			continue;
291		}
292		if (CL && *CL)
293			putpad(CL);
294		edithost(HE);
295
296		/* if a delay was specified then sleep for that
297		   number of seconds before writing the initial prompt */
298		if(DE)
299		    sleep(DE);
300
301		if (IM && *IM)
302			putf(IM);
303		if (setjmp(timeout)) {
304			cfsetispeed(&tmode, B0);
305			cfsetospeed(&tmode, B0);
306			(void)tcsetattr(0, TCSANOW, &tmode);
307			exit(1);
308		}
309		if (TO) {
310			signal(SIGALRM, dingdong);
311			alarm(TO);
312		}
313		if ((rval = getname()) == 2) {
314			execle(PP, "ppplogin", ttyn, (char *) 0, env);
315			syslog(LOG_ERR, "%s: %m", PP);
316			exit(1);
317		} else if (rval) {
318			register int i;
319
320			oflush();
321			alarm(0);
322			signal(SIGALRM, SIG_DFL);
323			if (name[0] == '-') {
324				puts("user names may not start with '-'.");
325				continue;
326			}
327			if (!(upper || lower || digit))
328				continue;
329			setflags(2);
330			if (crmod) {
331				tmode.c_iflag |= ICRNL;
332				tmode.c_oflag |= ONLCR;
333			}
334#if REALLY_OLD_TTYS
335			if (upper || UC)
336				tmode.sg_flags |= LCASE;
337			if (lower || LC)
338				tmode.sg_flags &= ~LCASE;
339#endif
340			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
341				syslog(LOG_ERR, "%s: %m", ttyn);
342				exit(1);
343			}
344			signal(SIGINT, SIG_DFL);
345			for (i = 0; environ[i] != (char *)0; i++)
346				env[i] = environ[i];
347			makeenv(&env[i]);
348
349			limit.rlim_max = RLIM_INFINITY;
350			limit.rlim_cur = RLIM_INFINITY;
351			(void)setrlimit(RLIMIT_CPU, &limit);
352			execle(LO, "login", "-p", name, (char *) 0, env);
353			syslog(LOG_ERR, "%s: %m", LO);
354			exit(1);
355		}
356		alarm(0);
357		signal(SIGALRM, SIG_DFL);
358		signal(SIGINT, SIG_IGN);
359		if (NX && *NX)
360			tname = NX;
361	}
362}
363
364static int
365getname()
366{
367	register int c;
368	register char *np;
369	unsigned char cs;
370	int ppp_state;
371	int ppp_connection = 0;
372
373	/*
374	 * Interrupt may happen if we use CBREAK mode
375	 */
376	if (setjmp(intrupt)) {
377		signal(SIGINT, SIG_IGN);
378		return (0);
379	}
380	signal(SIGINT, interrupt);
381	setflags(1);
382	prompt();
383	oflush();
384	if (PF > 0) {
385		sleep(PF);
386		PF = 0;
387	}
388	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
389		syslog(LOG_ERR, "%s: %m", ttyn);
390		exit(1);
391	}
392	crmod = digit = lower = upper = 0;
393	np = name;
394	for (;;) {
395		oflush();
396		if (read(STDIN_FILENO, &cs, 1) <= 0)
397			exit(0);
398		if ((c = cs&0177) == 0)
399			return (0);
400
401		/* PPP detection state machine..
402		   Look for sequences:
403		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
404		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
405		   See RFC1662.
406		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
407		   and Erik 'PPP' Olson, <eriko@wrq.com>
408		 */
409
410		if (PP && (cs == PPP_FRAME)) {
411			ppp_state = 1;
412		} else if (ppp_state == 1 && cs == PPP_STATION) {
413			ppp_state = 2;
414		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
415			ppp_state = 3;
416		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
417			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
418			ppp_state = 4;
419		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
420			ppp_state = 5;
421		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
422			ppp_connection = 1;
423			break;
424		} else {
425			ppp_state = 0;
426		}
427
428		if (c == EOT || c == CTRL('d'))
429			exit(1);
430		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
431			putf("\r\n");
432			break;
433		}
434		if (islower(c))
435			lower = 1;
436		else if (isupper(c))
437			upper = 1;
438		else if (c == ERASE || c == '\b' || c == 0177) {
439			if (np > name) {
440				np--;
441				if (cfgetospeed(&tmode) >= 1200)
442					puts("\b \b");
443				else
444					putchr(cs);
445			}
446			continue;
447		} else if (c == KILL || c == CTRL('u')) {
448			putchr('\r');
449			if (cfgetospeed(&tmode) < 1200)
450				putchr('\n');
451			/* this is the way they do it down under ... */
452			else if (np > name)
453				puts("                                     \r");
454			prompt();
455			np = name;
456			continue;
457		} else if (isdigit(c))
458			digit++;
459		if (IG && (c <= ' ' || c > 0176))
460			continue;
461		*np++ = c;
462		putchr(cs);
463	}
464	signal(SIGINT, SIG_IGN);
465	*np = 0;
466	if (c == '\r')
467		crmod = 1;
468	if ((upper && !lower && !LC) || UC)
469		for (np = name; *np; np++)
470			if (isupper(*np))
471				*np = tolower(*np);
472	return (1 + ppp_connection);
473}
474
475static void
476putpad(s)
477	register const char *s;
478{
479	register pad = 0;
480	speed_t ospeed = cfgetospeed(&tmode);
481
482	if (isdigit(*s)) {
483		while (isdigit(*s)) {
484			pad *= 10;
485			pad += *s++ - '0';
486		}
487		pad *= 10;
488		if (*s == '.' && isdigit(s[1])) {
489			pad += s[1] - '0';
490			s += 2;
491		}
492	}
493
494	puts(s);
495	/*
496	 * If no delay needed, or output speed is
497	 * not comprehensible, then don't try to delay.
498	 */
499	if (pad == 0 || ospeed <= 0)
500		return;
501
502	/*
503	 * Round up by a half a character frame, and then do the delay.
504	 * Too bad there are no user program accessible programmed delays.
505	 * Transmitting pad characters slows many terminals down and also
506	 * loads the system.
507	 */
508	pad = (pad * ospeed + 50000) / 100000;
509	while (pad--)
510		putchr(*PC);
511}
512
513static void
514puts(s)
515	register const char *s;
516{
517	while (*s)
518		putchr(*s++);
519}
520
521char	outbuf[OBUFSIZ];
522int	obufcnt = 0;
523
524static void
525putchr(cc)
526	int cc;
527{
528	char c;
529
530	c = cc;
531	if (!NP) {
532		c |= partab[c&0177] & 0200;
533		if (OP)
534			c ^= 0200;
535	}
536	if (!UB) {
537		outbuf[obufcnt++] = c;
538		if (obufcnt >= OBUFSIZ)
539			oflush();
540	} else
541		write(STDOUT_FILENO, &c, 1);
542}
543
544static void
545oflush()
546{
547	if (obufcnt)
548		write(STDOUT_FILENO, outbuf, obufcnt);
549	obufcnt = 0;
550}
551
552static void
553prompt()
554{
555
556	putf(LM);
557	if (CO)
558		putchr('\n');
559}
560
561static void
562putf(cp)
563	register const char *cp;
564{
565	extern char editedhost[];
566	time_t t;
567	char *slash, db[100];
568
569	while (*cp) {
570		if (*cp != '%') {
571			putchr(*cp++);
572			continue;
573		}
574		switch (*++cp) {
575
576		case 't':
577			slash = strrchr(ttyn, '/');
578			if (slash == (char *) 0)
579				puts(ttyn);
580			else
581				puts(&slash[1]);
582			break;
583
584		case 'h':
585			puts(editedhost);
586			break;
587
588		case 'd': {
589			t = (time_t)0;
590			(void)time(&t);
591			if (Lo)
592				(void)setlocale(LC_TIME, Lo);
593			(void)strftime(db, sizeof(db), "%+", localtime(&t));
594			puts(db);
595			break;
596
597		case 's':
598			puts(kerninfo.sysname);
599			break;
600
601		case 'm':
602			puts(kerninfo.machine);
603			break;
604
605		case 'r':
606			puts(kerninfo.release);
607			break;
608
609		case 'v':
610			puts(kerninfo.version);
611			break;
612		}
613
614		case '%':
615			putchr('%');
616			break;
617		}
618		cp++;
619	}
620}
621