Home | History | Annotate | Line # | Download | only in getty
main.c revision 1.23
      1 /*	$NetBSD: main.c,v 1.23 1997/10/19 23:46:08 cjs 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.23 1997/10/19 23:46:08 cjs 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((char *));
    173 static void	putpad __P((char *));
    174 static void	puts __P((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 				puts("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 					puts("\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 				puts("                                     \r");
    446 			prompt();
    447 			np = name;
    448 			continue;
    449 		} else if (isdigit(c))
    450 			digit++;
    451 		if (IG && (c <= ' ' || c > 0176))
    452 			continue;
    453 		*np++ = c;
    454 		putchr(cs);
    455 	}
    456 	signal(SIGINT, SIG_IGN);
    457 	*np = 0;
    458 	if (c == '\r')
    459 		crmod = 1;
    460 	if ((upper && !lower && !LC) || UC)
    461 		for (np = name; *np; np++)
    462 			if (isupper(*np))
    463 				*np = tolower(*np);
    464 	return (1);
    465 }
    466 
    467 static void
    468 putpad(s)
    469 	register char *s;
    470 {
    471 	register pad = 0;
    472 	speed_t ospeed = cfgetospeed(&tmode);
    473 
    474 	if (isdigit(*s)) {
    475 		while (isdigit(*s)) {
    476 			pad *= 10;
    477 			pad += *s++ - '0';
    478 		}
    479 		pad *= 10;
    480 		if (*s == '.' && isdigit(s[1])) {
    481 			pad += s[1] - '0';
    482 			s += 2;
    483 		}
    484 	}
    485 
    486 	puts(s);
    487 	/*
    488 	 * If no delay needed, or output speed is
    489 	 * not comprehensible, then don't try to delay.
    490 	 */
    491 	if (pad == 0 || ospeed <= 0)
    492 		return;
    493 
    494 	/*
    495 	 * Round up by a half a character frame, and then do the delay.
    496 	 * Too bad there are no user program accessible programmed delays.
    497 	 * Transmitting pad characters slows many terminals down and also
    498 	 * loads the system.
    499 	 */
    500 	pad = (pad * ospeed + 50000) / 100000;
    501 	while (pad--)
    502 		putchr(*PC);
    503 }
    504 
    505 static void
    506 puts(s)
    507 	register char *s;
    508 {
    509 	while (*s)
    510 		putchr(*s++);
    511 }
    512 
    513 char	outbuf[OBUFSIZ];
    514 int	obufcnt = 0;
    515 
    516 static void
    517 putchr(cc)
    518 	int cc;
    519 {
    520 	char c;
    521 
    522 	c = cc;
    523 	if (!NP) {
    524 		c |= partab[c&0177] & 0200;
    525 		if (OP)
    526 			c ^= 0200;
    527 	}
    528 	if (!UB) {
    529 		outbuf[obufcnt++] = c;
    530 		if (obufcnt >= OBUFSIZ)
    531 			oflush();
    532 	} else
    533 		write(STDOUT_FILENO, &c, 1);
    534 }
    535 
    536 static void
    537 oflush()
    538 {
    539 	if (obufcnt)
    540 		write(STDOUT_FILENO, outbuf, obufcnt);
    541 	obufcnt = 0;
    542 }
    543 
    544 static void
    545 prompt()
    546 {
    547 
    548 	putf(LM);
    549 	if (CO)
    550 		putchr('\n');
    551 }
    552 
    553 static void
    554 putf(cp)
    555 	register char *cp;
    556 {
    557 	extern char editedhost[];
    558 	time_t t;
    559 	char *slash, db[100];
    560 
    561 	while (*cp) {
    562 		if (*cp != '%') {
    563 			putchr(*cp++);
    564 			continue;
    565 		}
    566 		switch (*++cp) {
    567 
    568 		case 't':
    569 			slash = strrchr(ttyn, '/');
    570 			if (slash == (char *) 0)
    571 				puts(ttyn);
    572 			else
    573 				puts(&slash[1]);
    574 			break;
    575 
    576 		case 'h':
    577 			puts(editedhost);
    578 			break;
    579 
    580 		case 'd': {
    581 			static char fmt[] = "%l:% %p on %A, %d %B %Y";
    582 
    583 			fmt[4] = 'M';		/* I *hate* SCCS... */
    584 			(void)time(&t);
    585 			(void)strftime(db, sizeof(db), fmt, localtime(&t));
    586 			puts(db);
    587 			break;
    588 
    589 		case 's':
    590 			puts(kerninfo.sysname);
    591 			break;
    592 
    593 		case 'm':
    594 			puts(kerninfo.machine);
    595 			break;
    596 
    597 		case 'r':
    598 			puts(kerninfo.release);
    599 			break;
    600 
    601 		case 'v':
    602 			puts(kerninfo.version);
    603 			break;
    604 		}
    605 
    606 		case '%':
    607 			putchr('%');
    608 			break;
    609 		}
    610 		cp++;
    611 	}
    612 }
    613