Home | History | Annotate | Line # | Download | only in getty
main.c revision 1.26
      1 /*	$NetBSD: main.c,v 1.26 1998/07/06 06:48:19 mrg Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 
     38 #ifndef lint
     39 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
     40 	The Regents of the University of California.  All rights reserved.\n");
     41 #endif /* not lint */
     42 
     43 #ifndef lint
     44 #if 0
     45 static char sccsid[] = "from: @(#)main.c	8.1 (Berkeley) 6/20/93";
     46 #else
     47 __RCSID("$NetBSD: main.c,v 1.26 1998/07/06 06:48:19 mrg Exp $");
     48 #endif
     49 #endif /* not lint */
     50 
     51 #include <sys/param.h>
     52 #include <sys/stat.h>
     53 #include <termios.h>
     54 #include <sys/ioctl.h>
     55 #include <sys/resource.h>
     56 #include <sys/utsname.h>
     57 
     58 #include <errno.h>
     59 #include <fcntl.h>
     60 #include <time.h>
     61 #include <ctype.h>
     62 #include <fcntl.h>
     63 #include <pwd.h>
     64 #include <setjmp.h>
     65 #include <signal.h>
     66 #include <stdlib.h>
     67 #include <string.h>
     68 #include <syslog.h>
     69 #include <time.h>
     70 #include <unistd.h>
     71 #include <util.h>
     72 
     73 #include "gettytab.h"
     74 #include "pathnames.h"
     75 #include "extern.h"
     76 
     77 extern char *__progname;
     78 
     79 /*
     80  * Set the amount of running time that getty should accumulate
     81  * before deciding that something is wrong and exit.
     82  */
     83 #define GETTY_TIMEOUT	60 /* seconds */
     84 
     85 struct termios tmode, omode;
     86 
     87 int crmod, digit, lower, upper;
     88 
     89 char	hostname[MAXHOSTNAMELEN + 1];
     90 struct	utsname kerninfo;
     91 char	name[16];
     92 char	dev[] = _PATH_DEV;
     93 char	ttyn[32];
     94 char	lockfile[512];
     95 uid_t	ttyowner;
     96 
     97 #define	OBUFSIZ		128
     98 #define	TABBUFSIZ	512
     99 
    100 char	defent[TABBUFSIZ];
    101 char	tabent[TABBUFSIZ];
    102 
    103 char	*env[128];
    104 
    105 char partab[] = {
    106 	0001,0201,0201,0001,0201,0001,0001,0201,
    107 	0202,0004,0003,0205,0005,0206,0201,0001,
    108 	0201,0001,0001,0201,0001,0201,0201,0001,
    109 	0001,0201,0201,0001,0201,0001,0001,0201,
    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 	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 	0000,0200,0200,0000,0200,0000,0000,0200,
    119 	0200,0000,0000,0200,0000,0200,0200,0000,
    120 	0200,0000,0000,0200,0000,0200,0200,0000,
    121 	0000,0200,0200,0000,0200,0000,0000,0201
    122 };
    123 
    124 #define	ERASE	tmode.c_cc[VERASE]
    125 #define	KILL	tmode.c_cc[VKILL]
    126 #define	EOT	tmode.c_cc[VEOF]
    127 
    128 static void	dingdong __P((int));
    129 static void	interrupt __P((int));
    130 void		timeoverrun __P((int));
    131 
    132 jmp_buf timeout;
    133 
    134 static void
    135 dingdong(signo)
    136 	int signo;
    137 {
    138 
    139 	alarm(0);
    140 	signal(SIGALRM, SIG_DFL);
    141 	longjmp(timeout, 1);
    142 }
    143 
    144 jmp_buf	intrupt;
    145 
    146 static void
    147 interrupt(signo)
    148 	int signo;
    149 {
    150 
    151 	signal(SIGINT, interrupt);
    152 	longjmp(intrupt, 1);
    153 }
    154 
    155 /*
    156  * Action to take when getty is running too long.
    157  */
    158 void
    159 timeoverrun(signo)
    160 	int signo;
    161 {
    162 
    163 	syslog(LOG_ERR, "getty exiting due to excessive running time\n");
    164 	exit(1);
    165 }
    166 
    167 int		main __P((int, char **));
    168 static int	getname __P((void));
    169 static void	oflush __P((void));
    170 static void	prompt __P((void));
    171 static void	putchr __P((int));
    172 static void	putf __P((const char *));
    173 static void	putpad __P((const char *));
    174 static void	xputs __P((const char *));
    175 
    176 int
    177 main(argc, argv)
    178 	int argc;
    179 	char *argv[];
    180 {
    181 	extern char **environ;
    182 	char *tname;
    183 	int repcnt = 0, failopenlogged = 0, uugetty = 0;
    184 	struct rlimit limit;
    185 	struct passwd *pw;
    186 
    187 #ifdef __GNUC__
    188 	(void)&tname;		/* XXX gcc -Wall */
    189 #endif
    190 
    191 	signal(SIGINT, SIG_IGN);
    192 /*
    193 	signal(SIGQUIT, SIG_DFL);
    194 */
    195 	openlog("getty", LOG_ODELAY|LOG_PID, LOG_AUTH);
    196 	gethostname(hostname, sizeof(hostname));
    197 	hostname[sizeof(hostname) - 1] = '\0';
    198 	if (hostname[0] == '\0')
    199 		strcpy(hostname, "Amnesiac");
    200 	uname(&kerninfo);
    201 
    202 	if (__progname[0] == 'u' && __progname[1] == 'u')
    203 		uugetty = 1;
    204 
    205 	/*
    206 	 * Find id of uucp login (if present) so we can chown tty properly.
    207 	 */
    208 	if (uugetty && (pw = getpwnam("uucp")))
    209 		ttyowner = pw->pw_uid;
    210 	else
    211 		ttyowner = 0;
    212 
    213 	/*
    214 	 * Limit running time to deal with broken or dead lines.
    215 	 */
    216 	(void)signal(SIGXCPU, timeoverrun);
    217 	limit.rlim_max = RLIM_INFINITY;
    218 	limit.rlim_cur = GETTY_TIMEOUT;
    219 	(void)setrlimit(RLIMIT_CPU, &limit);
    220 
    221 	/*
    222 	 * The following is a work around for vhangup interactions
    223 	 * which cause great problems getting window systems started.
    224 	 * If the tty line is "-", we do the old style getty presuming
    225 	 * that the file descriptors are already set up for us.
    226 	 * J. Gettys - MIT Project Athena.
    227 	 */
    228 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
    229 	    strncpy(ttyn, ttyname(0), 32);
    230 	    ttyn[31] = (char)NULL;
    231 	}
    232 	else {
    233 	    int i;
    234 
    235 	    strcpy(ttyn, dev);
    236 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
    237 
    238 	    if (uugetty)  {
    239 		chown(ttyn, ttyowner, 0);
    240 		strcpy(lockfile, _PATH_LOCK);
    241 		strncat(lockfile, argv[2], sizeof(lockfile)-sizeof(_PATH_LOCK));
    242 		/* wait for lockfiles to go away before we try to open */
    243 		if ( pidlock(lockfile, 0, 0, 0) != 0 )  {
    244 		    syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
    245 		    exit(1);
    246 		}
    247 		unlink(lockfile);
    248 	    }
    249 	    if (strcmp(argv[0], "+") != 0) {
    250 		chown(ttyn, ttyowner, 0);
    251 		chmod(ttyn, 0600);
    252 		revoke(ttyn);
    253 		if (ttyaction(ttyn, "getty", "root"))
    254 			syslog(LOG_ERR,"%s: ttyaction failed", ttyn);
    255 		/*
    256 		 * Delay the open so DTR stays down long enough to be detected.
    257 		 */
    258 		sleep(2);
    259 		while ((i = open(ttyn, O_RDWR)) == -1) {
    260 			if ((repcnt % 10 == 0) &&
    261 			    (errno != ENXIO || !failopenlogged)) {
    262 				syslog(LOG_ERR, "%s: %m", ttyn);
    263 				closelog();
    264 				failopenlogged = 1;
    265 			}
    266 			repcnt++;
    267 			sleep(60);
    268 		}
    269 		if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
    270 			syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
    271 			exit(1);
    272 		}
    273 		(void) chown(lockfile, ttyowner, 0);
    274 		login_tty(i);
    275 	    }
    276 	}
    277 
    278 	/* Start with default tty settings */
    279 	if (tcgetattr(0, &tmode) < 0) {
    280 		syslog(LOG_ERR, "%s: %m", ttyn);
    281 		exit(1);
    282 	}
    283 	omode = tmode;
    284 
    285 	gettable("default", defent);
    286 	gendefaults();
    287 	tname = "default";
    288 	if (argc > 1)
    289 		tname = argv[1];
    290 	for (;;) {
    291 		int off;
    292 
    293 		gettable(tname, tabent);
    294 		if (OPset || EPset || APset)
    295 			APset++, OPset++, EPset++;
    296 		setdefaults();
    297 		off = 0;
    298 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
    299 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
    300 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
    301 
    302 		if (IS)
    303 			cfsetispeed(&tmode, IS);
    304 		else if (SP)
    305 			cfsetispeed(&tmode, SP);
    306 		if (OS)
    307 			cfsetospeed(&tmode, OS);
    308 		else if (SP)
    309 			cfsetospeed(&tmode, SP);
    310 		setflags(0);
    311 		setchars();
    312 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    313 			syslog(LOG_ERR, "%s: %m", ttyn);
    314 			exit(1);
    315 		}
    316 		if (AB) {
    317 			tname = autobaud();
    318 			continue;
    319 		}
    320 		if (PS) {
    321 			tname = portselector();
    322 			continue;
    323 		}
    324 		if (CL && *CL)
    325 			putpad(CL);
    326 		edithost(HE);
    327 		if (IM && *IM)
    328 			putf(IM);
    329 		if (setjmp(timeout)) {
    330 			tmode.c_ispeed = tmode.c_ospeed = 0;
    331 			(void)tcsetattr(0, TCSANOW, &tmode);
    332 			exit(1);
    333 		}
    334 		if (TO) {
    335 			signal(SIGALRM, dingdong);
    336 			alarm(TO);
    337 		}
    338 		if (getname()) {
    339 			int i;
    340 
    341 			oflush();
    342 			alarm(0);
    343 			signal(SIGALRM, SIG_DFL);
    344 			if (name[0] == '-') {
    345 				xputs("user names may not start with '-'.");
    346 				continue;
    347 			}
    348 			if (!(upper || lower || digit))
    349 				continue;
    350 			setflags(2);
    351 			if (crmod) {
    352 				tmode.c_iflag |= ICRNL;
    353 				tmode.c_oflag |= ONLCR;
    354 			}
    355 #if XXX
    356 			if (upper || UC)
    357 				tmode.sg_flags |= LCASE;
    358 			if (lower || LC)
    359 				tmode.sg_flags &= ~LCASE;
    360 #endif
    361 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    362 				syslog(LOG_ERR, "%s: %m", ttyn);
    363 				exit(1);
    364 			}
    365 			signal(SIGINT, SIG_DFL);
    366 			for (i = 0; environ[i] != (char *)0; i++)
    367 				env[i] = environ[i];
    368 			makeenv(&env[i]);
    369 
    370 			limit.rlim_max = RLIM_INFINITY;
    371 			limit.rlim_cur = RLIM_INFINITY;
    372 			(void)setrlimit(RLIMIT_CPU, &limit);
    373 			execle(LO, "login", "-p", "--", name, (char *)0, env);
    374 			syslog(LOG_ERR, "%s: %m", LO);
    375 			exit(1);
    376 		}
    377 		alarm(0);
    378 		signal(SIGALRM, SIG_DFL);
    379 		signal(SIGINT, SIG_IGN);
    380 		if (NX && *NX)
    381 			tname = NX;
    382 		unlink(lockfile);
    383 	}
    384 }
    385 
    386 static int
    387 getname()
    388 {
    389 	int c;
    390 	char *np;
    391 	char cs;
    392 
    393 	/*
    394 	 * Interrupt may happen if we use CBREAK mode
    395 	 */
    396 	if (setjmp(intrupt)) {
    397 		signal(SIGINT, SIG_IGN);
    398 		return (0);
    399 	}
    400 	signal(SIGINT, interrupt);
    401 	setflags(1);
    402 	prompt();
    403 	if (PF > 0) {
    404 		oflush();
    405 		sleep(PF);
    406 		PF = 0;
    407 	}
    408 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    409 		syslog(LOG_ERR, "%s: %m", ttyn);
    410 		exit(1);
    411 	}
    412 	crmod = digit = lower = upper = 0;
    413 	np = name;
    414 	for (;;) {
    415 		oflush();
    416 		if (read(STDIN_FILENO, &cs, 1) <= 0)
    417 			exit(0);
    418 		if ((c = cs&0177) == 0)
    419 			return (0);
    420 		if (c == EOT)
    421 			exit(1);
    422 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
    423 			putf("\r\n");
    424 			break;
    425 		}
    426 		if (islower(c))
    427 			lower = 1;
    428 		else if (isupper(c))
    429 			upper = 1;
    430 		else if (c == ERASE || c == '#' || c == '\b') {
    431 			if (np > name) {
    432 				np--;
    433 				if (cfgetospeed(&tmode) >= 1200)
    434 					xputs("\b \b");
    435 				else
    436 					putchr(cs);
    437 			}
    438 			continue;
    439 		} else if (c == KILL || c == '@') {
    440 			putchr(cs);
    441 			putchr('\r');
    442 			if (cfgetospeed(&tmode) < 1200)
    443 				putchr('\n');
    444 			/* this is the way they do it down under ... */
    445 			else if (np > name)
    446 				xputs(
    447 				    "                                     \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);
    467 }
    468 
    469 static void
    470 putpad(s)
    471 	const char *s;
    472 {
    473 	int 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 	xputs(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 xputs(s)
    509 	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 	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 				xputs(ttyn);
    574 			else
    575 				xputs(&slash[1]);
    576 			break;
    577 
    578 		case 'h':
    579 			xputs(editedhost);
    580 			break;
    581 
    582 		case 'd': {
    583 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
    584 
    585 			fmt[4] = 'M';		/* I *hate* SCCS... */
    586 			(void)time(&t);
    587 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
    588 			xputs(db);
    589 			break;
    590 
    591 		case 's':
    592 			xputs(kerninfo.sysname);
    593 			break;
    594 
    595 		case 'm':
    596 			xputs(kerninfo.machine);
    597 			break;
    598 
    599 		case 'r':
    600 			xputs(kerninfo.release);
    601 			break;
    602 
    603 		case 'v':
    604 			xputs(kerninfo.version);
    605 			break;
    606 		}
    607 
    608 		case '%':
    609 			putchr('%');
    610 			break;
    611 		}
    612 		cp++;
    613 	}
    614 }
    615