main.c revision 22208
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[] = "$FreeBSD: head/libexec/getty/main.c 22208 1997-02-02 14:24:57Z davidn $";
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];
96char	name[16];
97char	dev[] = _PATH_DEV;
98char	ttyn[32];
99
100#define	OBUFSIZ		128
101#define	TABBUFSIZ	512
102
103char	defent[TABBUFSIZ];
104char	tabent[TABBUFSIZ];
105
106char	*env[128];
107
108char partab[] = {
109	0001,0201,0201,0001,0201,0001,0001,0201,
110	0202,0004,0003,0205,0005,0206,0201,0001,
111	0201,0001,0001,0201,0001,0201,0201,0001,
112	0001,0201,0201,0001,0201,0001,0001,0201,
113	0200,0000,0000,0200,0000,0200,0200,0000,
114	0000,0200,0200,0000,0200,0000,0000,0200,
115	0000,0200,0200,0000,0200,0000,0000,0200,
116	0200,0000,0000,0200,0000,0200,0200,0000,
117	0200,0000,0000,0200,0000,0200,0200,0000,
118	0000,0200,0200,0000,0200,0000,0000,0200,
119	0000,0200,0200,0000,0200,0000,0000,0200,
120	0200,0000,0000,0200,0000,0200,0200,0000,
121	0000,0200,0200,0000,0200,0000,0000,0200,
122	0200,0000,0000,0200,0000,0200,0200,0000,
123	0200,0000,0000,0200,0000,0200,0200,0000,
124	0000,0200,0200,0000,0200,0000,0000,0201
125};
126
127#define	ERASE	tmode.c_cc[VERASE]
128#define	KILL	tmode.c_cc[VKILL]
129#define	EOT	tmode.c_cc[VEOF]
130
131static void	dingdong __P((int));
132static int	getname __P((void));
133static void	interrupt __P((int));
134static void	oflush __P((void));
135static void	prompt __P((void));
136static void	putchr __P((int));
137static void	putf __P((const char *));
138static void	putpad __P((const char *));
139static void	puts __P((const char *));
140static void	timeoverrun __P((int));
141static char	*getline __P((int));
142static void	setttymode __P((const char *, int));
143static void	setdefttymode __P((const char *));
144static int	opentty __P((const char *, int));
145
146int		main __P((int, char **));
147
148jmp_buf timeout;
149
150static void
151dingdong(signo)
152	int signo;
153{
154	alarm(0);
155	longjmp(timeout, 1);
156}
157
158jmp_buf	intrupt;
159
160static void
161interrupt(signo)
162	int signo;
163{
164	longjmp(intrupt, 1);
165}
166
167/*
168 * Action to take when getty is running too long.
169 */
170static void
171timeoverrun(signo)
172	int signo;
173{
174
175	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
176	exit(1);
177}
178
179int
180main(argc, argv)
181	int argc;
182	char **argv;
183{
184	extern	char **environ;
185	const char *tname;
186	int repcnt = 0, failopenlogged = 0, first_time = 1;
187	struct rlimit limit;
188	int rval;
189
190	signal(SIGINT, SIG_IGN);
191	signal(SIGQUIT, SIG_IGN);
192
193	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
194	gethostname(hostname, sizeof(hostname));
195	if (hostname[0] == '\0')
196		strcpy(hostname, "Amnesiac");
197
198	/*
199	 * Limit running time to deal with broken or dead lines.
200	 */
201	(void)signal(SIGXCPU, timeoverrun);
202	limit.rlim_max = RLIM_INFINITY;
203	limit.rlim_cur = GETTY_TIMEOUT;
204	(void)setrlimit(RLIMIT_CPU, &limit);
205
206	gettable("default", defent);
207	gendefaults();
208	tname = "default";
209	if (argc > 1)
210		tname = argv[1];
211
212	/*
213	 * The following is a work around for vhangup interactions
214	 * which cause great problems getting window systems started.
215	 * If the tty line is "-", we do the old style getty presuming
216	 * that the file descriptors are already set up for us.
217	 * J. Gettys - MIT Project Athena.
218	 */
219	if (argc <= 2 || strcmp(argv[2], "-") == 0)
220	    strcpy(ttyn, ttyname(STDIN_FILENO));
221	else {
222	    int i;
223
224	    strcpy(ttyn, dev);
225	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
226	    if (strcmp(argv[0], "+") != 0) {
227		chown(ttyn, 0, 0);
228		chmod(ttyn, 0600);
229		revoke(ttyn);
230
231		gettable(tname, tabent);
232
233		/* Init modem sequence has been specified
234		 */
235		if (IC) {
236			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
237				exit(1);
238			setdefttymode(tname);
239			if (getty_chat(IC, CT, DC) > 0) {
240				syslog(LOG_ERR, "modem init problem on %s", ttyn);
241				exit(1);
242			}
243		}
244
245		if (AC) {
246			int i, rfds;
247			struct timeval timeout;
248
249			if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
250				exit(1);
251        		setdefttymode(tname);
252        		rfds = 1 << 0;	/* FD_SET */
253        		timeout.tv_sec = RT;
254        		timeout.tv_usec = 0;
255        		i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
256        			       (fd_set*)NULL, RT ? &timeout : NULL);
257        		if (i < 0) {
258				syslog(LOG_ERR, "select %s: %m", ttyn);
259			} else if (i == 0) {
260				syslog(LOG_NOTICE, "recycle tty %s", ttyn);
261				exit(0);  /* recycle for init */
262			}
263			i = getty_chat(AC, CT, DC);
264			if (i > 0) {
265				syslog(LOG_ERR, "modem answer problem on %s", ttyn);
266				exit(1);
267			}
268		} else { /* blocking open */
269			if (!opentty(ttyn, O_RDWR))
270				exit(1);
271		}
272	    }
273	}
274
275	/* Start with default tty settings */
276	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
277		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
278		exit(1);
279	}
280	/*
281	 * Don't rely on the driver too much, and initialize crucial
282	 * things according to <sys/ttydefaults.h>.  Avoid clobbering
283	 * the c_cc[] settings however, the console drivers might wish
284	 * to leave their idea of the preferred VERASE key value
285	 * there.
286	 */
287	tmode.c_iflag = TTYDEF_IFLAG;
288	tmode.c_oflag = TTYDEF_OFLAG;
289	tmode.c_lflag = TTYDEF_LFLAG;
290	tmode.c_cflag = TTYDEF_CFLAG;
291	omode = tmode;
292
293	for (;;) {
294
295		setttymode(tname, 0);
296		if (AB) {
297			tname = autobaud();
298			continue;
299		}
300		if (PS) {
301			tname = portselector();
302			continue;
303		}
304		if (CL && *CL)
305			putpad(CL);
306		edithost(HE);
307
308		/* if a delay was specified then sleep for that
309		   number of seconds before writing the initial prompt */
310		if(DE) {
311		    sleep(DE);
312		    /* remove any noise */
313		    (void)tcflush(STDIN_FILENO, TCIOFLUSH);
314		}
315
316		/* if this is the first time through this, and an
317		   issue file has been given, then send it */
318		if (first_time && IF) {
319			int fd;
320
321			if ((fd = open(IF, O_RDONLY)) != -1) {
322				char * cp;
323
324				while ((cp = getline(fd)) != NULL) {
325					  putf(cp);
326				}
327				close(fd);
328			}
329			first_time = 0;
330		}
331
332		if (IM && *IM)
333			putf(IM);
334		if (setjmp(timeout)) {
335			cfsetispeed(&tmode, B0);
336			cfsetospeed(&tmode, B0);
337			(void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
338			exit(1);
339		}
340		if (TO) {
341			signal(SIGALRM, dingdong);
342			alarm(TO);
343		}
344		if ((rval = getname()) == 2) {
345			execle(PP, "ppplogin", ttyn, (char *) 0, env);
346			syslog(LOG_ERR, "%s: %m", PP);
347			exit(1);
348		} else if (rval) {
349			register int i;
350
351			oflush();
352			alarm(0);
353			signal(SIGALRM, SIG_DFL);
354			if (name[0] == '-') {
355				puts("user names may not start with '-'.");
356				continue;
357			}
358			if (!(upper || lower || digit))
359				continue;
360			setflags(2);
361			if (crmod) {
362				tmode.c_iflag |= ICRNL;
363				tmode.c_oflag |= ONLCR;
364			}
365#if REALLY_OLD_TTYS
366			if (upper || UC)
367				tmode.sg_flags |= LCASE;
368			if (lower || LC)
369				tmode.sg_flags &= ~LCASE;
370#endif
371			if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
372				syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
373				exit(1);
374			}
375			signal(SIGINT, SIG_DFL);
376			for (i = 0; environ[i] != (char *)0; i++)
377				env[i] = environ[i];
378			makeenv(&env[i]);
379
380			limit.rlim_max = RLIM_INFINITY;
381			limit.rlim_cur = RLIM_INFINITY;
382			(void)setrlimit(RLIMIT_CPU, &limit);
383			execle(LO, "login", "-p", name, (char *) 0, env);
384			syslog(LOG_ERR, "%s: %m", LO);
385			exit(1);
386		}
387		alarm(0);
388		signal(SIGALRM, SIG_DFL);
389		signal(SIGINT, SIG_IGN);
390		if (NX && *NX)
391			tname = NX;
392	}
393}
394
395static int
396opentty(const char *ttyn, int flags)
397{
398	int i, j = 0;
399	int failopenlogged = 0;
400
401	while (j < 10 && (i = open(ttyn, flags)) == -1)
402	{
403		if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) {
404			syslog(LOG_ERR, "open %s: %m", ttyn);
405			failopenlogged = 1;
406		}
407		j++;
408		sleep(60);
409	}
410	if (i == -1) {
411		syslog(LOG_ERR, "open %s: %m", ttyn);
412		return 0;
413	}
414	else {
415		login_tty(i);
416		return 1;
417	}
418}
419
420static void
421setdefttymode(tname)
422	const char * tname;
423{
424	if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
425		syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
426		exit(1);
427	}
428	tmode.c_iflag = TTYDEF_IFLAG;
429        tmode.c_oflag = TTYDEF_OFLAG;
430        tmode.c_lflag = TTYDEF_LFLAG;
431        tmode.c_cflag = TTYDEF_CFLAG;
432        omode = tmode;
433	setttymode(tname, 1);
434}
435
436static void
437setttymode(tname, raw)
438	const char * tname;
439	int raw;
440{
441	int off = 0;
442
443	gettable(tname, tabent);
444	if (OPset || EPset || APset)
445		APset++, OPset++, EPset++;
446	setdefaults();
447	(void)tcflush(STDIN_FILENO, TCIOFLUSH);	/* clear out the crap */
448	ioctl(STDIN_FILENO, FIONBIO, &off);	/* turn off non-blocking mode */
449	ioctl(STDIN_FILENO, FIOASYNC, &off);	/* ditto for async mode */
450
451	if (IS)
452		cfsetispeed(&tmode, speed(IS));
453	else if (SP)
454		cfsetispeed(&tmode, speed(SP));
455	if (OS)
456		cfsetospeed(&tmode, speed(OS));
457	else if (SP)
458		cfsetospeed(&tmode, speed(SP));
459	setflags(0);
460	setchars();
461	if (raw)
462		cfmakeraw(&tmode);
463	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
464		syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
465		exit(1);
466	}
467}
468
469
470static int
471getname()
472{
473	register int c;
474	register char *np;
475	unsigned char cs;
476	int ppp_state = 0;
477	int ppp_connection = 0;
478
479	/*
480	 * Interrupt may happen if we use CBREAK mode
481	 */
482	if (setjmp(intrupt)) {
483		signal(SIGINT, SIG_IGN);
484		return (0);
485	}
486	signal(SIGINT, interrupt);
487	setflags(1);
488	prompt();
489	oflush();
490	if (PF > 0) {
491		sleep(PF);
492		PF = 0;
493	}
494	if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
495		syslog(LOG_ERR, "%s: %m", ttyn);
496		exit(1);
497	}
498	crmod = digit = lower = upper = 0;
499	np = name;
500	for (;;) {
501		oflush();
502		if (read(STDIN_FILENO, &cs, 1) <= 0)
503			exit(0);
504		if ((c = cs&0177) == 0)
505			return (0);
506
507		/* PPP detection state machine..
508		   Look for sequences:
509		   PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
510		   PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
511		   See RFC1662.
512		   Derived from code from Michael Hancock, <michaelh@cet.co.jp>
513		   and Erik 'PPP' Olson, <eriko@wrq.com>
514		 */
515
516		if (PP && (cs == PPP_FRAME)) {
517			ppp_state = 1;
518		} else if (ppp_state == 1 && cs == PPP_STATION) {
519			ppp_state = 2;
520		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
521			ppp_state = 3;
522		} else if ((ppp_state == 2 && cs == PPP_CONTROL)
523			|| (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
524			ppp_state = 4;
525		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
526			ppp_state = 5;
527		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
528			ppp_connection = 1;
529			break;
530		} else {
531			ppp_state = 0;
532		}
533
534		if (c == EOT || c == CTRL('d'))
535			exit(1);
536		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
537			putf("\r\n");
538			break;
539		}
540		if (islower(c))
541			lower = 1;
542		else if (isupper(c))
543			upper = 1;
544		else if (c == ERASE || c == '\b' || c == 0177) {
545			if (np > name) {
546				np--;
547				if (cfgetospeed(&tmode) >= 1200)
548					puts("\b \b");
549				else
550					putchr(cs);
551			}
552			continue;
553		} else if (c == KILL || c == CTRL('u')) {
554			putchr('\r');
555			if (cfgetospeed(&tmode) < 1200)
556				putchr('\n');
557			/* this is the way they do it down under ... */
558			else if (np > name)
559				puts("                                     \r");
560			prompt();
561			np = name;
562			continue;
563		} else if (isdigit(c))
564			digit++;
565		if (IG && (c <= ' ' || c > 0176))
566			continue;
567		*np++ = c;
568		putchr(cs);
569	}
570	signal(SIGINT, SIG_IGN);
571	*np = 0;
572	if (c == '\r')
573		crmod = 1;
574	if ((upper && !lower && !LC) || UC)
575		for (np = name; *np; np++)
576			if (isupper(*np))
577				*np = tolower(*np);
578	return (1 + ppp_connection);
579}
580
581static void
582putpad(s)
583	register const char *s;
584{
585	register pad = 0;
586	speed_t ospeed = cfgetospeed(&tmode);
587
588	if (isdigit(*s)) {
589		while (isdigit(*s)) {
590			pad *= 10;
591			pad += *s++ - '0';
592		}
593		pad *= 10;
594		if (*s == '.' && isdigit(s[1])) {
595			pad += s[1] - '0';
596			s += 2;
597		}
598	}
599
600	puts(s);
601	/*
602	 * If no delay needed, or output speed is
603	 * not comprehensible, then don't try to delay.
604	 */
605	if (pad == 0 || ospeed <= 0)
606		return;
607
608	/*
609	 * Round up by a half a character frame, and then do the delay.
610	 * Too bad there are no user program accessible programmed delays.
611	 * Transmitting pad characters slows many terminals down and also
612	 * loads the system.
613	 */
614	pad = (pad * ospeed + 50000) / 100000;
615	while (pad--)
616		putchr(*PC);
617}
618
619static void
620puts(s)
621	register const char *s;
622{
623	while (*s)
624		putchr(*s++);
625}
626
627char	outbuf[OBUFSIZ];
628int	obufcnt = 0;
629
630static void
631putchr(cc)
632	int cc;
633{
634	char c;
635
636	c = cc;
637	if (!NP) {
638		c |= partab[c&0177] & 0200;
639		if (OP)
640			c ^= 0200;
641	}
642	if (!UB) {
643		outbuf[obufcnt++] = c;
644		if (obufcnt >= OBUFSIZ)
645			oflush();
646	} else
647		write(STDOUT_FILENO, &c, 1);
648}
649
650static void
651oflush()
652{
653	if (obufcnt)
654		write(STDOUT_FILENO, outbuf, obufcnt);
655	obufcnt = 0;
656}
657
658static void
659prompt()
660{
661
662	putf(LM);
663	if (CO)
664		putchr('\n');
665}
666
667
668static char *
669getline(fd)
670	int fd;
671{
672	int i = 0;
673	static char linebuf[512];
674
675	/*
676	 * This is certainly slow, but it avoids having to include
677	 * stdio.h unnecessarily. Issue files should be small anyway.
678	 */
679	while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
680		if (linebuf[i] == '\n') {
681			/* Don't rely on newline mode, assume raw */
682			linebuf[i++] = '\r';
683			linebuf[i++] = '\n';
684			linebuf[i] = '\0';
685			return linebuf;
686		}
687		++i;
688	}
689	linebuf[i] = '\0';
690	return i ? linebuf : 0;
691}
692
693static void
694putf(cp)
695	register const char *cp;
696{
697	extern char editedhost[];
698	time_t t;
699	char *slash, db[100];
700
701	static struct utsname kerninfo;
702
703	if (!*kerninfo.sysname)
704		uname(&kerninfo);
705
706	while (*cp) {
707		if (*cp != '%') {
708			putchr(*cp++);
709			continue;
710		}
711		switch (*++cp) {
712
713		case 't':
714			slash = strrchr(ttyn, '/');
715			if (slash == (char *) 0)
716				puts(ttyn);
717			else
718				puts(&slash[1]);
719			break;
720
721		case 'h':
722			puts(editedhost);
723			break;
724
725		case 'd': {
726			t = (time_t)0;
727			(void)time(&t);
728			if (Lo)
729				(void)setlocale(LC_TIME, Lo);
730			(void)strftime(db, sizeof(db), "%+", localtime(&t));
731			puts(db);
732			break;
733
734		case 's':
735			puts(kerninfo.sysname);
736			break;
737
738		case 'm':
739			puts(kerninfo.machine);
740			break;
741
742		case 'r':
743			puts(kerninfo.release);
744			break;
745
746		case 'v':
747			puts(kerninfo.version);
748			break;
749		}
750
751		case '%':
752			putchr('%');
753			break;
754		}
755		cp++;
756	}
757}
758