Home | History | Annotate | Line # | Download | only in getty
main.c revision 1.24
      1 /*	$NetBSD: main.c,v 1.24 1997/11/18 21:29:11 thorpej 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.24 1997/11/18 21:29:11 thorpej 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];
     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_CONS|LOG_PID, LOG_AUTH);
    196 	gethostname(hostname, sizeof(hostname));
    197 	if (hostname[0] == '\0')
    198 		strcpy(hostname, "Amnesiac");
    199 	uname(&kerninfo);
    200 
    201 	if (__progname[0] == 'u' && __progname[1] == 'u')
    202 		uugetty = 1;
    203 
    204 	/*
    205 	 * Find id of uucp login (if present) so we can chown tty properly.
    206 	 */
    207 	if (uugetty && (pw = getpwnam("uucp")))
    208 		ttyowner = pw->pw_uid;
    209 	else
    210 		ttyowner = 0;
    211 
    212 	/*
    213 	 * Limit running time to deal with broken or dead lines.
    214 	 */
    215 	(void)signal(SIGXCPU, timeoverrun);
    216 	limit.rlim_max = RLIM_INFINITY;
    217 	limit.rlim_cur = GETTY_TIMEOUT;
    218 	(void)setrlimit(RLIMIT_CPU, &limit);
    219 
    220 	/*
    221 	 * The following is a work around for vhangup interactions
    222 	 * which cause great problems getting window systems started.
    223 	 * If the tty line is "-", we do the old style getty presuming
    224 	 * that the file descriptors are already set up for us.
    225 	 * J. Gettys - MIT Project Athena.
    226 	 */
    227 	if (argc <= 2 || strcmp(argv[2], "-") == 0) {
    228 	    strncpy(ttyn, ttyname(0), 32);
    229 	    ttyn[31] = (char)NULL;
    230 	}
    231 	else {
    232 	    int i;
    233 
    234 	    strcpy(ttyn, dev);
    235 	    strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
    236 
    237 	    if (uugetty)  {
    238 		chown(ttyn, ttyowner, 0);
    239 		strcpy(lockfile, _PATH_LOCK);
    240 		strncat(lockfile, argv[2], sizeof(lockfile)-sizeof(_PATH_LOCK));
    241 		/* wait for lockfiles to go away before we try to open */
    242 		if ( pidlock(lockfile, 0, 0, 0) != 0 )  {
    243 		    syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
    244 		    exit(1);
    245 		}
    246 		unlink(lockfile);
    247 	    }
    248 	    if (strcmp(argv[0], "+") != 0) {
    249 		chown(ttyn, ttyowner, 0);
    250 		chmod(ttyn, 0600);
    251 		revoke(ttyn);
    252 		if (ttyaction(ttyn, "getty", "root"))
    253 			syslog(LOG_ERR,"%s: ttyaction failed", ttyn);
    254 		/*
    255 		 * Delay the open so DTR stays down long enough to be detected.
    256 		 */
    257 		sleep(2);
    258 		while ((i = open(ttyn, O_RDWR)) == -1) {
    259 			if ((repcnt % 10 == 0) &&
    260 			    (errno != ENXIO || !failopenlogged)) {
    261 				syslog(LOG_ERR, "%s: %m", ttyn);
    262 				closelog();
    263 				failopenlogged = 1;
    264 			}
    265 			repcnt++;
    266 			sleep(60);
    267 		}
    268 		if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
    269 			syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
    270 			exit(1);
    271 		}
    272 		(void) chown(lockfile, ttyowner, 0);
    273 		login_tty(i);
    274 	    }
    275 	}
    276 
    277 	/* Start with default tty settings */
    278 	if (tcgetattr(0, &tmode) < 0) {
    279 		syslog(LOG_ERR, "%s: %m", ttyn);
    280 		exit(1);
    281 	}
    282 	omode = tmode;
    283 
    284 	gettable("default", defent);
    285 	gendefaults();
    286 	tname = "default";
    287 	if (argc > 1)
    288 		tname = argv[1];
    289 	for (;;) {
    290 		int off;
    291 
    292 		gettable(tname, tabent);
    293 		if (OPset || EPset || APset)
    294 			APset++, OPset++, EPset++;
    295 		setdefaults();
    296 		off = 0;
    297 		(void)tcflush(0, TCIOFLUSH);	/* clear out the crap */
    298 		ioctl(0, FIONBIO, &off);	/* turn off non-blocking mode */
    299 		ioctl(0, FIOASYNC, &off);	/* ditto for async mode */
    300 
    301 		if (IS)
    302 			cfsetispeed(&tmode, IS);
    303 		else if (SP)
    304 			cfsetispeed(&tmode, SP);
    305 		if (OS)
    306 			cfsetospeed(&tmode, OS);
    307 		else if (SP)
    308 			cfsetospeed(&tmode, SP);
    309 		setflags(0);
    310 		setchars();
    311 		if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    312 			syslog(LOG_ERR, "%s: %m", ttyn);
    313 			exit(1);
    314 		}
    315 		if (AB) {
    316 			tname = autobaud();
    317 			continue;
    318 		}
    319 		if (PS) {
    320 			tname = portselector();
    321 			continue;
    322 		}
    323 		if (CL && *CL)
    324 			putpad(CL);
    325 		edithost(HE);
    326 		if (IM && *IM)
    327 			putf(IM);
    328 		if (setjmp(timeout)) {
    329 			tmode.c_ispeed = tmode.c_ospeed = 0;
    330 			(void)tcsetattr(0, TCSANOW, &tmode);
    331 			exit(1);
    332 		}
    333 		if (TO) {
    334 			signal(SIGALRM, dingdong);
    335 			alarm(TO);
    336 		}
    337 		if (getname()) {
    338 			register int i;
    339 
    340 			oflush();
    341 			alarm(0);
    342 			signal(SIGALRM, SIG_DFL);
    343 			if (name[0] == '-') {
    344 				xputs("user names may not start with '-'.");
    345 				continue;
    346 			}
    347 			if (!(upper || lower || digit))
    348 				continue;
    349 			setflags(2);
    350 			if (crmod) {
    351 				tmode.c_iflag |= ICRNL;
    352 				tmode.c_oflag |= ONLCR;
    353 			}
    354 #if XXX
    355 			if (upper || UC)
    356 				tmode.sg_flags |= LCASE;
    357 			if (lower || LC)
    358 				tmode.sg_flags &= ~LCASE;
    359 #endif
    360 			if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    361 				syslog(LOG_ERR, "%s: %m", ttyn);
    362 				exit(1);
    363 			}
    364 			signal(SIGINT, SIG_DFL);
    365 			for (i = 0; environ[i] != (char *)0; i++)
    366 				env[i] = environ[i];
    367 			makeenv(&env[i]);
    368 
    369 			limit.rlim_max = RLIM_INFINITY;
    370 			limit.rlim_cur = RLIM_INFINITY;
    371 			(void)setrlimit(RLIMIT_CPU, &limit);
    372 			execle(LO, "login", "-p", "--", name, (char *)0, env);
    373 			syslog(LOG_ERR, "%s: %m", LO);
    374 			exit(1);
    375 		}
    376 		alarm(0);
    377 		signal(SIGALRM, SIG_DFL);
    378 		signal(SIGINT, SIG_IGN);
    379 		if (NX && *NX)
    380 			tname = NX;
    381 		unlink(lockfile);
    382 	}
    383 }
    384 
    385 static int
    386 getname()
    387 {
    388 	register int c;
    389 	register char *np;
    390 	char cs;
    391 
    392 	/*
    393 	 * Interrupt may happen if we use CBREAK mode
    394 	 */
    395 	if (setjmp(intrupt)) {
    396 		signal(SIGINT, SIG_IGN);
    397 		return (0);
    398 	}
    399 	signal(SIGINT, interrupt);
    400 	setflags(1);
    401 	prompt();
    402 	if (PF > 0) {
    403 		oflush();
    404 		sleep(PF);
    405 		PF = 0;
    406 	}
    407 	if (tcsetattr(0, TCSANOW, &tmode) < 0) {
    408 		syslog(LOG_ERR, "%s: %m", ttyn);
    409 		exit(1);
    410 	}
    411 	crmod = digit = lower = upper = 0;
    412 	np = name;
    413 	for (;;) {
    414 		oflush();
    415 		if (read(STDIN_FILENO, &cs, 1) <= 0)
    416 			exit(0);
    417 		if ((c = cs&0177) == 0)
    418 			return (0);
    419 		if (c == EOT)
    420 			exit(1);
    421 		if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
    422 			putf("\r\n");
    423 			break;
    424 		}
    425 		if (islower(c))
    426 			lower = 1;
    427 		else if (isupper(c))
    428 			upper = 1;
    429 		else if (c == ERASE || c == '#' || c == '\b') {
    430 			if (np > name) {
    431 				np--;
    432 				if (cfgetospeed(&tmode) >= 1200)
    433 					xputs("\b \b");
    434 				else
    435 					putchr(cs);
    436 			}
    437 			continue;
    438 		} else if (c == KILL || c == '@') {
    439 			putchr(cs);
    440 			putchr('\r');
    441 			if (cfgetospeed(&tmode) < 1200)
    442 				putchr('\n');
    443 			/* this is the way they do it down under ... */
    444 			else if (np > name)
    445 				xputs(
    446 				    "                                     \r");
    447 			prompt();
    448 			np = name;
    449 			continue;
    450 		} else if (isdigit(c))
    451 			digit++;
    452 		if (IG && (c <= ' ' || c > 0176))
    453 			continue;
    454 		*np++ = c;
    455 		putchr(cs);
    456 	}
    457 	signal(SIGINT, SIG_IGN);
    458 	*np = 0;
    459 	if (c == '\r')
    460 		crmod = 1;
    461 	if ((upper && !lower && !LC) || UC)
    462 		for (np = name; *np; np++)
    463 			if (isupper(*np))
    464 				*np = tolower(*np);
    465 	return (1);
    466 }
    467 
    468 static void
    469 putpad(s)
    470 	register const char *s;
    471 {
    472 	register pad = 0;
    473 	speed_t ospeed = cfgetospeed(&tmode);
    474 
    475 	if (isdigit(*s)) {
    476 		while (isdigit(*s)) {
    477 			pad *= 10;
    478 			pad += *s++ - '0';
    479 		}
    480 		pad *= 10;
    481 		if (*s == '.' && isdigit(s[1])) {
    482 			pad += s[1] - '0';
    483 			s += 2;
    484 		}
    485 	}
    486 
    487 	xputs(s);
    488 	/*
    489 	 * If no delay needed, or output speed is
    490 	 * not comprehensible, then don't try to delay.
    491 	 */
    492 	if (pad == 0 || ospeed <= 0)
    493 		return;
    494 
    495 	/*
    496 	 * Round up by a half a character frame, and then do the delay.
    497 	 * Too bad there are no user program accessible programmed delays.
    498 	 * Transmitting pad characters slows many terminals down and also
    499 	 * loads the system.
    500 	 */
    501 	pad = (pad * ospeed + 50000) / 100000;
    502 	while (pad--)
    503 		putchr(*PC);
    504 }
    505 
    506 static void
    507 xputs(s)
    508 	register const char *s;
    509 {
    510 	while (*s)
    511 		putchr(*s++);
    512 }
    513 
    514 char	outbuf[OBUFSIZ];
    515 int	obufcnt = 0;
    516 
    517 static void
    518 putchr(cc)
    519 	int cc;
    520 {
    521 	char c;
    522 
    523 	c = cc;
    524 	if (!NP) {
    525 		c |= partab[c&0177] & 0200;
    526 		if (OP)
    527 			c ^= 0200;
    528 	}
    529 	if (!UB) {
    530 		outbuf[obufcnt++] = c;
    531 		if (obufcnt >= OBUFSIZ)
    532 			oflush();
    533 	} else
    534 		write(STDOUT_FILENO, &c, 1);
    535 }
    536 
    537 static void
    538 oflush()
    539 {
    540 	if (obufcnt)
    541 		write(STDOUT_FILENO, outbuf, obufcnt);
    542 	obufcnt = 0;
    543 }
    544 
    545 static void
    546 prompt()
    547 {
    548 
    549 	putf(LM);
    550 	if (CO)
    551 		putchr('\n');
    552 }
    553 
    554 static void
    555 putf(cp)
    556 	register const char *cp;
    557 {
    558 	extern char editedhost[];
    559 	time_t t;
    560 	char *slash, db[100];
    561 
    562 	while (*cp) {
    563 		if (*cp != '%') {
    564 			putchr(*cp++);
    565 			continue;
    566 		}
    567 		switch (*++cp) {
    568 
    569 		case 't':
    570 			slash = strrchr(ttyn, '/');
    571 			if (slash == (char *) 0)
    572 				xputs(ttyn);
    573 			else
    574 				xputs(&slash[1]);
    575 			break;
    576 
    577 		case 'h':
    578 			xputs(editedhost);
    579 			break;
    580 
    581 		case 'd': {
    582 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
    583 
    584 			fmt[4] = 'M';		/* I *hate* SCCS... */
    585 			(void)time(&t);
    586 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
    587 			xputs(db);
    588 			break;
    589 
    590 		case 's':
    591 			xputs(kerninfo.sysname);
    592 			break;
    593 
    594 		case 'm':
    595 			xputs(kerninfo.machine);
    596 			break;
    597 
    598 		case 'r':
    599 			xputs(kerninfo.release);
    600 			break;
    601 
    602 		case 'v':
    603 			xputs(kerninfo.version);
    604 			break;
    605 		}
    606 
    607 		case '%':
    608 			putchr('%');
    609 			break;
    610 		}
    611 		cp++;
    612 	}
    613 }
    614