Home | History | Annotate | Line # | Download | only in telnetd
sys_term.c revision 1.1
      1 /*
      2  * Copyright (c) 1989 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)sys_term.c	5.16 (Berkeley) 3/22/91";
     36 #endif /* not lint */
     37 
     38 #include "telnetd.h"
     39 #include "pathnames.h"
     40 
     41 #if	defined(AUTHENTICATE)
     42 #include <libtelnet/auth.h>
     43 #endif
     44 
     45 #ifdef	NEWINIT
     46 #include <initreq.h>
     47 #else	/* NEWINIT*/
     48 #include <utmp.h>
     49 struct	utmp wtmp;
     50 
     51 # ifndef CRAY
     52 char	wtmpf[]	= "/usr/adm/wtmp";
     53 char	utmpf[] = "/etc/utmp";
     54 # else	/* CRAY */
     55 char	wtmpf[]	= "/etc/wtmp";
     56 #include <tmpdir.h>
     57 #include <sys/wait.h>
     58 # endif	/* CRAY */
     59 #endif	/* NEWINIT */
     60 
     61 #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
     62 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
     63 
     64 #ifdef	STREAMS
     65 #include <sys/stream.h>
     66 #endif
     67 #include <sys/tty.h>
     68 #ifdef	t_erase
     69 #undef	t_erase
     70 #undef	t_kill
     71 #undef	t_intrc
     72 #undef	t_quitc
     73 #undef	t_startc
     74 #undef	t_stopc
     75 #undef	t_eofc
     76 #undef	t_brkc
     77 #undef	t_suspc
     78 #undef	t_dsuspc
     79 #undef	t_rprntc
     80 #undef	t_flushc
     81 #undef	t_werasc
     82 #undef	t_lnextc
     83 #endif
     84 
     85 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
     86 # define EXTPROC 0400
     87 #endif
     88 
     89 #ifndef	USE_TERMIO
     90 struct termbuf {
     91 	struct sgttyb sg;
     92 	struct tchars tc;
     93 	struct ltchars ltc;
     94 	int state;
     95 	int lflags;
     96 } termbuf, termbuf2;
     97 # define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
     98 # define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
     99 # define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
    100 # define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
    101 #else	/* USE_TERMIO */
    102 # ifdef	SYSV_TERMIO
    103 #	define termios termio
    104 # endif
    105 # ifndef	TCSANOW
    106 #  ifdef TCSETS
    107 #   define	TCSANOW		TCSETS
    108 #   define	TCSADRAIN	TCSETSW
    109 #   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
    110 #  else
    111 #   ifdef TCSETA
    112 #    define	TCSANOW		TCSETA
    113 #    define	TCSADRAIN	TCSETAW
    114 #    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
    115 #   else
    116 #    define	TCSANOW		TIOCSETA
    117 #    define	TCSADRAIN	TIOCSETAW
    118 #    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
    119 #   endif
    120 #  endif
    121 #  define	tcsetattr(f, a, t)	ioctl(f, a, t)
    122 #  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
    123 					(tp)->c_cflag |= (val)
    124 #  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
    125 #  ifdef CIBAUD
    126 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
    127 					(tp)->c_cflag |= ((val)<<IBSHIFT)
    128 #   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
    129 #  else
    130 #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
    131 					(tp)->c_cflag |= (val)
    132 #   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
    133 #  endif
    134 # endif /* TCSANOW */
    135 struct termios termbuf, termbuf2;	/* pty control structure */
    136 #endif	/* USE_TERMIO */
    137 
    138 /*
    139  * init_termbuf()
    140  * copy_termbuf(cp)
    141  * set_termbuf()
    142  *
    143  * These three routines are used to get and set the "termbuf" structure
    144  * to and from the kernel.  init_termbuf() gets the current settings.
    145  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
    146  * set_termbuf() writes the structure into the kernel.
    147  */
    148 
    149 	void
    150 init_termbuf()
    151 {
    152 #ifndef	USE_TERMIO
    153 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
    154 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
    155 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
    156 # ifdef	TIOCGSTATE
    157 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
    158 # endif
    159 #else
    160 	(void) tcgetattr(pty, &termbuf);
    161 #endif
    162 	termbuf2 = termbuf;
    163 }
    164 
    165 #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
    166 	void
    167 copy_termbuf(cp, len)
    168 	char *cp;
    169 	int len;
    170 {
    171 	if (len > sizeof(termbuf))
    172 		len = sizeof(termbuf);
    173 	bcopy(cp, (char *)&termbuf, len);
    174 	termbuf2 = termbuf;
    175 }
    176 #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
    177 
    178 	void
    179 set_termbuf()
    180 {
    181 	/*
    182 	 * Only make the necessary changes.
    183 	 */
    184 #ifndef	USE_TERMIO
    185 	if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
    186 		(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
    187 	if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
    188 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
    189 	if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
    190 							sizeof(termbuf.ltc)))
    191 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
    192 	if (termbuf.lflags != termbuf2.lflags)
    193 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
    194 #else	/* USE_TERMIO */
    195 	if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
    196 		(void) tcsetattr(pty, TCSANOW, &termbuf);
    197 # if	defined(CRAY2) && defined(UNCIOS5)
    198 	needtermstat = 1;
    199 # endif
    200 #endif	/* USE_TERMIO */
    201 }
    202 
    203 
    204 /*
    205  * spcset(func, valp, valpp)
    206  *
    207  * This function takes various special characters (func), and
    208  * sets *valp to the current value of that character, and
    209  * *valpp to point to where in the "termbuf" structure that
    210  * value is kept.
    211  *
    212  * It returns the SLC_ level of support for this function.
    213  */
    214 
    215 #ifndef	USE_TERMIO
    216 	int
    217 spcset(func, valp, valpp)
    218 	int func;
    219 	cc_t *valp;
    220 	cc_t **valpp;
    221 {
    222 	switch(func) {
    223 	case SLC_EOF:
    224 		*valp = termbuf.tc.t_eofc;
    225 		*valpp = (cc_t *)&termbuf.tc.t_eofc;
    226 		return(SLC_VARIABLE);
    227 	case SLC_EC:
    228 		*valp = termbuf.sg.sg_erase;
    229 		*valpp = (cc_t *)&termbuf.sg.sg_erase;
    230 		return(SLC_VARIABLE);
    231 	case SLC_EL:
    232 		*valp = termbuf.sg.sg_kill;
    233 		*valpp = (cc_t *)&termbuf.sg.sg_kill;
    234 		return(SLC_VARIABLE);
    235 	case SLC_IP:
    236 		*valp = termbuf.tc.t_intrc;
    237 		*valpp = (cc_t *)&termbuf.tc.t_intrc;
    238 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    239 	case SLC_ABORT:
    240 		*valp = termbuf.tc.t_quitc;
    241 		*valpp = (cc_t *)&termbuf.tc.t_quitc;
    242 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    243 	case SLC_XON:
    244 		*valp = termbuf.tc.t_startc;
    245 		*valpp = (cc_t *)&termbuf.tc.t_startc;
    246 		return(SLC_VARIABLE);
    247 	case SLC_XOFF:
    248 		*valp = termbuf.tc.t_stopc;
    249 		*valpp = (cc_t *)&termbuf.tc.t_stopc;
    250 		return(SLC_VARIABLE);
    251 	case SLC_AO:
    252 		*valp = termbuf.ltc.t_flushc;
    253 		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
    254 		return(SLC_VARIABLE);
    255 	case SLC_SUSP:
    256 		*valp = termbuf.ltc.t_suspc;
    257 		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
    258 		return(SLC_VARIABLE);
    259 	case SLC_EW:
    260 		*valp = termbuf.ltc.t_werasc;
    261 		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
    262 		return(SLC_VARIABLE);
    263 	case SLC_RP:
    264 		*valp = termbuf.ltc.t_rprntc;
    265 		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
    266 		return(SLC_VARIABLE);
    267 	case SLC_LNEXT:
    268 		*valp = termbuf.ltc.t_lnextc;
    269 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
    270 		return(SLC_VARIABLE);
    271 	case SLC_FORW1:
    272 		*valp = termbuf.tc.t_brkc;
    273 		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
    274 		return(SLC_VARIABLE);
    275 	case SLC_BRK:
    276 	case SLC_SYNCH:
    277 	case SLC_AYT:
    278 	case SLC_EOR:
    279 		*valp = (cc_t)0;
    280 		*valpp = (cc_t *)0;
    281 		return(SLC_DEFAULT);
    282 	default:
    283 		*valp = (cc_t)0;
    284 		*valpp = (cc_t *)0;
    285 		return(SLC_NOSUPPORT);
    286 	}
    287 }
    288 
    289 #else	/* USE_TERMIO */
    290 
    291 	int
    292 spcset(func, valp, valpp)
    293 	int func;
    294 	cc_t *valp;
    295 	cc_t **valpp;
    296 {
    297 
    298 #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
    299 			*valpp = &termbuf.c_cc[a]; \
    300 			return(b);
    301 #define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
    302 
    303 	switch(func) {
    304 	case SLC_EOF:
    305 		setval(VEOF, SLC_VARIABLE);
    306 	case SLC_EC:
    307 		setval(VERASE, SLC_VARIABLE);
    308 	case SLC_EL:
    309 		setval(VKILL, SLC_VARIABLE);
    310 	case SLC_IP:
    311 		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    312 	case SLC_ABORT:
    313 		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
    314 	case SLC_XON:
    315 #ifdef	VSTART
    316 		setval(VSTART, SLC_VARIABLE);
    317 #else
    318 		defval(0x13);
    319 #endif
    320 	case SLC_XOFF:
    321 #ifdef	VSTOP
    322 		setval(VSTOP, SLC_VARIABLE);
    323 #else
    324 		defval(0x11);
    325 #endif
    326 	case SLC_EW:
    327 #ifdef	VWERASE
    328 		setval(VWERASE, SLC_VARIABLE);
    329 #else
    330 		defval(0);
    331 #endif
    332 	case SLC_RP:
    333 #ifdef	VREPRINT
    334 		setval(VREPRINT, SLC_VARIABLE);
    335 #else
    336 		defval(0);
    337 #endif
    338 	case SLC_LNEXT:
    339 #ifdef	VLNEXT
    340 		setval(VLNEXT, SLC_VARIABLE);
    341 #else
    342 		defval(0);
    343 #endif
    344 	case SLC_AO:
    345 #if	!defined(VDISCARD) && defined(VFLUSHO)
    346 # define VDISCARD VFLUSHO
    347 #endif
    348 #ifdef	VDISCARD
    349 		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
    350 #else
    351 		defval(0);
    352 #endif
    353 	case SLC_SUSP:
    354 #ifdef	VSUSP
    355 		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
    356 #else
    357 		defval(0);
    358 #endif
    359 #ifdef	VEOL
    360 	case SLC_FORW1:
    361 		setval(VEOL, SLC_VARIABLE);
    362 #endif
    363 #ifdef	VEOL2
    364 	case SLC_FORW2:
    365 		setval(VEOL2, SLC_VARIABLE);
    366 #endif
    367 	case SLC_AYT:
    368 #ifdef	VSTATUS
    369 		setval(VSTATUS, SLC_VARIABLE);
    370 #else
    371 		defval(0);
    372 #endif
    373 
    374 	case SLC_BRK:
    375 	case SLC_SYNCH:
    376 	case SLC_EOR:
    377 		defval(0);
    378 
    379 	default:
    380 		*valp = 0;
    381 		*valpp = 0;
    382 		return(SLC_NOSUPPORT);
    383 	}
    384 }
    385 #endif	/* USE_TERMIO */
    386 
    387 #ifdef CRAY
    388 /*
    389  * getnpty()
    390  *
    391  * Return the number of pty's configured into the system.
    392  */
    393 	int
    394 getnpty()
    395 {
    396 #ifdef _SC_CRAY_NPTY
    397 	int numptys;
    398 
    399 	if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
    400 		return numptys;
    401 	else
    402 #endif /* _SC_CRAY_NPTY */
    403 		return 128;
    404 }
    405 #endif /* CRAY */
    406 
    407 #ifndef	convex
    408 /*
    409  * getpty()
    410  *
    411  * Allocate a pty.  As a side effect, the external character
    412  * array "line" contains the name of the slave side.
    413  *
    414  * Returns the file descriptor of the opened pty.
    415  */
    416 #ifndef	__GNUC__
    417 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    418 #else
    419 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    420 char *line = Xline;
    421 #endif
    422 #ifdef	CRAY
    423 char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    424 #endif	/* CRAY */
    425 
    426 	int
    427 getpty()
    428 {
    429 	register int p;
    430 #ifndef CRAY
    431 	register char c, *p1, *p2;
    432 	register int i;
    433 
    434 	(void) sprintf(line, "/dev/ptyXX");
    435 	p1 = &line[8];
    436 	p2 = &line[9];
    437 
    438 	for (c = 'p'; c <= 's'; c++) {
    439 		struct stat stb;
    440 
    441 		*p1 = c;
    442 		*p2 = '0';
    443 		if (stat(line, &stb) < 0)
    444 			break;
    445 		for (i = 0; i < 16; i++) {
    446 			*p2 = "0123456789abcdef"[i];
    447 			p = open(line, 2);
    448 			if (p > 0) {
    449 				line[5] = 't';
    450 				return(p);
    451 			}
    452 		}
    453 	}
    454 #else	/* CRAY */
    455 	register int npty;
    456 	extern lowpty, highpty;
    457 	struct stat sb;
    458 
    459 	for (npty = lowpty; npty <= highpty; npty++) {
    460 		(void) sprintf(myline, "/dev/pty/%03d", npty);
    461 		p = open(myline, 2);
    462 		if (p < 0)
    463 			continue;
    464 		(void) sprintf(line, "/dev/ttyp%03d", npty);
    465 		/*
    466 		 * Here are some shenanigans to make sure that there
    467 		 * are no listeners lurking on the line.
    468 		 */
    469 		if(stat(line, &sb) < 0) {
    470 			(void) close(p);
    471 			continue;
    472 		}
    473 		if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
    474 			chown(line, 0, 0);
    475 			chmod(line, 0600);
    476 			(void)close(p);
    477 			p = open(myline, 2);
    478 			if (p < 0)
    479 				continue;
    480 		}
    481 		/*
    482 		 * Now it should be safe...check for accessability.
    483 		 */
    484 		if (access(line, 6) == 0)
    485 			return(p);
    486 		else {
    487 			/* no tty side to pty so skip it */
    488 			(void) close(p);
    489 		}
    490 	}
    491 #endif	/* CRAY */
    492 	return(-1);
    493 }
    494 #endif	/* convex */
    495 
    496 #ifdef	LINEMODE
    497 /*
    498  * tty_flowmode()	Find out if flow control is enabled or disabled.
    499  * tty_linemode()	Find out if linemode (external processing) is enabled.
    500  * tty_setlinemod(on)	Turn on/off linemode.
    501  * tty_isecho()		Find out if echoing is turned on.
    502  * tty_setecho(on)	Enable/disable character echoing.
    503  * tty_israw()		Find out if terminal is in RAW mode.
    504  * tty_binaryin(on)	Turn on/off BINARY on input.
    505  * tty_binaryout(on)	Turn on/off BINARY on output.
    506  * tty_isediting()	Find out if line editing is enabled.
    507  * tty_istrapsig()	Find out if signal trapping is enabled.
    508  * tty_setedit(on)	Turn on/off line editing.
    509  * tty_setsig(on)	Turn on/off signal trapping.
    510  * tty_issofttab()	Find out if tab expansion is enabled.
    511  * tty_setsofttab(on)	Turn on/off soft tab expansion.
    512  * tty_islitecho()	Find out if typed control chars are echoed literally
    513  * tty_setlitecho()	Turn on/off literal echo of control chars
    514  * tty_tspeed(val)	Set transmit speed to val.
    515  * tty_rspeed(val)	Set receive speed to val.
    516  */
    517 
    518 	int
    519 tty_flowmode()
    520 {
    521 #ifndef USE_TERMIO
    522 	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
    523 #else
    524 	return(termbuf.c_iflag & IXON ? 1 : 0);
    525 #endif
    526 }
    527 
    528 #ifdef convex
    529 static int linestate;
    530 #endif
    531 
    532 	int
    533 tty_linemode()
    534 {
    535 #ifndef convex
    536 #ifndef	USE_TERMIO
    537 	return(termbuf.state & TS_EXTPROC);
    538 #else
    539 	return(termbuf.c_lflag & EXTPROC);
    540 #endif
    541 #else
    542 	return(linestate);
    543 #endif
    544 }
    545 
    546 	void
    547 tty_setlinemode(on)
    548 	int on;
    549 {
    550 #ifdef	TIOCEXT
    551 # ifndef convex
    552 	set_termbuf();
    553 # else
    554 	linestate = on;
    555 # endif
    556 	(void) ioctl(pty, TIOCEXT, (char *)&on);
    557 # ifndef convex
    558 	init_termbuf();
    559 # endif
    560 #else	/* !TIOCEXT */
    561 # ifdef	EXTPROC
    562 	if (on)
    563 		termbuf.c_lflag |= EXTPROC;
    564 	else
    565 		termbuf.c_lflag &= ~EXTPROC;
    566 # endif
    567 #endif	/* TIOCEXT */
    568 }
    569 
    570 	int
    571 tty_isecho()
    572 {
    573 #ifndef USE_TERMIO
    574 	return (termbuf.sg.sg_flags & ECHO);
    575 #else
    576 	return (termbuf.c_lflag & ECHO);
    577 #endif
    578 }
    579 #endif	/* LINEMODE */
    580 
    581 	void
    582 tty_setecho(on)
    583 	int on;
    584 {
    585 #ifndef	USE_TERMIO
    586 	if (on)
    587 		termbuf.sg.sg_flags |= ECHO|CRMOD;
    588 	else
    589 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
    590 #else
    591 	if (on)
    592 		termbuf.c_lflag |= ECHO;
    593 	else
    594 		termbuf.c_lflag &= ~ECHO;
    595 #endif
    596 }
    597 
    598 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    599 	int
    600 tty_israw()
    601 {
    602 #ifndef USE_TERMIO
    603 	return(termbuf.sg.sg_flags & RAW);
    604 #else
    605 	return(!(termbuf.c_lflag & ICANON));
    606 #endif
    607 }
    608 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    609 
    610 	void
    611 tty_binaryin(on)
    612 	int on;
    613 {
    614 #ifndef	USE_TERMIO
    615 	if (on)
    616 		termbuf.lflags |= LPASS8;
    617 	else
    618 		termbuf.lflags &= ~LPASS8;
    619 #else
    620 	if (on) {
    621 		termbuf.c_iflag &= ~ISTRIP;
    622 	} else {
    623 		termbuf.c_iflag |= ISTRIP;
    624 	}
    625 #endif
    626 }
    627 
    628 	void
    629 tty_binaryout(on)
    630 	int on;
    631 {
    632 #ifndef	USE_TERMIO
    633 	if (on)
    634 		termbuf.lflags |= LLITOUT;
    635 	else
    636 		termbuf.lflags &= ~LLITOUT;
    637 #else
    638 	if (on) {
    639 		termbuf.c_cflag &= ~(CSIZE|PARENB);
    640 		termbuf.c_cflag |= CS8;
    641 		termbuf.c_oflag &= ~OPOST;
    642 	} else {
    643 		termbuf.c_cflag &= ~CSIZE;
    644 		termbuf.c_cflag |= CS7|PARENB;
    645 		termbuf.c_oflag |= OPOST;
    646 	}
    647 #endif
    648 }
    649 
    650 	int
    651 tty_isbinaryin()
    652 {
    653 #ifndef	USE_TERMIO
    654 	return(termbuf.lflags & LPASS8);
    655 #else
    656 	return(!(termbuf.c_iflag & ISTRIP));
    657 #endif
    658 }
    659 
    660 	int
    661 tty_isbinaryout()
    662 {
    663 #ifndef	USE_TERMIO
    664 	return(termbuf.lflags & LLITOUT);
    665 #else
    666 	return(!(termbuf.c_oflag&OPOST));
    667 #endif
    668 }
    669 
    670 #ifdef	LINEMODE
    671 	int
    672 tty_isediting()
    673 {
    674 #ifndef USE_TERMIO
    675 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
    676 #else
    677 	return(termbuf.c_lflag & ICANON);
    678 #endif
    679 }
    680 
    681 	int
    682 tty_istrapsig()
    683 {
    684 #ifndef USE_TERMIO
    685 	return(!(termbuf.sg.sg_flags&RAW));
    686 #else
    687 	return(termbuf.c_lflag & ISIG);
    688 #endif
    689 }
    690 
    691 	void
    692 tty_setedit(on)
    693 	int on;
    694 {
    695 #ifndef USE_TERMIO
    696 	if (on)
    697 		termbuf.sg.sg_flags &= ~CBREAK;
    698 	else
    699 		termbuf.sg.sg_flags |= CBREAK;
    700 #else
    701 	if (on)
    702 		termbuf.c_lflag |= ICANON;
    703 	else
    704 		termbuf.c_lflag &= ~ICANON;
    705 #endif
    706 }
    707 
    708 	void
    709 tty_setsig(on)
    710 	int on;
    711 {
    712 #ifndef	USE_TERMIO
    713 	if (on)
    714 		;
    715 #else
    716 	if (on)
    717 		termbuf.c_lflag |= ISIG;
    718 	else
    719 		termbuf.c_lflag &= ~ISIG;
    720 #endif
    721 }
    722 #endif	/* LINEMODE */
    723 
    724 	int
    725 tty_issofttab()
    726 {
    727 #ifndef	USE_TERMIO
    728 	return (termbuf.sg.sg_flags & XTABS);
    729 #else
    730 # ifdef	OXTABS
    731 	return (termbuf.c_oflag & OXTABS);
    732 # endif
    733 # ifdef	TABDLY
    734 	return ((termbuf.c_oflag & TABDLY) == TAB3);
    735 # endif
    736 #endif
    737 }
    738 
    739 	void
    740 tty_setsofttab(on)
    741 	int on;
    742 {
    743 #ifndef	USE_TERMIO
    744 	if (on)
    745 		termbuf.sg.sg_flags |= XTABS;
    746 	else
    747 		termbuf.sg.sg_flags &= ~XTABS;
    748 #else
    749 	if (on) {
    750 # ifdef	OXTABS
    751 		termbuf.c_oflag |= OXTABS;
    752 # endif
    753 # ifdef	TABDLY
    754 		termbuf.c_oflag &= ~TABDLY;
    755 		termbuf.c_oflag |= TAB3;
    756 # endif
    757 	} else {
    758 # ifdef	OXTABS
    759 		termbuf.c_oflag &= ~OXTABS;
    760 # endif
    761 # ifdef	TABDLY
    762 		termbuf.c_oflag &= ~TABDLY;
    763 		termbuf.c_oflag |= TAB0;
    764 # endif
    765 	}
    766 #endif
    767 }
    768 
    769 	int
    770 tty_islitecho()
    771 {
    772 #ifndef	USE_TERMIO
    773 	return (!(termbuf.lflags & LCTLECH));
    774 #else
    775 # ifdef	ECHOCTL
    776 	return (!(termbuf.c_lflag & ECHOCTL));
    777 # endif
    778 # ifdef	TCTLECH
    779 	return (!(termbuf.c_lflag & TCTLECH));
    780 # endif
    781 # if	!defined(ECHOCTL) && !defined(TCTLECH)
    782 	return (0);	/* assumes ctl chars are echoed '^x' */
    783 # endif
    784 #endif
    785 }
    786 
    787 	void
    788 tty_setlitecho(on)
    789 	int on;
    790 {
    791 #ifndef	USE_TERMIO
    792 	if (on)
    793 		termbuf.lflags &= ~LCTLECH;
    794 	else
    795 		termbuf.lflags |= LCTLECH;
    796 #else
    797 # ifdef	ECHOCTL
    798 	if (on)
    799 		termbuf.c_lflag &= ~ECHOCTL;
    800 	else
    801 		termbuf.c_lflag |= ECHOCTL;
    802 # endif
    803 # ifdef	TCTLECH
    804 	if (on)
    805 		termbuf.c_lflag &= ~TCTLECH;
    806 	else
    807 		termbuf.c_lflag |= TCTLECH;
    808 # endif
    809 #endif
    810 }
    811 
    812 	int
    813 tty_iscrnl()
    814 {
    815 #ifndef	USE_TERMIO
    816 	return (termbuf.sg.sg_flags & CRMOD);
    817 #else
    818 	return (termbuf.c_iflag & ICRNL);
    819 #endif
    820 }
    821 
    822 /*
    823  * A table of available terminal speeds
    824  */
    825 struct termspeeds {
    826 	int	speed;
    827 	int	value;
    828 } termspeeds[] = {
    829 	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
    830 	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
    831 	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
    832 	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
    833 	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
    834 	{ 38400, B9600 }, { -1,    B9600 }
    835 };
    836 
    837 	void
    838 tty_tspeed(val)
    839 	int val;
    840 {
    841 	register struct termspeeds *tp;
    842 
    843 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
    844 		;
    845 	cfsetospeed(&termbuf, tp->value);
    846 }
    847 
    848 	void
    849 tty_rspeed(val)
    850 	int val;
    851 {
    852 	register struct termspeeds *tp;
    853 
    854 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
    855 		;
    856 	cfsetispeed(&termbuf, tp->value);
    857 }
    858 
    859 #if	defined(CRAY2) && defined(UNICOS5)
    860 	int
    861 tty_isnewmap()
    862 {
    863 	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
    864 			!(termbuf.c_oflag & ONLRET));
    865 }
    866 #endif
    867 
    868 #ifdef	CRAY
    869 # ifndef NEWINIT
    870 extern	struct utmp wtmp;
    871 extern char wtmpf[];
    872 # else	/* NEWINIT */
    873 int	gotalarm;
    874 
    875 	/* ARGSUSED */
    876 	void
    877 nologinproc(sig)
    878 	int sig;
    879 {
    880 	gotalarm++;
    881 }
    882 # endif	/* NEWINIT */
    883 #endif /* CRAY */
    884 
    885 #ifndef	NEWINIT
    886 # ifdef	CRAY
    887 extern void utmp_sig_init P((void));
    888 extern void utmp_sig_reset P((void));
    889 extern void utmp_sig_wait P((void));
    890 extern void utmp_sig_notify P((int));
    891 # endif
    892 #endif
    893 
    894 /*
    895  * getptyslave()
    896  *
    897  * Open the slave side of the pty, and do any initialization
    898  * that is necessary.  The return value is a file descriptor
    899  * for the slave side.
    900  */
    901 	int
    902 getptyslave()
    903 {
    904 	register int t = -1;
    905 
    906 #if	!defined(CRAY) || !defined(NEWINIT)
    907 # ifdef	LINEMODE
    908 	int waslm;
    909 # endif
    910 # ifdef	TIOCGWINSZ
    911 	struct winsize ws;
    912 	extern int def_row, def_col;
    913 # endif
    914 	extern int def_tspeed, def_rspeed;
    915 	/*
    916 	 * Opening the slave side may cause initilization of the
    917 	 * kernel tty structure.  We need remember the state of
    918 	 * 	if linemode was turned on
    919 	 *	terminal window size
    920 	 *	terminal speed
    921 	 * so that we can re-set them if we need to.
    922 	 */
    923 # ifdef	LINEMODE
    924 	waslm = tty_linemode();
    925 # endif
    926 
    927 
    928 	/*
    929 	 * Make sure that we don't have a controlling tty, and
    930 	 * that we are the session (process group) leader.
    931 	 */
    932 # ifdef	TIOCNOTTY
    933 	t = open(_PATH_TTY, O_RDWR);
    934 	if (t >= 0) {
    935 		(void) ioctl(t, TIOCNOTTY, (char *)0);
    936 		(void) close(t);
    937 	}
    938 # endif
    939 
    940 
    941 # ifdef	CRAY
    942 	/*
    943 	 * Wait for our parent to get the utmp stuff to get done.
    944 	 */
    945 	utmp_sig_wait();
    946 # endif
    947 
    948 	t = cleanopen(line);
    949 	if (t < 0)
    950 		fatalperror(net, line);
    951 
    952 	/*
    953 	 * set up the tty modes as we like them to be.
    954 	 */
    955 	init_termbuf();
    956 # ifdef	TIOCGWINSZ
    957 	if (def_row || def_col) {
    958 		bzero((char *)&ws, sizeof(ws));
    959 		ws.ws_col = def_col;
    960 		ws.ws_row = def_row;
    961 		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
    962 	}
    963 # endif
    964 
    965 	/*
    966 	 * Settings for sgtty based systems
    967 	 */
    968 # ifndef	USE_TERMIO
    969 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
    970 # endif	/* USE_TERMIO */
    971 
    972 	/*
    973 	 * Settings for UNICOS
    974 	 */
    975 # ifdef	CRAY
    976 	termbuf.c_oflag = OPOST|ONLCR|TAB3;
    977 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
    978 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
    979 	termbuf.c_cflag = EXTB|HUPCL|CS8;
    980 # endif
    981 
    982 	/*
    983 	 * Settings for all other termios/termio based
    984 	 * systems, other than 4.4BSD.  In 4.4BSD the
    985 	 * kernel does the initial terminal setup.
    986 	 */
    987 # if defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43)
    988 #  ifndef	OXTABS
    989 #   define OXTABS	0
    990 #  endif
    991 	termbuf.c_lflag |= ECHO;
    992 	termbuf.c_oflag |= ONLCR|OXTABS;
    993 	termbuf.c_iflag |= ICRNL;
    994 	termbuf.c_iflag &= ~IXOFF;
    995 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
    996 	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
    997 	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
    998 # ifdef	LINEMODE
    999 	if (waslm)
   1000 		tty_setlinemode(1);
   1001 # endif	/* LINEMODE */
   1002 
   1003 	/*
   1004 	 * Set the tty modes, and make this our controlling tty.
   1005 	 */
   1006 	set_termbuf();
   1007 	if (login_tty(t) == -1)
   1008 		fatalperror(net, "login_tty");
   1009 #endif	/* !defined(CRAY) || !defined(NEWINIT) */
   1010 	if (net > 2)
   1011 		(void) close(net);
   1012 	if (pty > 2)
   1013 		(void) close(pty);
   1014 }
   1015 
   1016 #if	!defined(CRAY) || !defined(NEWINIT)
   1017 #ifndef	O_NOCTTY
   1018 #define	O_NOCTTY	0
   1019 #endif
   1020 /*
   1021  * Open the specified slave side of the pty,
   1022  * making sure that we have a clean tty.
   1023  */
   1024 	int
   1025 cleanopen(line)
   1026 	char *line;
   1027 {
   1028 	register int t;
   1029 
   1030 	/*
   1031 	 * Make sure that other people can't open the
   1032 	 * slave side of the connection.
   1033 	 */
   1034 	(void) chown(line, 0, 0);
   1035 	(void) chmod(line, 0600);
   1036 
   1037 # if !defined(CRAY) && (BSD > 43)
   1038 	(void) revoke(line);
   1039 # endif
   1040 	t = open(line, O_RDWR|O_NOCTTY);
   1041 	if (t < 0)
   1042 		return(-1);
   1043 
   1044 	/*
   1045 	 * Hangup anybody else using this ttyp, then reopen it for
   1046 	 * ourselves.
   1047 	 */
   1048 # if !defined(CRAY) && (BSD <= 43)
   1049 	(void) signal(SIGHUP, SIG_IGN);
   1050 	vhangup();
   1051 	(void) signal(SIGHUP, SIG_DFL);
   1052 	t = open(line, O_RDWR|O_NOCTTY);
   1053 	if (t < 0)
   1054 		return(-1);
   1055 # endif
   1056 # if	defined(CRAY) && defined(TCVHUP)
   1057 	{
   1058 		register int i;
   1059 		(void) signal(SIGHUP, SIG_IGN);
   1060 		(void) ioctl(t, TCVHUP, (char *)0);
   1061 		(void) signal(SIGHUP, SIG_DFL);
   1062 		setpgrp();
   1063 		i = open(line, O_RDWR);
   1064 		if (i < 0)
   1065 			return(-1);
   1066 		(void) close(t);
   1067 		t = i;
   1068 	}
   1069 # endif	/* defined(CRAY) && defined(TCVHUP) */
   1070 	return(t);
   1071 }
   1072 #endif	/* !defined(CRAY) || !defined(NEWINIT) */
   1073 
   1074 #if BSD <= 43
   1075 	int
   1076 login_tty(t)
   1077 	int t;
   1078 {
   1079 	if (setsid() < 0)
   1080 		fatalperror(net, "setsid()");
   1081 # ifdef	TIOCSCTTY
   1082 	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
   1083 		fatalperror(net, "ioctl(sctty)");
   1084 #  if defined(CRAY) && defined(SESS_CTTY)	/* SESS_CTTY is in param.h */
   1085 	/*
   1086 	 * Close the hard fd to /dev/ttypXXX, and re-open through
   1087 	 * the indirect /dev/tty interface.
   1088 	 */
   1089 	close(t);
   1090 	if ((t = open("/dev/tty", O_RDWR)) < 0)
   1091 		fatalperror(net, "open(/dev/tty)");
   1092 #  endif
   1093 # else
   1094 	close(open(line, O_RDWR));
   1095 # endif
   1096 	if (t != 0)
   1097 		(void) dup2(t, 0);
   1098 	if (t != 1)
   1099 		(void) dup2(t, 1);
   1100 	if (t != 2)
   1101 		(void) dup2(t, 2);
   1102 	if (t > 2)
   1103 		close(t);
   1104 	return(0);
   1105 }
   1106 #endif	/* BSD <= 43 */
   1107 
   1108 #ifdef	NEWINIT
   1109 char *gen_id = "fe";
   1110 #endif
   1111 
   1112 /*
   1113  * startslave(host)
   1114  *
   1115  * Given a hostname, do whatever
   1116  * is necessary to startup the login process on the slave side of the pty.
   1117  */
   1118 
   1119 /* ARGSUSED */
   1120 	void
   1121 startslave(host, autologin, autoname)
   1122 	char *host;
   1123 	int autologin;
   1124 	char *autoname;
   1125 {
   1126 	register int i;
   1127 	long time();
   1128 	char name[256];
   1129 #ifdef	NEWINIT
   1130 	extern char *ptyip;
   1131 	struct init_request request;
   1132 	void nologinproc();
   1133 	register int n;
   1134 #endif	/* NEWINIT */
   1135 
   1136 #if	defined(AUTHENTICATE)
   1137 	if (!autoname || !autoname[0])
   1138 		autologin = 0;
   1139 
   1140 	if (autologin < auth_level) {
   1141 		fatal(net, "Authorization failed");
   1142 		exit(1);
   1143 	}
   1144 #endif
   1145 
   1146 #ifndef	NEWINIT
   1147 # ifdef	CRAY
   1148 	utmp_sig_init();
   1149 # endif	/* CRAY */
   1150 
   1151 	if ((i = fork()) < 0)
   1152 		fatalperror(net, "fork");
   1153 	if (i) {
   1154 # ifdef	CRAY
   1155 		/*
   1156 		 * Cray parent will create utmp entry for child and send
   1157 		 * signal to child to tell when done.  Child waits for signal
   1158 		 * before doing anything important.
   1159 		 */
   1160 		register int pid = i;
   1161 		void sigjob P((int));
   1162 
   1163 		setpgrp();
   1164 		utmp_sig_reset();		/* reset handler to default */
   1165 		/*
   1166 		 * Create utmp entry for child
   1167 		 */
   1168 		(void) time(&wtmp.ut_time);
   1169 		wtmp.ut_type = LOGIN_PROCESS;
   1170 		wtmp.ut_pid = pid;
   1171 		SCPYN(wtmp.ut_user, "LOGIN");
   1172 		SCPYN(wtmp.ut_host, host);
   1173 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
   1174 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
   1175 		pututline(&wtmp);
   1176 		endutent();
   1177 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
   1178 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
   1179 			(void) close(i);
   1180 		}
   1181 		(void) signal(WJSIGNAL, sigjob);
   1182 		utmp_sig_notify(pid);
   1183 # endif	/* CRAY */
   1184 	} else {
   1185 		getptyslave();
   1186 		start_login(host, autologin, autoname);
   1187 		/*NOTREACHED*/
   1188 	}
   1189 #else	/* NEWINIT */
   1190 
   1191 	/*
   1192 	 * Init will start up login process if we ask nicely.  We only wait
   1193 	 * for it to start up and begin normal telnet operation.
   1194 	 */
   1195 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
   1196 		char tbuf[128];
   1197 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
   1198 		fatalperror(net, tbuf);
   1199 	}
   1200 	memset((char *)&request, 0, sizeof(request));
   1201 	request.magic = INIT_MAGIC;
   1202 	SCPYN(request.gen_id, gen_id);
   1203 	SCPYN(request.tty_id, &line[8]);
   1204 	SCPYN(request.host, host);
   1205 	SCPYN(request.term_type, terminaltype ? terminaltype : "network");
   1206 #if	!defined(UNICOS5)
   1207 	request.signal = SIGCLD;
   1208 	request.pid = getpid();
   1209 #endif
   1210 #ifdef BFTPDAEMON
   1211 	/*
   1212 	 * Are we working as the bftp daemon?
   1213 	 */
   1214 	if (bftpd) {
   1215 		SCPYN(request.exec_name, BFTPPATH);
   1216 	}
   1217 #endif /* BFTPDAEMON */
   1218 	if (write(i, (char *)&request, sizeof(request)) < 0) {
   1219 		char tbuf[128];
   1220 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
   1221 		fatalperror(net, tbuf);
   1222 	}
   1223 	(void) close(i);
   1224 	(void) signal(SIGALRM, nologinproc);
   1225 	for (i = 0; ; i++) {
   1226 		char tbuf[128];
   1227 		alarm(15);
   1228 		n = read(pty, ptyip, BUFSIZ);
   1229 		if (i == 3 || n >= 0 || !gotalarm)
   1230 			break;
   1231 		gotalarm = 0;
   1232 		sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
   1233 		(void) write(net, tbuf, strlen(tbuf));
   1234 	}
   1235 	if (n < 0 && gotalarm)
   1236 		fatal(net, "/etc/init didn't start login process");
   1237 	pcc += n;
   1238 	alarm(0);
   1239 	(void) signal(SIGALRM, SIG_DFL);
   1240 
   1241 	return;
   1242 #endif	/* NEWINIT */
   1243 }
   1244 
   1245 char	*envinit[3];
   1246 extern char **environ;
   1247 
   1248 	void
   1249 init_env()
   1250 {
   1251 	extern char *getenv();
   1252 	char **envp;
   1253 
   1254 	envp = envinit;
   1255 	if (*envp = getenv("TZ"))
   1256 		*envp++ -= 3;
   1257 #ifdef	CRAY
   1258 	else
   1259 		*envp++ = "TZ=GMT0";
   1260 #endif
   1261 	*envp = 0;
   1262 	environ = envinit;
   1263 }
   1264 
   1265 #ifndef	NEWINIT
   1266 
   1267 /*
   1268  * start_login(host)
   1269  *
   1270  * Assuming that we are now running as a child processes, this
   1271  * function will turn us into the login process.
   1272  */
   1273 
   1274 	void
   1275 start_login(host, autologin, name)
   1276 	char *host;
   1277 	int autologin;
   1278 	char *name;
   1279 {
   1280 	register char *cp;
   1281 	register char **argv;
   1282 	char **addarg();
   1283 
   1284 	/*
   1285 	 * -h : pass on name of host.
   1286 	 *		WARNING:  -h is accepted by login if and only if
   1287 	 *			getuid() == 0.
   1288 	 * -p : don't clobber the environment (so terminal type stays set).
   1289 	 *
   1290 	 * -f : force this login, he has already been authenticated
   1291 	 */
   1292 	argv = addarg(0, "login");
   1293 	argv = addarg(argv, "-h");
   1294 	argv = addarg(argv, host);
   1295 #if	!defined(NO_LOGIN_P)
   1296 	argv = addarg(argv, "-p");
   1297 #endif
   1298 #ifdef	BFTPDAEMON
   1299 	/*
   1300 	 * Are we working as the bftp daemon?  If so, then ask login
   1301 	 * to start bftp instead of shell.
   1302 	 */
   1303 	if (bftpd) {
   1304 		argv = addarg(argv, "-e");
   1305 		argv = addarg(argv, BFTPPATH);
   1306 	} else
   1307 #endif
   1308 #if	defined (SecurID)
   1309 	/*
   1310 	 * don't worry about the -f that might get sent.
   1311 	 * A -s is supposed to override it anyhow.
   1312 	 */
   1313 	if (require_SecurID)
   1314 		argv = addarg(argv, "-s");
   1315 #endif
   1316 #if	defined (AUTHENTICATE)
   1317 	if (auth_level >= 0 && autologin == AUTH_VALID) {
   1318 # if	!defined(NO_LOGIN_F)
   1319 		argv = addarg(argv, "-f");
   1320 # endif
   1321 		argv = addarg(argv, name);
   1322 	} else
   1323 #endif
   1324 	if (getenv("USER")) {
   1325 		argv = addarg(argv, getenv("USER"));
   1326 #if	defined(CRAY) && defined(NO_LOGIN_P)
   1327 		{
   1328 			register char **cpp;
   1329 			for (cpp = environ; *cpp; cpp++)
   1330 				argv = addarg(argv, *cpp);
   1331 		}
   1332 #endif
   1333 	}
   1334 	closelog();
   1335 	execv(_PATH_LOGIN, argv);
   1336 
   1337 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
   1338 	fatalperror(net, _PATH_LOGIN);
   1339 	/*NOTREACHED*/
   1340 }
   1341 
   1342 	char **
   1343 addarg(argv, val)
   1344 	register char **argv;
   1345 	register char *val;
   1346 {
   1347 	register char **cpp;
   1348 
   1349 	if (argv == NULL) {
   1350 		/*
   1351 		 * 10 entries, a leading length, and a null
   1352 		 */
   1353 		argv = (char **)malloc(sizeof(*argv) * 12);
   1354 		if (argv == NULL)
   1355 			return(NULL);
   1356 		*argv++ = (char *)10;
   1357 		*argv = (char *)0;
   1358 	}
   1359 	for (cpp = argv; *cpp; cpp++)
   1360 		;
   1361 	if (cpp == &argv[(int)argv[-1]]) {
   1362 		--argv;
   1363 		*argv = (char *)((int)(*argv) + 10);
   1364 		argv = (char **)realloc(argv, (int)(*argv) + 2);
   1365 		if (argv == NULL)
   1366 			return(NULL);
   1367 		argv++;
   1368 		cpp = &argv[(int)argv[-1] - 10];
   1369 	}
   1370 	*cpp++ = val;
   1371 	*cpp = 0;
   1372 	return(argv);
   1373 }
   1374 #endif	/* NEWINIT */
   1375 
   1376 /*
   1377  * cleanup()
   1378  *
   1379  * This is the routine to call when we are all through, to
   1380  * clean up anything that needs to be cleaned up.
   1381  */
   1382 	/* ARGSUSED */
   1383 	void
   1384 cleanup(sig)
   1385 	int sig;
   1386 {
   1387 #ifndef	CRAY
   1388 # if (BSD > 43) || defined(convex)
   1389 	char *p;
   1390 
   1391 	p = line + sizeof("/dev/") - 1;
   1392 	if (logout(p))
   1393 		logwtmp(p, "", "");
   1394 	(void)chmod(line, 0666);
   1395 	(void)chown(line, 0, 0);
   1396 	*p = 'p';
   1397 	(void)chmod(line, 0666);
   1398 	(void)chown(line, 0, 0);
   1399 	(void) shutdown(net, 2);
   1400 	exit(1);
   1401 # else
   1402 	void rmut();
   1403 
   1404 	rmut();
   1405 	vhangup();	/* XXX */
   1406 	(void) shutdown(net, 2);
   1407 	exit(1);
   1408 # endif
   1409 #else	/* CRAY */
   1410 # ifdef	NEWINIT
   1411 	(void) shutdown(net, 2);
   1412 	exit(1);
   1413 # else	/* NEWINIT */
   1414 	static int incleanup = 0;
   1415 	register int t;
   1416 
   1417 	/*
   1418 	 * 1: Pick up the zombie, if we are being called
   1419 	 *    as the signal handler.
   1420 	 * 2: If we are a nested cleanup(), return.
   1421 	 * 3: Try to clean up TMPDIR.
   1422 	 * 4: Fill in utmp with shutdown of process.
   1423 	 * 5: Close down the network and pty connections.
   1424 	 * 6: Finish up the TMPDIR cleanup, if needed.
   1425 	 */
   1426 	if (sig == SIGCHLD)
   1427 		while (waitpid(-1, 0, WNOHANG) > 0)
   1428 			;	/* VOID */
   1429 	t = sigblock(sigmask(SIGCHLD));
   1430 	if (incleanup) {
   1431 		sigsetmask(t);
   1432 		return;
   1433 	}
   1434 	incleanup = 1;
   1435 	sigsetmask(t);
   1436 
   1437 	t = cleantmp(&wtmp);
   1438 	setutent();	/* just to make sure */
   1439 	rmut(line);
   1440 	close(pty);
   1441 	(void) shutdown(net, 2);
   1442 	if (t == 0)
   1443 		cleantmp(&wtmp);
   1444 	exit(1);
   1445 # endif	/* NEWINT */
   1446 #endif	/* CRAY */
   1447 }
   1448 
   1449 #if	defined(CRAY) && !defined(NEWINIT)
   1450 /*
   1451  * _utmp_sig_rcv
   1452  * utmp_sig_init
   1453  * utmp_sig_wait
   1454  *	These three functions are used to coordinate the handling of
   1455  *	the utmp file between the server and the soon-to-be-login shell.
   1456  *	The server actually creates the utmp structure, the child calls
   1457  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
   1458  *	signals the future-login shell to proceed.
   1459  */
   1460 static int caught=0;		/* NZ when signal intercepted */
   1461 static void (*func)();		/* address of previous handler */
   1462 
   1463 	void
   1464 _utmp_sig_rcv(sig)
   1465 	int sig;
   1466 {
   1467 	caught = 1;
   1468 	(void) signal(SIGUSR1, func);
   1469 }
   1470 
   1471 	void
   1472 utmp_sig_init()
   1473 {
   1474 	/*
   1475 	 * register signal handler for UTMP creation
   1476 	 */
   1477 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
   1478 		fatalperror(net, "telnetd/signal");
   1479 }
   1480 
   1481 	void
   1482 utmp_sig_reset()
   1483 {
   1484 	(void) signal(SIGUSR1, func);	/* reset handler to default */
   1485 }
   1486 
   1487 	void
   1488 utmp_sig_wait()
   1489 {
   1490 	/*
   1491 	 * Wait for parent to write our utmp entry.
   1492 	 */
   1493 	sigoff();
   1494 	while (caught == 0) {
   1495 		pause();	/* wait until we get a signal (sigon) */
   1496 		sigoff();	/* turn off signals while we check caught */
   1497 	}
   1498 	sigon();		/* turn on signals again */
   1499 }
   1500 
   1501 	void
   1502 utmp_sig_notify(pid)
   1503 {
   1504 	kill(pid, SIGUSR1);
   1505 }
   1506 
   1507 static int gotsigjob = 0;
   1508 
   1509 	/*ARGSUSED*/
   1510 	void
   1511 sigjob(sig)
   1512 	int sig;
   1513 {
   1514 	register int jid;
   1515 	register struct jobtemp *jp;
   1516 
   1517 	while ((jid = waitjob(NULL)) != -1) {
   1518 		if (jid == 0) {
   1519 			return;
   1520 		}
   1521 		gotsigjob++;
   1522 		jobend(jid, NULL, NULL);
   1523 	}
   1524 }
   1525 
   1526 /*
   1527  * Clean up the TMPDIR that login created.
   1528  * The first time this is called we pick up the info
   1529  * from the utmp.  If the job has already gone away,
   1530  * then we'll clean up and be done.  If not, then
   1531  * when this is called the second time it will wait
   1532  * for the signal that the job is done.
   1533  */
   1534 	int
   1535 cleantmp(wtp)
   1536 	register struct utmp *wtp;
   1537 {
   1538 	struct utmp *utp;
   1539 	static int first = 1;
   1540 	register int mask, omask, ret;
   1541 	extern struct utmp *getutid P((struct utmp *));
   1542 
   1543 	mask = sigmask(WJSIGNAL);
   1544 
   1545 	if (first == 0) {
   1546 		omask = sigblock(mask);
   1547 		while (gotsigjob == 0)
   1548 			sigpause(omask);
   1549 		return(1);
   1550 	}
   1551 	first = 0;
   1552 	setutent();	/* just to make sure */
   1553 
   1554 	utp = getutid(wtp);
   1555 	if (utp == 0) {
   1556 		syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
   1557 		return(-1);
   1558 	}
   1559 	/*
   1560 	 * Nothing to clean up if the user shell was never started.
   1561 	 */
   1562 	if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
   1563 		return(1);
   1564 
   1565 	/*
   1566 	 * Block the WJSIGNAL while we are in jobend().
   1567 	 */
   1568 	omask = sigblock(mask);
   1569 	ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
   1570 	sigsetmask(omask);
   1571 	return(ret);
   1572 }
   1573 
   1574 	int
   1575 jobend(jid, path, user)
   1576 	register int jid;
   1577 	register char *path;
   1578 	register char *user;
   1579 {
   1580 	static int saved_jid = 0;
   1581 	static char saved_path[sizeof(wtmp.ut_tpath)+1];
   1582 	static char saved_user[sizeof(wtmp.ut_user)+1];
   1583 
   1584 	if (path) {
   1585 		strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
   1586 		strncpy(saved_user, user, sizeof(wtmp.ut_user));
   1587 		saved_path[sizeof(saved_path)] = '\0';
   1588 		saved_user[sizeof(saved_user)] = '\0';
   1589 	}
   1590 	if (saved_jid == 0) {
   1591 		saved_jid = jid;
   1592 		return(0);
   1593 	}
   1594 	cleantmpdir(jid, saved_path, saved_user);
   1595 	return(1);
   1596 }
   1597 
   1598 /*
   1599  * Fork a child process to clean up the TMPDIR
   1600  */
   1601 cleantmpdir(jid, tpath, user)
   1602 	register int jid;
   1603 	register char *tpath;
   1604 	register char *user;
   1605 {
   1606 	switch(fork()) {
   1607 	case -1:
   1608 		syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
   1609 							tpath);
   1610 		break;
   1611 	case 0:
   1612 		execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
   1613 		syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
   1614 							tpath, CLEANTMPCMD);
   1615 		exit(1);
   1616 	default:
   1617 		/*
   1618 		 * Forget about child.  We will exit, and
   1619 		 * /etc/init will pick it up.
   1620 		 */
   1621 		break;
   1622 	}
   1623 }
   1624 #endif	/* defined(CRAY) && !defined(NEWINIT) */
   1625 
   1626 /*
   1627  * rmut()
   1628  *
   1629  * This is the function called by cleanup() to
   1630  * remove the utmp entry for this person.
   1631  */
   1632 
   1633 #if	!defined(CRAY) && BSD <= 43
   1634 	void
   1635 rmut()
   1636 {
   1637 	register f;
   1638 	int found = 0;
   1639 	struct utmp *u, *utmp;
   1640 	int nutmp;
   1641 	struct stat statbf;
   1642 
   1643 	f = open(utmpf, O_RDWR);
   1644 	if (f >= 0) {
   1645 		(void) fstat(f, &statbf);
   1646 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
   1647 		if (!utmp)
   1648 			syslog(LOG_ERR, "utmp malloc failed");
   1649 		if (statbf.st_size && utmp) {
   1650 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
   1651 			nutmp /= sizeof(struct utmp);
   1652 
   1653 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
   1654 				if (SCMPN(u->ut_line, line+5) ||
   1655 				    u->ut_name[0]==0)
   1656 					continue;
   1657 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
   1658 				SCPYN(u->ut_name, "");
   1659 				SCPYN(u->ut_host, "");
   1660 				(void) time(&u->ut_time);
   1661 				(void) write(f, (char *)u, sizeof(wtmp));
   1662 				found++;
   1663 			}
   1664 		}
   1665 		(void) close(f);
   1666 	}
   1667 	if (found) {
   1668 		f = open(wtmpf, O_WRONLY|O_APPEND);
   1669 		if (f >= 0) {
   1670 			SCPYN(wtmp.ut_line, line+5);
   1671 			SCPYN(wtmp.ut_name, "");
   1672 			SCPYN(wtmp.ut_host, "");
   1673 			(void) time(&wtmp.ut_time);
   1674 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
   1675 			(void) close(f);
   1676 		}
   1677 	}
   1678 	(void) chmod(line, 0666);
   1679 	(void) chown(line, 0, 0);
   1680 	line[strlen("/dev/")] = 'p';
   1681 	(void) chmod(line, 0666);
   1682 	(void) chown(line, 0, 0);
   1683 }  /* end of rmut */
   1684 #endif	/* CRAY */
   1685