xref: /freebsd/libexec/getty/main.c (revision 1130b656e5fe4c2d1ba299e024d1b40eaeebd380)
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[] = "$FreeBSD$";
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 
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 
364 static int
365 getname()
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 
475 static void
476 putpad(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 
513 static void
514 puts(s)
515 	register const char *s;
516 {
517 	while (*s)
518 		putchr(*s++);
519 }
520 
521 char	outbuf[OBUFSIZ];
522 int	obufcnt = 0;
523 
524 static void
525 putchr(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 
544 static void
545 oflush()
546 {
547 	if (obufcnt)
548 		write(STDOUT_FILENO, outbuf, obufcnt);
549 	obufcnt = 0;
550 }
551 
552 static void
553 prompt()
554 {
555 
556 	putf(LM);
557 	if (CO)
558 		putchr('\n');
559 }
560 
561 static void
562 putf(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