main.c revision 19697
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.10 1996/05/07 16:42:26 ache 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		if (IM && *IM)
296			putf(IM);
297		if (setjmp(timeout)) {
298			cfsetispeed(&tmode, B0);
299			cfsetospeed(&tmode, B0);
300			(void)tcsetattr(0, TCSANOW, &tmode);
301			exit(1);
302		}
303		if (TO) {
304			signal(SIGALRM, dingdong);
305			alarm(TO);
306		}
307		if ((rval = getname()) == 2) {
308			execle(PP, "ppplogin", ttyn, (char *) 0, env);
309			syslog(LOG_ERR, "%s: %m", PP);
310			exit(1);
311		} else if (rval) {
312			register int i;
313
314			oflush();
315			alarm(0);
316			signal(SIGALRM, SIG_DFL);
317			if (name[0] == '-') {
318				puts("user names may not start with '-'.");
319				continue;
320			}
321			if (!(upper || lower || digit))
322				continue;
323			setflags(2);
324			if (crmod) {
325				tmode.c_iflag |= ICRNL;
326				tmode.c_oflag |= ONLCR;
327			}
328#if REALLY_OLD_TTYS
329			if (upper || UC)
330				tmode.sg_flags |= LCASE;
331			if (lower || LC)
332				tmode.sg_flags &= ~LCASE;
333#endif
334			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
335				syslog(LOG_ERR, "%s: %m", ttyn);
336				exit(1);
337			}
338			signal(SIGINT, SIG_DFL);
339			for (i = 0; environ[i] != (char *)0; i++)
340				env[i] = environ[i];
341			makeenv(&env[i]);
342
343			limit.rlim_max = RLIM_INFINITY;
344			limit.rlim_cur = RLIM_INFINITY;
345			(void)setrlimit(RLIMIT_CPU, &limit);
346			execle(LO, "login", "-p", name, (char *) 0, env);
347			syslog(LOG_ERR, "%s: %m", LO);
348			exit(1);
349		}
350		alarm(0);
351		signal(SIGALRM, SIG_DFL);
352		signal(SIGINT, SIG_IGN);
353		if (NX && *NX)
354			tname = NX;
355	}
356}
357
358static int
359getname()
360{
361	register int c;
362	register char *np;
363	unsigned char cs;
364	int ppp_state;
365	int ppp_connection = 0;
366
367	/*
368	 * Interrupt may happen if we use CBREAK mode
369	 */
370	if (setjmp(intrupt)) {
371		signal(SIGINT, SIG_IGN);
372		return (0);
373	}
374	signal(SIGINT, interrupt);
375	setflags(1);
376	prompt();
377	oflush();
378	if (PF > 0) {
379		sleep(PF);
380		PF = 0;
381	}
382	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
383		syslog(LOG_ERR, "%s: %m", ttyn);
384		exit(1);
385	}
386	crmod = digit = lower = upper = 0;
387	np = name;
388	for (;;) {
389		oflush();
390		if (read(STDIN_FILENO, &cs, 1) <= 0)
391			exit(0);
392		if ((c = cs&0177) == 0)
393			return (0);
394
395		/* PPP detection state machine..
396		   Look for sequences:
397		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
398		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
399		   See RFC1662.
400		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
401		   and Erik 'PPP' Olson, <eriko@wrq.com>
402		 */
403
404		if (PP && (cs == PPP_FRAME)) {
405			ppp_state = 1;
406		} else if (ppp_state == 1 && cs == PPP_STATION) {
407			ppp_state = 2;
408		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
409			ppp_state = 3;
410		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
411			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
412			ppp_state = 4;
413		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
414			ppp_state = 5;
415		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
416			ppp_connection = 1;
417			break;
418		} else {
419			ppp_state = 0;
420		}
421
422		if (c == EOT || c == CTRL('d'))
423			exit(1);
424		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
425			putf("\r\n");
426			break;
427		}
428		if (islower(c))
429			lower = 1;
430		else if (isupper(c))
431			upper = 1;
432		else if (c == ERASE || c == '\b' || c == 0177) {
433			if (np > name) {
434				np--;
435				if (cfgetospeed(&tmode) >= 1200)
436					puts("\b \b");
437				else
438					putchr(cs);
439			}
440			continue;
441		} else if (c == KILL || c == CTRL('u')) {
442			putchr('\r');
443			if (cfgetospeed(&tmode) < 1200)
444				putchr('\n');
445			/* this is the way they do it down under ... */
446			else if (np > name)
447				puts("                                     \r");
448			prompt();
449			np = name;
450			continue;
451		} else if (isdigit(c))
452			digit++;
453		if (IG && (c <= ' ' || c > 0176))
454			continue;
455		*np++ = c;
456		putchr(cs);
457	}
458	signal(SIGINT, SIG_IGN);
459	*np = 0;
460	if (c == '\r')
461		crmod = 1;
462	if ((upper && !lower && !LC) || UC)
463		for (np = name; *np; np++)
464			if (isupper(*np))
465				*np = tolower(*np);
466	return (1 + ppp_connection);
467}
468
469static void
470putpad(s)
471	register const char *s;
472{
473	register pad = 0;
474	speed_t ospeed = cfgetospeed(&tmode);
475
476	if (isdigit(*s)) {
477		while (isdigit(*s)) {
478			pad *= 10;
479			pad += *s++ - '0';
480		}
481		pad *= 10;
482		if (*s == '.' && isdigit(s[1])) {
483			pad += s[1] - '0';
484			s += 2;
485		}
486	}
487
488	puts(s);
489	/*
490	 * If no delay needed, or output speed is
491	 * not comprehensible, then don't try to delay.
492	 */
493	if (pad == 0 || ospeed <= 0)
494		return;
495
496	/*
497	 * Round up by a half a character frame, and then do the delay.
498	 * Too bad there are no user program accessible programmed delays.
499	 * Transmitting pad characters slows many terminals down and also
500	 * loads the system.
501	 */
502	pad = (pad * ospeed + 50000) / 100000;
503	while (pad--)
504		putchr(*PC);
505}
506
507static void
508puts(s)
509	register const char *s;
510{
511	while (*s)
512		putchr(*s++);
513}
514
515char	outbuf[OBUFSIZ];
516int	obufcnt = 0;
517
518static void
519putchr(cc)
520	int cc;
521{
522	char c;
523
524	c = cc;
525	if (!NP) {
526		c |= partab[c&0177] & 0200;
527		if (OP)
528			c ^= 0200;
529	}
530	if (!UB) {
531		outbuf[obufcnt++] = c;
532		if (obufcnt >= OBUFSIZ)
533			oflush();
534	} else
535		write(STDOUT_FILENO, &c, 1);
536}
537
538static void
539oflush()
540{
541	if (obufcnt)
542		write(STDOUT_FILENO, outbuf, obufcnt);
543	obufcnt = 0;
544}
545
546static void
547prompt()
548{
549
550	putf(LM);
551	if (CO)
552		putchr('\n');
553}
554
555static void
556putf(cp)
557	register const char *cp;
558{
559	extern char editedhost[];
560	time_t t;
561	char *slash, db[100];
562
563	while (*cp) {
564		if (*cp != '%') {
565			putchr(*cp++);
566			continue;
567		}
568		switch (*++cp) {
569
570		case 't':
571			slash = strrchr(ttyn, '/');
572			if (slash == (char *) 0)
573				puts(ttyn);
574			else
575				puts(&slash[1]);
576			break;
577
578		case 'h':
579			puts(editedhost);
580			break;
581
582		case 'd': {
583			t = (time_t)0;
584			(void)time(&t);
585			if (Lo)
586				(void)setlocale(LC_TIME, Lo);
587			(void)strftime(db, sizeof(db), "%+", localtime(&t));
588			puts(db);
589			break;
590
591		case 's':
592			puts(kerninfo.sysname);
593			break;
594
595		case 'm':
596			puts(kerninfo.machine);
597			break;
598
599		case 'r':
600			puts(kerninfo.release);
601			break;
602
603		case 'v':
604			puts(kerninfo.version);
605			break;
606		}
607
608		case '%':
609			putchr('%');
610			break;
611		}
612		cp++;
613	}
614}
615