xref: /freebsd/libexec/getty/main.c (revision bcd92649c9952c9c9e8845dbd34276a60dd16664)
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
35 static 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";*/
42 static 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 
91 struct termios tmode, omode;
92 
93 int crmod, digit, lower, upper;
94 
95 char	hostname[MAXHOSTNAMELEN];
96 struct utsname kerninfo;
97 char	name[16];
98 char	dev[] = _PATH_DEV;
99 char	ttyn[32];
100 
101 #define	OBUFSIZ		128
102 #define	TABBUFSIZ	512
103 
104 char	defent[TABBUFSIZ];
105 char	tabent[TABBUFSIZ];
106 
107 char	*env[128];
108 
109 char 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 
132 jmp_buf timeout;
133 
134 static void	dingdong __P((int));
135 static int	getname __P((void));
136 static void	interrupt __P((int));
137 static void	oflush __P((void));
138 static void	prompt __P((void));
139 static void	putchr __P((int));
140 static void	putf __P((const char *));
141 static void	putpad __P((const char *));
142 static void	puts __P((const char *));
143 static void	timeoverrun __P((int));
144 
145 int		main __P((int, char **));
146 
147 static void
148 dingdong(signo)
149 	int signo;
150 {
151 	alarm(0);
152 	longjmp(timeout, 1);
153 }
154 
155 jmp_buf	intrupt;
156 
157 static void
158 interrupt(signo)
159 	int signo;
160 {
161 	longjmp(intrupt, 1);
162 }
163 
164 /*
165  * Action to take when getty is running too long.
166  */
167 static void
168 timeoverrun(signo)
169 	int signo;
170 {
171 
172 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
173 	exit(1);
174 }
175 
176 int
177 main(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 
358 static int
359 getname()
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 
469 static void
470 putpad(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 
507 static void
508 puts(s)
509 	register const char *s;
510 {
511 	while (*s)
512 		putchr(*s++);
513 }
514 
515 char	outbuf[OBUFSIZ];
516 int	obufcnt = 0;
517 
518 static void
519 putchr(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 
538 static void
539 oflush()
540 {
541 	if (obufcnt)
542 		write(STDOUT_FILENO, outbuf, obufcnt);
543 	obufcnt = 0;
544 }
545 
546 static void
547 prompt()
548 {
549 
550 	putf(LM);
551 	if (CO)
552 		putchr('\n');
553 }
554 
555 static void
556 putf(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