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