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