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