1 /**	$MirOS: src/libexec/getty/main.c,v 1.3 2005/05/30 07:29:32 tg Exp $ */
2 /*	$OpenBSD: main.c,v 1.28 2003/07/29 18:39:22 deraadt Exp $	*/
3 
4 /*-
5  * Copyright (c) 1980, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 static char copyright[] =
35 "@(#) Copyright (c) 1980, 1993\n\
36 	The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38 
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <termios.h>
42 #include <sys/ioctl.h>
43 #include <sys/resource.h>
44 #include <sys/utsname.h>
45 #include <errno.h>
46 #include <signal.h>
47 #include <fcntl.h>
48 #include <time.h>
49 #include <ctype.h>
50 #include <fcntl.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <stdio.h>
55 #include <time.h>
56 #include <unistd.h>
57 #include <util.h>
58 
59 #include "gettytab.h"
60 #include "pathnames.h"
61 #include "extern.h"
62 
63 __SCCSID("@(#)main.c	8.1 (Berkeley) 6/20/93");
64 __RCSID("$MirOS: src/libexec/getty/main.c,v 1.3 2005/05/30 07:29:32 tg Exp $");
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 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
73 
74 #define PPP_FRAME	    0x7e  /* PPP Framing character */
75 #define PPP_STATION	    0xff  /* "All Station" character */
76 #define PPP_ESCAPE	    0x7d  /* Escape Character */
77 #define PPP_CONTROL	    0x03  /* PPP Control Field */
78 #define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
79 #define PPP_LCP_HI	    0xc0  /* LCP protocol - high byte */
80 #define PPP_LCP_LOW	    0x21  /* LCP protocol - low byte */
81 
82 struct termios tmode, omode;
83 
84 int crmod, digit, lower, upper;
85 
86 char	hostname[MAXHOSTNAMELEN];
87 struct	utsname kerninfo;
88 char	name[MAXLOGNAME];
89 char	dev[] = _PATH_DEV;
90 char	ttyn[32];
91 char	*portselector(void);
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.c_cc[VERASE]
121 #define	KILL	tmode.c_cc[VKILL]
122 #define	EOT	tmode.c_cc[VEOF]
123 
124 static void
dingdong(int signo)125 dingdong(int signo)
126 {
127 	tmode.c_ispeed = tmode.c_ospeed = 0;
128 	(void)tcsetattr(0, TCSANOW, &tmode);
129 	_exit(1);
130 }
131 
132 volatile sig_atomic_t interrupt_flag;
133 
134 static void
interrupt(int signo)135 interrupt(int signo)
136 {
137 	int save_errno = errno;
138 
139 	interrupt_flag = 1;
140 	signal(SIGINT, interrupt);
141 	errno = save_errno;
142 }
143 
144 /*
145  * Action to take when getty is running too long.
146  */
147 static void
timeoverrun(int signo)148 timeoverrun(int signo)
149 {
150 	struct syslog_data sdata = SYSLOG_DATA_INIT;
151 
152 	syslog_r(LOG_ERR, &sdata,
153 	    "getty exiting due to excessive running time");
154 	_exit(1);
155 }
156 
157 static int	getname(void);
158 static void	oflush(void);
159 static void	prompt(void);
160 static void	putchr(int);
161 static void	putf(char *);
162 static void	putpad(char *);
163 static void	xputs(char *);
164 
165 int
main(int argc,char * argv[])166 main(int argc, char *argv[])
167 {
168 	extern char **environ;
169 	char *tname;
170 	int repcnt = 0, failopenlogged = 0;
171 	struct rlimit limit;
172 	int rval;
173 
174 	signal(SIGINT, SIG_IGN);
175 /*
176 	signal(SIGQUIT, SIG_DFL);
177 */
178 	openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
179 	gethostname(hostname, sizeof(hostname));
180 	if (hostname[0] == '\0')
181 		strlcpy(hostname, "Amnesiac", sizeof hostname);
182 	uname(&kerninfo);
183 
184 	/*
185 	 * Limit running time to deal with broken or dead lines.
186 	 */
187 	(void)signal(SIGXCPU, timeoverrun);
188 	limit.rlim_max = RLIM_INFINITY;
189 	limit.rlim_cur = GETTY_TIMEOUT;
190 	(void)setrlimit(RLIMIT_CPU, &limit);
191 
192 	/*
193 	 * The following is a work around for vhangup interactions
194 	 * which cause great problems getting window systems started.
195 	 * If the tty line is "-", we do the old style getty presuming
196 	 * that the file descriptors are already set up for us.
197 	 * J. Gettys - MIT Project Athena.
198 	 */
199 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
200 		snprintf(ttyn, sizeof ttyn, "%s", ttyname(0));
201 	} else {
202 		int i;
203 
204 		snprintf(ttyn, sizeof ttyn, "%s%s", dev, argv[2]);
205 		if (strcmp(argv[0], "+") != 0) {
206 			chown(ttyn, 0, 0);
207 			chmod(ttyn, 0600);
208 			revoke(ttyn);
209 			/*
210 			 * Delay the open so DTR stays down long enough to be detected.
211 			 */
212 			sleep(2);
213 			while ((i = open(ttyn, O_RDWR)) == -1) {
214 				if ((repcnt % 10 == 0) &&
215 				    (errno != ENXIO || !failopenlogged)) {
216 					syslog(LOG_ERR, "%s: %m", ttyn);
217 					closelog();
218 					failopenlogged = 1;
219 				}
220 				repcnt++;
221 				sleep(60);
222 			}
223 			login_tty(i);
224 		}
225 	}
226 
227 	/* Start with default tty settings */
228 	if (tcgetattr(0, &tmode) < 0) {
229 		syslog(LOG_ERR, "%s: %m", ttyn);
230 		exit(1);
231 	}
232 	omode = tmode;
233 
234 	gettable("default", defent);
235 	gendefaults();
236 	tname = "default";
237 	if (argc > 1)
238 		tname = argv[1];
239 	for (;;) {
240 		int off;
241 
242 		gettable(tname, tabent);
243 		if (OPset || EPset || APset)
244 			APset++, OPset++, EPset++;
245 		setdefaults();
246 		off = 0;
247 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
248 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
249 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
250 
251 		if (IS)
252 			cfsetispeed(&tmode, IS);
253 		else if (SP)
254 			cfsetispeed(&tmode, SP);
255 		if (OS)
256 			cfsetospeed(&tmode, OS);
257 		else if (SP)
258 			cfsetospeed(&tmode, SP);
259 		setflags(0);
260 		setchars();
261 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
262 			syslog(LOG_ERR, "%s: %m", ttyn);
263 			exit(1);
264 		}
265 		if (AB) {
266 			tname = autobaud();
267 			continue;
268 		}
269 		if (PS) {
270 			tname = portselector();
271 			continue;
272 		}
273 		if (CL && *CL)
274 			putpad(CL);
275 		edithost(HE);
276 		if (IM && *IM)
277 			putf(IM);
278 		if (TO) {
279 			signal(SIGALRM, dingdong);
280 			alarm(TO);
281 		}
282 		if ((rval = getname()) == 2) {
283 			oflush();
284 			alarm(0);
285 			signal(SIGALRM, SIG_DFL);
286 			execle(PP, "ppplogin", ttyn, (char *) 0, env);
287 			syslog(LOG_ERR, "%s: %m", PP);
288 			exit(1);
289 		} else if (rval) {
290 			int i;
291 
292 			oflush();
293 			alarm(0);
294 			signal(SIGALRM, SIG_DFL);
295 			if (name[0] == '-') {
296 				xputs("user names may not start with '-'.");
297 				continue;
298 			}
299 			if (!(upper || lower || digit))
300 				continue;
301 			setflags(2);
302 			if (crmod) {
303 				tmode.c_iflag |= ICRNL;
304 				tmode.c_oflag |= ONLCR;
305 			}
306 			if (upper || UC) {
307 				tmode.c_iflag |= IUCLC;
308 				tmode.c_oflag |= OLCUC;
309 				tmode.c_lflag |= XCASE;
310 			}
311 			if (lower || LC) {
312 				tmode.c_iflag &= ~IUCLC;
313 				tmode.c_oflag &= ~OLCUC;
314 				tmode.c_lflag &= ~XCASE;
315 			}
316 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
317 				syslog(LOG_ERR, "%s: %m", ttyn);
318 				exit(1);
319 			}
320 			signal(SIGINT, SIG_DFL);
321 			for (i = 0; environ[i] != (char *)0; i++)
322 				env[i] = environ[i];
323 			makeenv(&env[i]);
324 
325 			limit.rlim_max = RLIM_INFINITY;
326 			limit.rlim_cur = RLIM_INFINITY;
327 			(void)setrlimit(RLIMIT_CPU, &limit);
328 			execle(LO, "login", "-p", "--", name, (char *)0, env);
329 			syslog(LOG_ERR, "%s: %m", LO);
330 			exit(1);
331 		}
332 		alarm(0);
333 		signal(SIGALRM, SIG_DFL);
334 		signal(SIGINT, SIG_IGN);
335 		if (NX && *NX)
336 			tname = NX;
337 	}
338 }
339 
340 static int
getname(void)341 getname(void)
342 {
343 	int ppp_state = 0, ppp_connection = 0;
344 	unsigned char cs;
345 	int c, r;
346 	char *np;
347 
348 	/*
349 	 * Interrupt may happen if we use CBREAK mode
350 	 */
351 	signal(SIGINT, interrupt);
352 	setflags(1);
353 	prompt();
354 	if (PF > 0) {
355 		oflush();
356 		sleep(PF);
357 		PF = 0;
358 	}
359 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
360 		syslog(LOG_ERR, "%s: %m", ttyn);
361 		exit(1);
362 	}
363 	crmod = digit = lower = upper = 0;
364 	np = name;
365 	for (;;) {
366 		oflush();
367 		r = read(STDIN_FILENO, &cs, 1);
368 		if (r <= 0) {
369 			if (r == -1 && errno == EINTR && interrupt_flag) {
370 				interrupt_flag = 0;
371 				return (0);
372 			}
373 			exit(0);
374 		}
375 		if ((c = cs&0177) == 0)
376 			return (0);
377 
378 		/*
379 		 * PPP detection state machine..
380 		 * Look for sequences:
381 		 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
382 		 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
383 		 * See RFC1662.
384 		 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
385 		 * and Erik 'PPP' Olson <eriko@wrq.com>
386 		 */
387 		if (PP && cs == PPP_FRAME) {
388 			ppp_state = 1;
389 		} else if (ppp_state == 1 && cs == PPP_STATION) {
390 			ppp_state = 2;
391 		} else if (ppp_state == 2 && cs == PPP_ESCAPE) {
392 			ppp_state = 3;
393 		} else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
394 		    (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
395 			ppp_state = 4;
396 		} else if (ppp_state == 4 && cs == PPP_LCP_HI) {
397 			ppp_state = 5;
398 		} else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
399 			ppp_connection = 1;
400 			break;
401 		} else {
402 			ppp_state = 0;
403 		}
404 
405 		if (c == EOT)
406 			exit(1);
407 		if (c == '\r' || c == '\n') {
408 			putf("\r\n");
409 			break;
410 		} else if (c == ERASE || c == '#' || c == '\b') {
411 			if (np > name) {
412 				np--;
413 				if (cfgetospeed(&tmode) >= 1200)
414 					xputs("\b \b");
415 				else
416 					putchr(cs);
417 			}
418 			continue;
419 		} else if (c == KILL || c == '@') {
420 			putchr(cs);
421 			putchr('\r');
422 			if (cfgetospeed(&tmode) < 1200)
423 				putchr('\n');
424 			/* this is the way they do it down under ... */
425 			else if (np > name)
426 				xputs("                                     \r");
427 			prompt();
428 			np = name;
429 			continue;
430 		}
431 		if (np >= name + sizeof name - 1) {
432 			putf("\a\b \b");
433 			np--;
434 			continue;
435 		}
436 		if (islower(c))
437 			lower = 1;
438 		else if (isupper(c))
439 			upper = 1;
440 		else if (isdigit(c))
441 			digit++;
442 		if (IG && (c <= ' ' || c > 0176))
443 			continue;
444 		*np++ = c;
445 		putchr(cs);
446 	}
447 	signal(SIGINT, SIG_IGN);
448 	if (interrupt_flag) {
449 		interrupt_flag = 0;
450 		return (0);
451 	}
452 	*np = 0;
453 	if (c == '\r')
454 		crmod = 1;
455 	if (upper && !lower && !LC || UC)
456 		for (np = name; *np; np++)
457 			if (isupper(*np))
458 				*np = tolower(*np);
459 	return (1 + ppp_connection);
460 }
461 
462 static void
putpad(char * s)463 putpad(char *s)
464 {
465 	int pad = 0;
466 	speed_t ospeed = cfgetospeed(&tmode);
467 
468 	if (isdigit(*s)) {
469 		while (isdigit(*s)) {
470 			pad *= 10;
471 			pad += *s++ - '0';
472 		}
473 		pad *= 10;
474 		if (*s == '.' && isdigit(s[1])) {
475 			pad += s[1] - '0';
476 			s += 2;
477 		}
478 	}
479 
480 	xputs(s);
481 	/*
482 	 * If no delay needed, or output speed is
483 	 * not comprehensible, then don't try to delay.
484 	 */
485 	if (pad == 0 || ospeed <= 0)
486 		return;
487 
488 	/*
489 	 * Round up by a half a character frame, and then do the delay.
490 	 * Too bad there are no user program accessible programmed delays.
491 	 * Transmitting pad characters slows many terminals down and also
492 	 * loads the system.
493 	 */
494 	pad = (pad * ospeed + 50000) / 100000;
495 	while (pad--)
496 		putchr(*PC);
497 }
498 
499 static void
xputs(char * s)500 xputs(char *s)
501 {
502 	while (*s)
503 		putchr(*s++);
504 }
505 
506 char	outbuf[OBUFSIZ];
507 int	obufcnt = 0;
508 
509 static void
putchr(int cc)510 putchr(int cc)
511 {
512 	char c;
513 
514 	c = cc;
515 	if (!NP) {
516 		c |= partab[c&0177] & 0200;
517 		if (OP)
518 			c ^= 0200;
519 	}
520 	if (!UB) {
521 		outbuf[obufcnt++] = c;
522 		if (obufcnt >= OBUFSIZ)
523 			oflush();
524 	} else
525 		write(STDOUT_FILENO, &c, 1);
526 }
527 
528 static void
oflush(void)529 oflush(void)
530 {
531 	if (obufcnt)
532 		write(STDOUT_FILENO, outbuf, obufcnt);
533 	obufcnt = 0;
534 }
535 
536 static void
prompt(void)537 prompt(void)
538 {
539 
540 	putf(LM);
541 	if (CO)
542 		putchr('\n');
543 }
544 
545 static void
putf(char * cp)546 putf(char *cp)
547 {
548 	extern char editedhost[];
549 	char *slash, db[100];
550 	time_t t;
551 
552 	while (*cp) {
553 		if (*cp != '%') {
554 			putchr(*cp++);
555 			continue;
556 		}
557 		switch (*++cp) {
558 
559 		case 't':
560 			slash = strrchr(ttyn, '/');
561 			if (slash == (char *) 0)
562 				xputs(ttyn);
563 			else
564 				xputs(&slash[1]);
565 			break;
566 
567 		case 'h':
568 			xputs(editedhost);
569 			break;
570 
571 		case 'd': {
572 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
573 
574 			fmt[4] = 'M';		/* I *hate* SCCS... */
575 			(void)time(&t);
576 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
577 			xputs(db);
578 			break;
579 		}
580 
581 		case 's':
582 			xputs(kerninfo.sysname);
583 			break;
584 
585 		case 'm':
586 			xputs(kerninfo.machine);
587 			break;
588 
589 		case 'r':
590 			xputs(kerninfo.release);
591 			break;
592 
593 		case 'v':
594 			xputs(kerninfo.version);
595 			break;
596 
597 		case '%':
598 			putchr('%');
599 			break;
600 		}
601 		cp++;
602 	}
603 }
604