xref: /freebsd/libexec/getty/main.c (revision 0c43d89a0d8e976ca494d4837f4c1f3734d2c300)
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[] = "@(#)main.c	8.1 (Berkeley) 6/20/93";
42 #endif /* not lint */
43 
44 #define USE_OLD_TTY
45 
46 #include <sys/param.h>
47 #include <sys/stat.h>
48 #include <sys/resource.h>
49 
50 #include <ctype.h>
51 #include <ctype.h>
52 #include <fcntl.h>
53 #include <setjmp.h>
54 #include <sgtty.h>
55 #include <signal.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <syslog.h>
59 #include <time.h>
60 #include <unistd.h>
61 
62 #include "gettytab.h"
63 #include "pathnames.h"
64 #include "extern.h"
65 
66 /*
67  * Set the amount of running time that getty should accumulate
68  * before deciding that something is wrong and exit.
69  */
70 #define GETTY_TIMEOUT	60 /* seconds */
71 
72 struct	sgttyb tmode = {
73 	0, 0, CERASE, CKILL, 0
74 };
75 struct	tchars tc = {
76 	CINTR, CQUIT, CSTART,
77 	CSTOP, CEOF, CBRK,
78 };
79 struct	ltchars ltc = {
80 	CSUSP, CDSUSP, CRPRNT,
81 	CFLUSH, CWERASE, CLNEXT
82 };
83 
84 int crmod, digit, lower, upper;
85 
86 char	hostname[MAXHOSTNAMELEN];
87 char	name[16];
88 char	dev[] = _PATH_DEV;
89 char	ttyn[32];
90 char	*portselector();
91 char	*ttyname();
92 
93 #define	OBUFSIZ		128
94 #define	TABBUFSIZ	512
95 
96 char	defent[TABBUFSIZ];
97 char	tabent[TABBUFSIZ];
98 
99 char	*env[128];
100 
101 char partab[] = {
102 	0001,0201,0201,0001,0201,0001,0001,0201,
103 	0202,0004,0003,0205,0005,0206,0201,0001,
104 	0201,0001,0001,0201,0001,0201,0201,0001,
105 	0001,0201,0201,0001,0201,0001,0001,0201,
106 	0200,0000,0000,0200,0000,0200,0200,0000,
107 	0000,0200,0200,0000,0200,0000,0000,0200,
108 	0000,0200,0200,0000,0200,0000,0000,0200,
109 	0200,0000,0000,0200,0000,0200,0200,0000,
110 	0200,0000,0000,0200,0000,0200,0200,0000,
111 	0000,0200,0200,0000,0200,0000,0000,0200,
112 	0000,0200,0200,0000,0200,0000,0000,0200,
113 	0200,0000,0000,0200,0000,0200,0200,0000,
114 	0000,0200,0200,0000,0200,0000,0000,0200,
115 	0200,0000,0000,0200,0000,0200,0200,0000,
116 	0200,0000,0000,0200,0000,0200,0200,0000,
117 	0000,0200,0200,0000,0200,0000,0000,0201
118 };
119 
120 #define	ERASE	tmode.sg_erase
121 #define	KILL	tmode.sg_kill
122 #define	EOT	tc.t_eofc
123 
124 jmp_buf timeout;
125 
126 static void
127 dingdong()
128 {
129 
130 	alarm(0);
131 	signal(SIGALRM, SIG_DFL);
132 	longjmp(timeout, 1);
133 }
134 
135 jmp_buf	intrupt;
136 
137 static void
138 interrupt()
139 {
140 
141 	signal(SIGINT, interrupt);
142 	longjmp(intrupt, 1);
143 }
144 
145 /*
146  * Action to take when getty is running too long.
147  */
148 void
149 timeoverrun(signo)
150 	int signo;
151 {
152 
153 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
154 	exit(1);
155 }
156 
157 static int	getname __P((void));
158 static void	oflush __P((void));
159 static void	prompt __P((void));
160 static void	putchr __P((int));
161 static void	putf __P((char *));
162 static void	putpad __P((char *));
163 static void	puts __P((char *));
164 extern void	reset_fbtab __P((char *));
165 int
166 main(argc, argv)
167 	int argc;
168 	char *argv[];
169 {
170 	extern char **environ;
171 	char *tname;
172 	long allflags;
173 	int repcnt = 0;
174 	struct rlimit limit;
175 
176 	signal(SIGINT, SIG_IGN);
177 /*
178 	signal(SIGQUIT, SIG_DFL);
179 */
180 	openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
181 	gethostname(hostname, sizeof(hostname));
182 	if (hostname[0] == '\0')
183 		strcpy(hostname, "Amnesiac");
184 
185 	/*
186 	 * Limit running time to deal with broken or dead lines.
187 	 */
188 	(void)signal(SIGXCPU, timeoverrun);
189 	limit.rlim_max = RLIM_INFINITY;
190 	limit.rlim_cur = GETTY_TIMEOUT;
191 	(void)setrlimit(RLIMIT_CPU, &limit);
192 
193 	/*
194 	 * The following is a work around for vhangup interactions
195 	 * which cause great problems getting window systems started.
196 	 * If the tty line is "-", we do the old style getty presuming
197 	 * that the file descriptors are already set up for us.
198 	 * J. Gettys - MIT Project Athena.
199 	 */
200 	if (argc <= 2 || strcmp(argv[2], "-") == 0)
201 	    strcpy(ttyn, ttyname(0));
202 	else {
203 	    int i;
204 
205 	    strcpy(ttyn, dev);
206 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
207 	    if (strcmp(argv[0], "+") != 0) {
208 		chown(ttyn, 0, 0);
209 		chmod(ttyn, 0600);
210 		revoke(ttyn);
211 		/*
212 		 * Delay the open so DTR stays down long enough to be detected.
213 		 */
214 		sleep(2);
215 		while ((i = open(ttyn, O_RDWR)) == -1) {
216 			if (repcnt % 10 == 0) {
217 				syslog(LOG_ERR, "%s: %m", ttyn);
218 				closelog();
219 			}
220 			repcnt++;
221 			sleep(60);
222 		}
223 		login_tty(i);
224 	    }
225 	}
226 
227 	/* Read the FBTAB file and check if we have to reset perms/ownership */
228 	reset_fbtab(ttyn);
229 
230 	gettable("default", defent);
231 	gendefaults();
232 	tname = "default";
233 	if (argc > 1)
234 		tname = argv[1];
235 	for (;;) {
236 		int off;
237 
238 		gettable(tname, tabent);
239 		if (OPset || EPset || APset)
240 			APset++, OPset++, EPset++;
241 		setdefaults();
242 		off = 0;
243 		ioctl(0, TIOCFLUSH, &off);	/* clear out the crap */
244 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
245 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
246 		if (IS)
247 			tmode.sg_ispeed = speed(IS);
248 		else if (SP)
249 			tmode.sg_ispeed = speed(SP);
250 		if (OS)
251 			tmode.sg_ospeed = speed(OS);
252 		else if (SP)
253 			tmode.sg_ospeed = speed(SP);
254 		tmode.sg_flags = setflags(0);
255 		ioctl(0, TIOCSETP, &tmode);
256 		setchars();
257 		ioctl(0, TIOCSETC, &tc);
258 		if (HC)
259 			ioctl(0, TIOCHPCL, 0);
260 		if (AB) {
261 			extern char *autobaud();
262 
263 			tname = autobaud();
264 			continue;
265 		}
266 		if (PS) {
267 			tname = portselector();
268 			continue;
269 		}
270 		if (CL && *CL)
271 			putpad(CL);
272 		edithost(HE);
273 		if (IM && *IM)
274 			putf(IM);
275 		if (setjmp(timeout)) {
276 			tmode.sg_ispeed = tmode.sg_ospeed = 0;
277 			ioctl(0, TIOCSETP, &tmode);
278 			exit(1);
279 		}
280 		if (TO) {
281 			signal(SIGALRM, dingdong);
282 			alarm(TO);
283 		}
284 		if (getname()) {
285 			register int i;
286 
287 			oflush();
288 			alarm(0);
289 			signal(SIGALRM, SIG_DFL);
290 			if (name[0] == '-') {
291 				puts("user names may not start with '-'.");
292 				continue;
293 			}
294 			if (!(upper || lower || digit))
295 				continue;
296 			allflags = setflags(2);
297 			tmode.sg_flags = allflags & 0xffff;
298 			allflags >>= 16;
299 			if (crmod || NL)
300 				tmode.sg_flags |= CRMOD;
301 			if (upper || UC)
302 				tmode.sg_flags |= LCASE;
303 			if (lower || LC)
304 				tmode.sg_flags &= ~LCASE;
305 			ioctl(0, TIOCSETP, &tmode);
306 			ioctl(0, TIOCSLTC, &ltc);
307 			ioctl(0, TIOCLSET, &allflags);
308 			signal(SIGINT, SIG_DFL);
309 			for (i = 0; environ[i] != (char *)0; i++)
310 				env[i] = environ[i];
311 			makeenv(&env[i]);
312 
313 			/*
314 			 * this is what login was doing anyway.
315 			 * soon we rewrite getty completely.
316 			 */
317 			set_ttydefaults(0);
318 			limit.rlim_max = RLIM_INFINITY;
319 			limit.rlim_cur = RLIM_INFINITY;
320 			(void)setrlimit(RLIMIT_CPU, &limit);
321 			execle(LO, "login", "-p", name, (char *) 0, env);
322 			syslog(LOG_ERR, "%s: %m", LO);
323 			exit(1);
324 		}
325 		alarm(0);
326 		signal(SIGALRM, SIG_DFL);
327 		signal(SIGINT, SIG_IGN);
328 		if (NX && *NX)
329 			tname = NX;
330 	}
331 }
332 
333 static int
334 getname()
335 {
336 	register int c;
337 	register char *np;
338 	char cs;
339 
340 	/*
341 	 * Interrupt may happen if we use CBREAK mode
342 	 */
343 	if (setjmp(intrupt)) {
344 		signal(SIGINT, SIG_IGN);
345 		return (0);
346 	}
347 	signal(SIGINT, interrupt);
348 	tmode.sg_flags = setflags(0);
349 	ioctl(0, TIOCSETP, &tmode);
350 	tmode.sg_flags = setflags(1);
351 	prompt();
352 	if (PF > 0) {
353 		oflush();
354 		sleep(PF);
355 		PF = 0;
356 	}
357 	ioctl(0, TIOCSETP, &tmode);
358 	crmod = digit = lower = upper = 0;
359 	np = name;
360 	for (;;) {
361 		oflush();
362 		if (read(STDIN_FILENO, &cs, 1) <= 0)
363 			exit(0);
364 		if ((c = cs&0177) == 0)
365 			return (0);
366 		if (c == EOT)
367 			exit(1);
368 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
369 			putf("\r\n");
370 			break;
371 		}
372 		if (islower(c))
373 			lower = 1;
374 		else if (isupper(c))
375 			upper = 1;
376 		else if (c == ERASE || c == '#' || c == '\b') {
377 			if (np > name) {
378 				np--;
379 				if (tmode.sg_ospeed >= B1200)
380 					puts("\b \b");
381 				else
382 					putchr(cs);
383 			}
384 			continue;
385 		} else if (c == KILL || c == '@') {
386 			putchr(cs);
387 			putchr('\r');
388 			if (tmode.sg_ospeed < B1200)
389 				putchr('\n');
390 			/* this is the way they do it down under ... */
391 			else if (np > name)
392 				puts("                                     \r");
393 			prompt();
394 			np = name;
395 			continue;
396 		} else if (isdigit(c))
397 			digit++;
398 		if (IG && (c <= ' ' || c > 0176))
399 			continue;
400 		*np++ = c;
401 		putchr(cs);
402 	}
403 	signal(SIGINT, SIG_IGN);
404 	*np = 0;
405 	if (c == '\r')
406 		crmod = 1;
407 	if (upper && !lower && !LC || UC)
408 		for (np = name; *np; np++)
409 			if (isupper(*np))
410 				*np = tolower(*np);
411 	return (1);
412 }
413 
414 static
415 short	tmspc10[] = {
416 	0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
417 };
418 
419 static void
420 putpad(s)
421 	register char *s;
422 {
423 	register pad = 0;
424 	register mspc10;
425 
426 	if (isdigit(*s)) {
427 		while (isdigit(*s)) {
428 			pad *= 10;
429 			pad += *s++ - '0';
430 		}
431 		pad *= 10;
432 		if (*s == '.' && isdigit(s[1])) {
433 			pad += s[1] - '0';
434 			s += 2;
435 		}
436 	}
437 
438 	puts(s);
439 	/*
440 	 * If no delay needed, or output speed is
441 	 * not comprehensible, then don't try to delay.
442 	 */
443 	if (pad == 0)
444 		return;
445 	if (tmode.sg_ospeed <= 0 ||
446 	    tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
447 		return;
448 
449 	/*
450 	 * Round up by a half a character frame, and then do the delay.
451 	 * Too bad there are no user program accessible programmed delays.
452 	 * Transmitting pad characters slows many terminals down and also
453 	 * loads the system.
454 	 */
455 	mspc10 = tmspc10[tmode.sg_ospeed];
456 	pad += mspc10 / 2;
457 	for (pad /= mspc10; pad > 0; pad--)
458 		putchr(*PC);
459 }
460 
461 static void
462 puts(s)
463 	register char *s;
464 {
465 	while (*s)
466 		putchr(*s++);
467 }
468 
469 char	outbuf[OBUFSIZ];
470 int	obufcnt = 0;
471 
472 static void
473 putchr(cc)
474 	int cc;
475 {
476 	char c;
477 
478 	c = cc;
479 	if (!NP) {
480 		c |= partab[c&0177] & 0200;
481 		if (OP)
482 			c ^= 0200;
483 	}
484 	if (!UB) {
485 		outbuf[obufcnt++] = c;
486 		if (obufcnt >= OBUFSIZ)
487 			oflush();
488 	} else
489 		write(STDOUT_FILENO, &c, 1);
490 }
491 
492 static void
493 oflush()
494 {
495 	if (obufcnt)
496 		write(STDOUT_FILENO, outbuf, obufcnt);
497 	obufcnt = 0;
498 }
499 
500 static void
501 prompt()
502 {
503 
504 	putf(LM);
505 	if (CO)
506 		putchr('\n');
507 }
508 
509 static void
510 putf(cp)
511 	register char *cp;
512 {
513 	extern char editedhost[];
514 	time_t t;
515 	char *slash, db[100];
516 
517 	while (*cp) {
518 		if (*cp != '%') {
519 			putchr(*cp++);
520 			continue;
521 		}
522 		switch (*++cp) {
523 
524 		case 't':
525 			slash = strrchr(ttyn, '/');
526 			if (slash == (char *) 0)
527 				puts(ttyn);
528 			else
529 				puts(&slash[1]);
530 			break;
531 
532 		case 'h':
533 			puts(editedhost);
534 			break;
535 
536 		case 'd': {
537 			static char fmt[] = "%l:% %P on %A, %d %B %Y";
538 
539 			fmt[4] = 'M';		/* I *hate* SCCS... */
540 			(void)time(&t);
541 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
542 			puts(db);
543 			break;
544 		}
545 
546 		case '%':
547 			putchr('%');
548 			break;
549 		}
550 		cp++;
551 	}
552 }
553