Home | History | Annotate | Line # | Download | only in telnetd
sys_term.c revision 1.36
      1 /*	$NetBSD: sys_term.c,v 1.36 2003/07/14 15:55:54 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1989, 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 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)sys_term.c	8.4+1 (Berkeley) 5/30/95";
     40 #else
     41 __RCSID("$NetBSD: sys_term.c,v 1.36 2003/07/14 15:55:54 itojun Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 #include "telnetd.h"
     46 #include "pathnames.h"
     47 
     48 #include <util.h>
     49 
     50 #include <sys/cdefs.h>
     51 
     52 #ifdef	UTMPX
     53 #include <utmpx.h>
     54 struct	utmpx wtmp;
     55 #else
     56 #include <utmp.h>
     57 struct	utmp wtmp;
     58 #endif /* UTMPX */
     59 
     60 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
     61 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
     62 
     63 struct termios termbuf, termbuf2;	/* pty control structure */
     64 
     65 void getptyslave __P((void));
     66 int cleanopen __P((char *));
     67 char **addarg __P((char **, char *));
     68 void scrub_env __P((void));
     69 int getent __P((char *, char *));
     70 char *getstr __P((const char *, char **));
     71 #ifdef KRB5
     72 extern void kerberos5_cleanup __P((void));
     73 #endif
     74 
     75 /*
     76  * init_termbuf()
     77  * copy_termbuf(cp)
     78  * set_termbuf()
     79  *
     80  * These three routines are used to get and set the "termbuf" structure
     81  * to and from the kernel.  init_termbuf() gets the current settings.
     82  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
     83  * set_termbuf() writes the structure into the kernel.
     84  */
     85 
     86 void
     87 init_termbuf()
     88 {
     89 	(void) tcgetattr(pty, &termbuf);
     90 	termbuf2 = termbuf;
     91 }
     92 
     93 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
     94 void
     95 copy_termbuf(cp, len)
     96 	char *cp;
     97 	int len;
     98 {
     99 	if (len > sizeof(termbuf))
    100 		len = sizeof(termbuf);
    101 	memmove((char *)&termbuf, cp, len);
    102 	termbuf2 = termbuf;
    103 }
    104 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
    105 
    106 void
    107 set_termbuf()
    108 {
    109 	/*
    110 	 * Only make the necessary changes.
    111 	 */
    112 	if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
    113 		(void) tcsetattr(pty, TCSANOW, &termbuf);
    114 }
    115 
    116 
    117 /*
    118  * spcset(func, valp, valpp)
    119  *
    120  * This function takes various special characters (func), and
    121  * sets *valp to the current value of that character, and
    122  * *valpp to point to where in the "termbuf" structure that
    123  * value is kept.
    124  *
    125  * It returns the SLC_ level of support for this function.
    126  */
    127 
    128 
    129 int
    130 spcset(func, valp, valpp)
    131 	int func;
    132 	cc_t *valp;
    133 	cc_t **valpp;
    134 {
    135 
    136 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
    137 			*valpp = &termbuf.c_cc[a]; \
    138 			return(b);
    139 #define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
    140 
    141 	switch(func) {
    142 	case SLC_EOF:
    143 		setval(VEOF, SLC_VARIABLE);
    144 	case SLC_EC:
    145 		setval(VERASE, SLC_VARIABLE);
    146 	case SLC_EL:
    147 		setval(VKILL, SLC_VARIABLE);
    148 	case SLC_IP:
    149 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    150 	case SLC_ABORT:
    151 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    152 	case SLC_XON:
    153 		setval(VSTART, SLC_VARIABLE);
    154 	case SLC_XOFF:
    155 		setval(VSTOP, SLC_VARIABLE);
    156 	case SLC_EW:
    157 		setval(VWERASE, SLC_VARIABLE);
    158 	case SLC_RP:
    159 		setval(VREPRINT, SLC_VARIABLE);
    160 	case SLC_LNEXT:
    161 		setval(VLNEXT, SLC_VARIABLE);
    162 	case SLC_AO:
    163 		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
    164 	case SLC_SUSP:
    165 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
    166 	case SLC_FORW1:
    167 		setval(VEOL, SLC_VARIABLE);
    168 	case SLC_FORW2:
    169 		setval(VEOL2, SLC_VARIABLE);
    170 	case SLC_AYT:
    171 		setval(VSTATUS, SLC_VARIABLE);
    172 
    173 	case SLC_BRK:
    174 	case SLC_SYNCH:
    175 	case SLC_EOR:
    176 		defval(0);
    177 
    178 	default:
    179 		*valp = 0;
    180 		*valpp = 0;
    181 		return(SLC_NOSUPPORT);
    182 	}
    183 }
    184 
    185 
    186 /*
    187  * getpty()
    188  *
    189  * Allocate a pty.  As a side effect, the external character
    190  * array "line" contains the name of the slave side.
    191  *
    192  * Returns the file descriptor of the opened pty.
    193  */
    194 #ifndef	__GNUC__
    195 char *line = NULL16STR;
    196 #else
    197 static char Xline[] = NULL16STR;
    198 char *line = Xline;
    199 #endif
    200 
    201 
    202 static int ptyslavefd; /* for cleanopen() */
    203 
    204 int
    205 getpty(ptynum)
    206 int *ptynum;
    207 {
    208 	int ptyfd;
    209 
    210 	ptyfd = openpty(ptynum, &ptyslavefd, line, NULL, NULL);
    211 	if (ptyfd == 0)
    212 		return *ptynum;
    213 	ptyslavefd = -1;
    214 	return (-1);
    215 }
    216 
    217 #ifdef	LINEMODE
    218 /*
    219  * tty_flowmode()	Find out if flow control is enabled or disabled.
    220  * tty_linemode()	Find out if linemode (external processing) is enabled.
    221  * tty_setlinemod(on)	Turn on/off linemode.
    222  * tty_isecho()		Find out if echoing is turned on.
    223  * tty_setecho(on)	Enable/disable character echoing.
    224  * tty_israw()		Find out if terminal is in RAW mode.
    225  * tty_binaryin(on)	Turn on/off BINARY on input.
    226  * tty_binaryout(on)	Turn on/off BINARY on output.
    227  * tty_isediting()	Find out if line editing is enabled.
    228  * tty_istrapsig()	Find out if signal trapping is enabled.
    229  * tty_setedit(on)	Turn on/off line editing.
    230  * tty_setsig(on)	Turn on/off signal trapping.
    231  * tty_issofttab()	Find out if tab expansion is enabled.
    232  * tty_setsofttab(on)	Turn on/off soft tab expansion.
    233  * tty_islitecho()	Find out if typed control chars are echoed literally
    234  * tty_setlitecho()	Turn on/off literal echo of control chars
    235  * tty_tspeed(val)	Set transmit speed to val.
    236  * tty_rspeed(val)	Set receive speed to val.
    237  */
    238 
    239 
    240 int
    241 tty_linemode()
    242 {
    243 	return(termbuf.c_lflag & EXTPROC);
    244 }
    245 
    246 void
    247 tty_setlinemode(on)
    248 	int on;
    249 {
    250 	set_termbuf();
    251 	(void) ioctl(pty, TIOCEXT, (char *)&on);
    252 	init_termbuf();
    253 }
    254 #endif	/* LINEMODE */
    255 
    256 int
    257 tty_isecho()
    258 {
    259 	return (termbuf.c_lflag & ECHO);
    260 }
    261 
    262 int
    263 tty_flowmode()
    264 {
    265 	return((termbuf.c_iflag & IXON) ? 1 : 0);
    266 }
    267 
    268 int
    269 tty_restartany()
    270 {
    271 	return((termbuf.c_iflag & IXANY) ? 1 : 0);
    272 }
    273 
    274 void
    275 tty_setecho(on)
    276 	int on;
    277 {
    278 	if (on)
    279 		termbuf.c_lflag |= ECHO;
    280 	else
    281 		termbuf.c_lflag &= ~ECHO;
    282 }
    283 
    284 int
    285 tty_israw()
    286 {
    287 	return(!(termbuf.c_lflag & ICANON));
    288 }
    289 
    290 void
    291 tty_binaryin(on)
    292 	int on;
    293 {
    294 	if (on) {
    295 		termbuf.c_iflag &= ~ISTRIP;
    296 	} else {
    297 		termbuf.c_iflag |= ISTRIP;
    298 	}
    299 }
    300 
    301 void
    302 tty_binaryout(on)
    303 	int on;
    304 {
    305 	if (on) {
    306 		termbuf.c_cflag &= ~(CSIZE|PARENB);
    307 		termbuf.c_cflag |= CS8;
    308 		termbuf.c_oflag &= ~OPOST;
    309 	} else {
    310 		termbuf.c_cflag &= ~CSIZE;
    311 		termbuf.c_cflag |= CS7|PARENB;
    312 		termbuf.c_oflag |= OPOST;
    313 	}
    314 }
    315 
    316 int
    317 tty_isbinaryin()
    318 {
    319 	return(!(termbuf.c_iflag & ISTRIP));
    320 }
    321 
    322 int
    323 tty_isbinaryout()
    324 {
    325 	return(!(termbuf.c_oflag&OPOST));
    326 }
    327 
    328 #ifdef	LINEMODE
    329 int
    330 tty_isediting()
    331 {
    332 	return(termbuf.c_lflag & ICANON);
    333 }
    334 
    335 int
    336 tty_istrapsig()
    337 {
    338 	return(termbuf.c_lflag & ISIG);
    339 }
    340 
    341 void
    342 tty_setedit(on)
    343 	int on;
    344 {
    345 	if (on)
    346 		termbuf.c_lflag |= ICANON;
    347 	else
    348 		termbuf.c_lflag &= ~ICANON;
    349 }
    350 
    351 void
    352 tty_setsig(on)
    353 	int on;
    354 {
    355 	if (on)
    356 		termbuf.c_lflag |= ISIG;
    357 	else
    358 		termbuf.c_lflag &= ~ISIG;
    359 }
    360 #endif	/* LINEMODE */
    361 
    362 int
    363 tty_issofttab()
    364 {
    365 # ifdef	OXTABS
    366 	return (termbuf.c_oflag & OXTABS);
    367 # endif
    368 # ifdef	TABDLY
    369 	return ((termbuf.c_oflag & TABDLY) == TAB3);
    370 # endif
    371 }
    372 
    373 void
    374 tty_setsofttab(on)
    375 	int on;
    376 {
    377 	if (on) {
    378 # ifdef	OXTABS
    379 		termbuf.c_oflag |= OXTABS;
    380 # endif
    381 # ifdef	TABDLY
    382 		termbuf.c_oflag &= ~TABDLY;
    383 		termbuf.c_oflag |= TAB3;
    384 # endif
    385 	} else {
    386 # ifdef	OXTABS
    387 		termbuf.c_oflag &= ~OXTABS;
    388 # endif
    389 # ifdef	TABDLY
    390 		termbuf.c_oflag &= ~TABDLY;
    391 		termbuf.c_oflag |= TAB0;
    392 # endif
    393 	}
    394 }
    395 
    396 int
    397 tty_islitecho()
    398 {
    399 # ifdef	ECHOCTL
    400 	return (!(termbuf.c_lflag & ECHOCTL));
    401 # endif
    402 # ifdef	TCTLECH
    403 	return (!(termbuf.c_lflag & TCTLECH));
    404 # endif
    405 # if	!defined(ECHOCTL) && !defined(TCTLECH)
    406 	return (0);	/* assumes ctl chars are echoed '^x' */
    407 # endif
    408 }
    409 
    410 void
    411 tty_setlitecho(on)
    412 	int on;
    413 {
    414 # ifdef	ECHOCTL
    415 	if (on)
    416 		termbuf.c_lflag &= ~ECHOCTL;
    417 	else
    418 		termbuf.c_lflag |= ECHOCTL;
    419 # endif
    420 # ifdef	TCTLECH
    421 	if (on)
    422 		termbuf.c_lflag &= ~TCTLECH;
    423 	else
    424 		termbuf.c_lflag |= TCTLECH;
    425 # endif
    426 }
    427 
    428 int
    429 tty_iscrnl()
    430 {
    431 	return (termbuf.c_iflag & ICRNL);
    432 }
    433 
    434 void
    435 tty_tspeed(val)
    436 	int val;
    437 {
    438 	cfsetospeed(&termbuf, val);
    439 }
    440 
    441 void
    442 tty_rspeed(val)
    443 	int val;
    444 {
    445 	cfsetispeed(&termbuf, val);
    446 }
    447 
    448 
    449 
    450 
    451 /*
    452  * getptyslave()
    453  *
    454  * Open the slave side of the pty, and do any initialization
    455  * that is necessary.  The return value is a file descriptor
    456  * for the slave side.
    457  */
    458 extern int def_tspeed, def_rspeed;
    459 	extern int def_row, def_col;
    460 
    461     void
    462 getptyslave()
    463 {
    464 	register int t = -1;
    465 
    466 #ifdef	LINEMODE
    467 	int waslm;
    468 #endif
    469 	struct winsize ws;
    470 	/*
    471 	 * Opening the slave side may cause initilization of the
    472 	 * kernel tty structure.  We need remember the state of
    473 	 * 	if linemode was turned on
    474 	 *	terminal window size
    475 	 *	terminal speed
    476 	 * so that we can re-set them if we need to.
    477 	 */
    478 #ifdef	LINEMODE
    479 	waslm = tty_linemode();
    480 #endif
    481 
    482 	/*
    483 	 * Make sure that we don't have a controlling tty, and
    484 	 * that we are the session (process group) leader.
    485 	 */
    486 	t = open(_PATH_TTY, O_RDWR);
    487 	if (t >= 0) {
    488 		(void) ioctl(t, TIOCNOTTY, (char *)0);
    489 		(void) close(t);
    490 	}
    491 
    492 
    493 
    494 	t = cleanopen(line);
    495 	if (t < 0)
    496 		fatalperror(net, line);
    497 
    498 
    499 	/*
    500 	 * set up the tty modes as we like them to be.
    501 	 */
    502 	init_termbuf();
    503 	if (def_row || def_col) {
    504 		memset((char *)&ws, 0, sizeof(ws));
    505 		ws.ws_col = def_col;
    506 		ws.ws_row = def_row;
    507 		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
    508 	}
    509 
    510 	/*
    511 	 * Settings for sgtty based systems
    512 	 */
    513 
    514 	/*
    515 	 * Settings for all other termios/termio based
    516 	 * systems, other than 4.4BSD.  In 4.4BSD the
    517 	 * kernel does the initial terminal setup.
    518 	 */
    519 	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
    520 	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
    521 #ifdef	LINEMODE
    522 	if (waslm)
    523 		tty_setlinemode(1);
    524 #endif	/* LINEMODE */
    525 
    526 	/*
    527 	 * Set the tty modes, and make this our controlling tty.
    528 	 */
    529 	set_termbuf();
    530 	if (login_tty(t) == -1)
    531 		fatalperror(net, "login_tty");
    532 	if (net > 2)
    533 		(void) close(net);
    534 	if (pty > 2) {
    535 		(void) close(pty);
    536 		pty = -1;
    537 	}
    538 }
    539 
    540 /*
    541  * Open the specified slave side of the pty,
    542  * making sure that we have a clean tty.
    543  */
    544 int
    545 cleanopen(ttyline)
    546 	char *ttyline;
    547 {
    548 	return ptyslavefd;
    549 }
    550 
    551 /*
    552  * startslave(host)
    553  *
    554  * Given a hostname, do whatever
    555  * is necessary to startup the login process on the slave side of the pty.
    556  */
    557 
    558 /* ARGSUSED */
    559 void
    560 startslave(host, autologin, autoname)
    561 	char *host;
    562 	int autologin;
    563 	char *autoname;
    564 {
    565 	register int i;
    566 
    567 #ifdef AUTHENTICATION
    568 	if (!autoname || !autoname[0])
    569 		autologin = 0;
    570 
    571 	if (autologin < auth_level) {
    572 		fatal(net, "Authorization failed");
    573 		exit(1);
    574 	}
    575 #endif
    576 
    577 
    578 	if ((i = fork()) < 0)
    579 		fatalperror(net, "fork");
    580 	if (i) {
    581 	} else {
    582 		getptyslave();
    583 		start_login(host, autologin, autoname);
    584 		/*NOTREACHED*/
    585 	}
    586 }
    587 
    588 char	*envinit[3];
    589 
    590 void
    591 init_env()
    592 {
    593 	char **envp;
    594 
    595 	envp = envinit;
    596 	if ((*envp = getenv("TZ")))
    597 		*envp++ -= 3;
    598 	*envp = 0;
    599 	environ = envinit;
    600 }
    601 
    602 
    603 /*
    604  * start_login(host)
    605  *
    606  * Assuming that we are now running as a child processes, this
    607  * function will turn us into the login process.
    608  */
    609 extern char *gettyname;
    610 
    611 void
    612 start_login(host, autologin, name)
    613 	char *host;
    614 	int autologin;
    615 	char *name;
    616 {
    617 	register char **argv;
    618 #define	TABBUFSIZ	512
    619 	char	defent[TABBUFSIZ];
    620 	char	defstrs[TABBUFSIZ];
    621 #undef	TABBUFSIZ
    622 	const char *loginprog = NULL;
    623 #ifdef	UTMPX
    624 	register int pid = getpid();
    625 	struct utmpx utmpx;
    626 #endif
    627 
    628 #ifdef	UTMPX
    629 	/*
    630 	 * Create utmp entry for child
    631 	 */
    632 
    633 	memset(&utmpx, 0, sizeof(utmpx));
    634 	SCPYN(utmpx.ut_user, ".telnet");
    635 	SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
    636 	utmpx.ut_pid = pid;
    637 	utmpx.ut_id[0] = 't';
    638 	utmpx.ut_id[1] = 'n';
    639 	utmpx.ut_id[2] = SC_WILDC;
    640 	utmpx.ut_id[3] = SC_WILDC;
    641 	utmpx.ut_type = LOGIN_PROCESS;
    642 	(void) time(&utmpx.ut_tv.tv_sec);
    643 	if (makeutx(&utmpx) == NULL)
    644 		fatal(net, "makeutx failed");
    645 #endif
    646 
    647 	scrub_env();
    648 
    649 	/*
    650 	 * -h : pass on name of host.
    651 	 *		WARNING:  -h is accepted by login if and only if
    652 	 *			getuid() == 0.
    653 	 * -p : don't clobber the environment (so terminal type stays set).
    654 	 *
    655 	 * -f : force this login, he has already been authenticated
    656 	 */
    657 	argv = addarg(0, "login");
    658 
    659 	{
    660 		argv = addarg(argv, "-h");
    661 		argv = addarg(argv, host);
    662 	}
    663 	argv = addarg(argv, "-p");
    664 #ifdef	LINEMODE
    665 	/*
    666 	 * Set the environment variable "LINEMODE" to either
    667 	 * "real" or "kludge" if we are operating in either
    668 	 * real or kludge linemode.
    669 	 */
    670 	if (lmodetype == REAL_LINEMODE)
    671 		setenv("LINEMODE", "real", 1);
    672 # ifdef KLUDGELINEMODE
    673 	else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
    674 		setenv("LINEMODE", "kludge", 1);
    675 # endif
    676 #endif
    677 #ifdef SECURELOGIN
    678 	/*
    679 	 * don't worry about the -f that might get sent.
    680 	 * A -s is supposed to override it anyhow.
    681 	 */
    682 	if (require_secure_login)
    683 		argv = addarg(argv, "-s");
    684 #endif
    685 #ifdef AUTHENTICATION
    686 	if (auth_level >= 0 && autologin == AUTH_VALID) {
    687 		argv = addarg(argv, "-f");
    688 		argv = addarg(argv, "--");
    689 		argv = addarg(argv, name);
    690 	} else
    691 #endif
    692 	if (getenv("USER")) {
    693 		argv = addarg(argv, "--");
    694 		argv = addarg(argv, getenv("USER"));
    695 		/*
    696 		 * Assume that login will set the USER variable
    697 		 * correctly.  For SysV systems, this means that
    698 		 * USER will no longer be set, just LOGNAME by
    699 		 * login.  (The problem is that if the auto-login
    700 		 * fails, and the user then specifies a different
    701 		 * account name, he can get logged in with both
    702 		 * LOGNAME and USER in his environment, but the
    703 		 * USER value will be wrong.
    704 		 */
    705 		unsetenv("USER");
    706 	}
    707         if (getent(defent, gettyname) == 1) {
    708                 char *cp = defstrs;
    709 
    710                 loginprog = getstr("lo", &cp);
    711         }
    712         if (loginprog == NULL)
    713                 loginprog = _PATH_LOGIN;
    714 	closelog();
    715 	/*
    716 	 * This sleep(1) is in here so that telnetd can
    717 	 * finish up with the tty.  There's a race condition
    718 	 * the login banner message gets lost...
    719 	 */
    720 	sleep(1);
    721         execv(loginprog, argv);
    722 
    723         syslog(LOG_ERR, "%s: %m", loginprog);
    724         fatalperror(net, loginprog);
    725 	/*NOTREACHED*/
    726 }
    727 
    728 	char **
    729 addarg(argv, val)
    730 	register char **argv;
    731 	register char *val;
    732 {
    733 	register char **cpp;
    734 
    735 	if (argv == NULL) {
    736 		/*
    737 		 * 10 entries, a leading length, and a null
    738 		 */
    739 		argv = (char **)malloc(sizeof(*argv) * 12);
    740 		if (argv == NULL)
    741 			return(NULL);
    742 		*argv++ = (char *)10;
    743 		*argv = (char *)0;
    744 	}
    745 	for (cpp = argv; *cpp; cpp++)
    746 		;
    747 	if (cpp == &argv[(long)argv[-1]]) {
    748 		--argv;
    749 		*argv = (char *)((long)(*argv) + 10);
    750 		argv = (char **)realloc(argv, sizeof(*argv) * ((long)(*argv) + 2));
    751 		if (argv == NULL) {
    752 			fatal(net, "not enough memory");
    753 			/*NOTREACHED*/
    754 		}
    755 		argv++;
    756 		cpp = &argv[(long)argv[-1] - 10];
    757 	}
    758 	*cpp++ = val;
    759 	*cpp = 0;
    760 	return(argv);
    761 }
    762 
    763 /*
    764  * scrub_env()
    765  *
    766  * We only accept the environment variables listed below.
    767  */
    768 
    769 void
    770 scrub_env()
    771 {
    772 	static const char *reject[] = {
    773 		"TERMCAP=/",
    774 		NULL
    775 	};
    776 
    777 	static const char *acceptstr[] = {
    778 		"XAUTH=", "XAUTHORITY=", "DISPLAY=",
    779 		"TERM=",
    780 		"EDITOR=",
    781 		"PAGER=",
    782 		"LOGNAME=",
    783 		"POSIXLY_CORRECT=",
    784 		"TERMCAP=",
    785 		"PRINTER=",
    786 		NULL
    787 	};
    788 
    789 	char **cpp, **cpp2;
    790 	const char **p;
    791 
    792 	for (cpp2 = cpp = environ; *cpp; cpp++) {
    793 		int reject_it = 0;
    794 
    795 		for(p = reject; *p; p++)
    796 			if(strncmp(*cpp, *p, strlen(*p)) == 0) {
    797 				reject_it = 1;
    798 				break;
    799 			}
    800 		if (reject_it)
    801 			continue;
    802 
    803 		for(p = acceptstr; *p; p++)
    804 			if(strncmp(*cpp, *p, strlen(*p)) == 0)
    805 				break;
    806 		if(*p != NULL)
    807 			*cpp2++ = *cpp;
    808 	}
    809 	*cpp2 = NULL;
    810 }
    811 
    812 /*
    813  * cleanup()
    814  *
    815  * This is the routine to call when we are all through, to
    816  * clean up anything that needs to be cleaned up.
    817  */
    818 /* ARGSUSED */
    819 void
    820 cleanup(sig)
    821 	int sig;
    822 {
    823 # if BSD > 43
    824 	char *p, c;
    825 
    826 	p = line + sizeof("/dev/") - 1;
    827 #ifdef SUPPORT_UTMP
    828 	if (logout(p))
    829 		logwtmp(p, "", "");
    830 #endif
    831 #ifdef SUPPORT_UTMPX
    832 	if (logoutx(p, 0, DEAD_PROCESS))
    833 		logwtmpx(p, "", "", 0, DEAD_PROCESS);
    834 #endif
    835 	(void)chmod(line, 0666);
    836 	(void)chown(line, 0, 0);
    837 	c = *p; *p = 'p';
    838 	(void)chmod(line, 0666);
    839 	(void)chown(line, 0, 0);
    840 	*p = c;
    841 	if (ttyaction(line, "telnetd", "root"))
    842 		syslog(LOG_ERR, "%s: ttyaction failed", line);
    843 	(void) shutdown(net, 2);
    844 	exit(1);
    845 # else
    846 	void rmut();
    847 
    848 	rmut();
    849 	vhangup();	/* XXX */
    850 	(void) shutdown(net, 2);
    851 	exit(1);
    852 # endif
    853 }
    854 
    855 /*
    856  * rmut()
    857  *
    858  * This is the function called by cleanup() to
    859  * remove the utmp entry for this person.
    860  */
    861 
    862 #ifdef	UTMPX
    863 void
    864 rmut()
    865 {
    866 	register f;
    867 	int found = 0;
    868 	struct utmp *u, *utmp;
    869 	int nutmp;
    870 	struct stat statbf;
    871 
    872 	struct utmpx *utxp, utmpx;
    873 
    874 	/*
    875 	 * This updates the utmpx and utmp entries and make a wtmp/x entry
    876 	 */
    877 
    878 	SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
    879 	utxp = getutxline(&utmpx);
    880 	if (utxp) {
    881 		utxp->ut_type = DEAD_PROCESS;
    882 		utxp->ut_exit.e_termination = 0;
    883 		utxp->ut_exit.e_exit = 0;
    884 		(void) time(&utmpx.ut_tv.tv_sec);
    885 		utmpx.ut_tv.tv_usec = 0;
    886 		modutx(utxp);
    887 	}
    888 	endutxent();
    889 }  /* end of rmut */
    890 #endif
    891 
    892 #if	!defined(UTMPX) && BSD <= 43
    893 void
    894 rmut()
    895 {
    896 	register f;
    897 	int found = 0;
    898 	struct utmp *u, *utmp;
    899 	int nutmp;
    900 	struct stat statbf;
    901 
    902 	f = open(utmpf, O_RDWR);
    903 	if (f >= 0) {
    904 		(void) fstat(f, &statbf);
    905 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
    906 		if (!utmp)
    907 			syslog(LOG_WARNING, "utmp malloc failed");
    908 		if (statbf.st_size && utmp) {
    909 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
    910 			nutmp /= sizeof(struct utmp);
    911 
    912 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
    913 				if (SCMPN(u->ut_line, line+5) ||
    914 				    u->ut_name[0]==0)
    915 					continue;
    916 				(void)lseek(f, (off_t)((long)u)-((long)utmp),
    917 				    SEEK_SET);
    918 				SCPYN(u->ut_name, "");
    919 				SCPYN(u->ut_host, "");
    920 				(void) time(&u->ut_time);
    921 				(void) write(f, (char *)u, sizeof(wtmp));
    922 				found++;
    923 			}
    924 		}
    925 		(void) close(f);
    926 	}
    927 	if (found) {
    928 		f = open(wtmpf, O_WRONLY|O_APPEND);
    929 		if (f >= 0) {
    930 			SCPYN(wtmp.ut_line, line+5);
    931 			SCPYN(wtmp.ut_name, "");
    932 			SCPYN(wtmp.ut_host, "");
    933 			(void) time(&wtmp.ut_time);
    934 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
    935 			(void) close(f);
    936 		}
    937 	}
    938 	(void) chmod(line, 0666);
    939 	(void) chown(line, 0, 0);
    940 	line[strlen("/dev/")] = 'p';
    941 	(void) chmod(line, 0666);
    942 	(void) chown(line, 0, 0);
    943 }  /* end of rmut */
    944 #endif
    945 
    946