xref: /csrg-svn/libexec/telnetd/sys_term.c (revision 46809)
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.13 (Berkeley) 03/01/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 	cfsetospeed(&termbuf, (def_tspeed == -1) ? B9600 : def_tspeed);
971 	cfsetispeed(&termbuf, (def_rspeed == -1) ? B9600 : def_rspeed);
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 # else
1059 	close(open(line, O_RDWR));
1060 # endif
1061 	(void) dup2(t, 0);
1062 	(void) dup2(t, 1);
1063 	(void) dup2(t, 2);
1064 	close(t);
1065 	return(0);
1066 }
1067 #endif	/* BSD <= 43 */
1068 
1069 #ifdef	NEWINIT
1070 char *gen_id = "fe";
1071 #endif
1072 
1073 /*
1074  * startslave(host)
1075  *
1076  * Given a hostname, do whatever
1077  * is necessary to startup the login process on the slave side of the pty.
1078  */
1079 
1080 /* ARGSUSED */
1081 	void
1082 startslave(host, autologin, autoname)
1083 	char *host;
1084 	int autologin;
1085 	char *autoname;
1086 {
1087 	register int i;
1088 	long time();
1089 	char name[256];
1090 #ifdef	NEWINIT
1091 	extern char *ptyip;
1092 	struct init_request request;
1093 	void nologinproc();
1094 	register int n;
1095 #endif	/* NEWINIT */
1096 
1097 #if	defined(AUTHENTICATE)
1098 	if (!autoname || !autoname[0])
1099 		autologin = 0;
1100 
1101 	if (autologin < auth_level) {
1102 		fatal(net, "Authorization failed");
1103 		exit(1);
1104 	}
1105 #endif
1106 
1107 #ifndef	NEWINIT
1108 # ifdef	CRAY
1109 	utmp_sig_init();
1110 # endif	/* CRAY */
1111 
1112 	if ((i = fork()) < 0)
1113 		fatalperror(net, "fork");
1114 	if (i) {
1115 # ifdef	CRAY
1116 		/*
1117 		 * Cray parent will create utmp entry for child and send
1118 		 * signal to child to tell when done.  Child waits for signal
1119 		 * before doing anything important.
1120 		 */
1121 		register int pid = i;
1122 		void sigjob P((int));
1123 
1124 		setpgrp();
1125 		utmp_sig_reset();		/* reset handler to default */
1126 		/*
1127 		 * Create utmp entry for child
1128 		 */
1129 		(void) time(&wtmp.ut_time);
1130 		wtmp.ut_type = LOGIN_PROCESS;
1131 		wtmp.ut_pid = pid;
1132 		SCPYN(wtmp.ut_user, "LOGIN");
1133 		SCPYN(wtmp.ut_host, host);
1134 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
1135 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
1136 		pututline(&wtmp);
1137 		endutent();
1138 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1139 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
1140 			(void) close(i);
1141 		}
1142 		(void) signal(WJSIGNAL, sigjob);
1143 		utmp_sig_notify(pid);
1144 # endif	/* CRAY */
1145 	} else {
1146 		getptyslave();
1147 		start_login(host, autologin, autoname);
1148 		/*NOTREACHED*/
1149 	}
1150 #else	/* NEWINIT */
1151 
1152 	/*
1153 	 * Init will start up login process if we ask nicely.  We only wait
1154 	 * for it to start up and begin normal telnet operation.
1155 	 */
1156 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1157 		char tbuf[128];
1158 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
1159 		fatalperror(net, tbuf);
1160 	}
1161 	memset((char *)&request, 0, sizeof(request));
1162 	request.magic = INIT_MAGIC;
1163 	SCPYN(request.gen_id, gen_id);
1164 	SCPYN(request.tty_id, &line[8]);
1165 	SCPYN(request.host, host);
1166 	SCPYN(request.term_type, terminaltype ? terminaltype : "network");
1167 #if	!defined(UNICOS5)
1168 	request.signal = SIGCLD;
1169 	request.pid = getpid();
1170 #endif
1171 #ifdef BFTPDAEMON
1172 	/*
1173 	 * Are we working as the bftp daemon?
1174 	 */
1175 	if (bftpd) {
1176 		SCPYN(request.exec_name, BFTPPATH);
1177 	}
1178 #endif /* BFTPDAEMON */
1179 	if (write(i, (char *)&request, sizeof(request)) < 0) {
1180 		char tbuf[128];
1181 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
1182 		fatalperror(net, tbuf);
1183 	}
1184 	(void) close(i);
1185 	(void) signal(SIGALRM, nologinproc);
1186 	for (i = 0; ; i++) {
1187 		char tbuf[128];
1188 		alarm(15);
1189 		n = read(pty, ptyip, BUFSIZ);
1190 		if (i == 3 || n >= 0 || !gotalarm)
1191 			break;
1192 		gotalarm = 0;
1193 		sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1194 		(void) write(net, tbuf, strlen(tbuf));
1195 	}
1196 	if (n < 0 && gotalarm)
1197 		fatal(net, "/etc/init didn't start login process");
1198 	pcc += n;
1199 	alarm(0);
1200 	(void) signal(SIGALRM, SIG_DFL);
1201 
1202 	return;
1203 #endif	/* NEWINIT */
1204 }
1205 
1206 char	*envinit[3];
1207 extern char **environ;
1208 
1209 	void
1210 init_env()
1211 {
1212 	extern char *getenv();
1213 	char **envp;
1214 
1215 	envp = envinit;
1216 	if (*envp = getenv("TZ"))
1217 		*envp++ -= 3;
1218 #ifdef	CRAY
1219 	else
1220 		*envp++ = "TZ=GMT0";
1221 #endif
1222 	*envp = 0;
1223 	environ = envinit;
1224 }
1225 
1226 #ifndef	NEWINIT
1227 
1228 /*
1229  * start_login(host)
1230  *
1231  * Assuming that we are now running as a child processes, this
1232  * function will turn us into the login process.
1233  */
1234 
1235 	void
1236 start_login(host, autologin, name)
1237 	char *host;
1238 	int autologin;
1239 	char *name;
1240 {
1241 	register char *cp;
1242 	register char **argv;
1243 	char **addarg();
1244 
1245 	/*
1246 	 * -h : pass on name of host.
1247 	 *		WARNING:  -h is accepted by login if and only if
1248 	 *			getuid() == 0.
1249 	 * -p : don't clobber the environment (so terminal type stays set).
1250 	 *
1251 	 * -f : force this login, he has already been authenticated
1252 	 */
1253 	argv = addarg(0, "login");
1254 	argv = addarg(argv, "-h");
1255 	argv = addarg(argv, host);
1256 #if	!defined(NO_LOGIN_P)
1257 	argv = addarg(argv, "-p");
1258 #endif
1259 #ifdef	BFTPDAEMON
1260 	/*
1261 	 * Are we working as the bftp daemon?  If so, then ask login
1262 	 * to start bftp instead of shell.
1263 	 */
1264 	if (bftpd) {
1265 		argv = addarg(argv, "-e");
1266 		argv = addarg(argv, BFTPPATH);
1267 	} else
1268 #endif
1269 #if	defined (SecurID)
1270 	/*
1271 	 * don't worry about the -f that might get sent.
1272 	 * A -s is supposed to override it anyhow.
1273 	 */
1274 	if (require_SecurID)
1275 		argv = addarg(argv, "-s");
1276 #endif
1277 #if	defined (AUTHENTICATE)
1278 	if (auth_level >= 0 && autologin == AUTH_VALID) {
1279 # if	!defined(NO_LOGIN_F)
1280 		argv = addarg(argv, "-f");
1281 # endif
1282 		argv = addarg(argv, name);
1283 	} else
1284 #endif
1285 	if (getenv("USER")) {
1286 		argv = addarg(argv, getenv("USER"));
1287 #if	defined(CRAY) && defined(NO_LOGIN_P)
1288 		{
1289 			register char **cpp;
1290 			for (cpp = environ; *cpp; cpp++)
1291 				argv = addarg(argv, *cpp);
1292 		}
1293 #endif
1294 	}
1295 	closelog();
1296 	execv(_PATH_LOGIN, argv);
1297 
1298 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
1299 	fatalperror(net, _PATH_LOGIN);
1300 	/*NOTREACHED*/
1301 }
1302 
1303 	char **
1304 addarg(argv, val)
1305 	register char **argv;
1306 	register char *val;
1307 {
1308 	register char **cpp;
1309 
1310 	if (argv == NULL) {
1311 		/*
1312 		 * 10 entries, a leading length, and a null
1313 		 */
1314 		argv = (char **)malloc(sizeof(*argv) * 12);
1315 		if (argv == NULL)
1316 			return(NULL);
1317 		*argv++ = (char *)10;
1318 		*argv = (char *)0;
1319 	}
1320 	for (cpp = argv; *cpp; cpp++)
1321 		;
1322 	if (cpp == &argv[(int)argv[-1]]) {
1323 		--argv;
1324 		*argv = (char *)((int)(*argv) + 10);
1325 		argv = (char **)realloc(argv, (int)(*argv) + 2);
1326 		if (argv == NULL)
1327 			return(NULL);
1328 		argv++;
1329 		cpp = &argv[(int)argv[-1] - 10];
1330 	}
1331 	*cpp++ = val;
1332 	*cpp = 0;
1333 	return(argv);
1334 }
1335 #endif	/* NEWINIT */
1336 
1337 /*
1338  * cleanup()
1339  *
1340  * This is the routine to call when we are all through, to
1341  * clean up anything that needs to be cleaned up.
1342  */
1343 	/* ARGSUSED */
1344 	void
1345 cleanup(sig)
1346 	int sig;
1347 {
1348 #ifndef	CRAY
1349 # if (BSD > 43) || defined(convex)
1350 	char *p;
1351 
1352 	p = line + sizeof("/dev/") - 1;
1353 	if (logout(p))
1354 		logwtmp(p, "", "");
1355 	(void)chmod(line, 0666);
1356 	(void)chown(line, 0, 0);
1357 	*p = 'p';
1358 	(void)chmod(line, 0666);
1359 	(void)chown(line, 0, 0);
1360 	(void) shutdown(net, 2);
1361 	exit(1);
1362 # else
1363 	void rmut();
1364 
1365 	rmut();
1366 	vhangup();	/* XXX */
1367 	(void) shutdown(net, 2);
1368 	exit(1);
1369 # endif
1370 #else	/* CRAY */
1371 # ifdef	NEWINIT
1372 	(void) shutdown(net, 2);
1373 	exit(1);
1374 # else	/* NEWINIT */
1375 	static int incleanup = 0;
1376 	register int t;
1377 
1378 	/*
1379 	 * 1: Pick up the zombie, if we are being called
1380 	 *    as the signal handler.
1381 	 * 2: If we are a nested cleanup(), return.
1382 	 * 3: Try to clean up TMPDIR.
1383 	 * 4: Fill in utmp with shutdown of process.
1384 	 * 5: Close down the network and pty connections.
1385 	 * 6: Finish up the TMPDIR cleanup, if needed.
1386 	 */
1387 	if (sig == SIGCHLD)
1388 		while (waitpid(-1, 0, WNOHANG) > 0)
1389 			;	/* VOID */
1390 	t = sigblock(sigmask(SIGCHLD));
1391 	if (incleanup) {
1392 		sigsetmask(t);
1393 		return;
1394 	}
1395 	incleanup = 1;
1396 	sigsetmask(t);
1397 
1398 	t = cleantmp(&wtmp);
1399 	setutent();	/* just to make sure */
1400 	rmut(line);
1401 	close(pty);
1402 	(void) shutdown(net, 2);
1403 	if (t == 0)
1404 		cleantmp(&wtmp);
1405 	exit(1);
1406 # endif	/* NEWINT */
1407 #endif	/* CRAY */
1408 }
1409 
1410 #if	defined(CRAY) && !defined(NEWINIT)
1411 /*
1412  * _utmp_sig_rcv
1413  * utmp_sig_init
1414  * utmp_sig_wait
1415  *	These three functions are used to coordinate the handling of
1416  *	the utmp file between the server and the soon-to-be-login shell.
1417  *	The server actually creates the utmp structure, the child calls
1418  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
1419  *	signals the future-login shell to proceed.
1420  */
1421 static int caught=0;		/* NZ when signal intercepted */
1422 static void (*func)();		/* address of previous handler */
1423 
1424 	void
1425 _utmp_sig_rcv(sig)
1426 	int sig;
1427 {
1428 	caught = 1;
1429 	(void) signal(SIGUSR1, func);
1430 }
1431 
1432 	void
1433 utmp_sig_init()
1434 {
1435 	/*
1436 	 * register signal handler for UTMP creation
1437 	 */
1438 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1439 		fatalperror(net, "telnetd/signal");
1440 }
1441 
1442 	void
1443 utmp_sig_reset()
1444 {
1445 	(void) signal(SIGUSR1, func);	/* reset handler to default */
1446 }
1447 
1448 	void
1449 utmp_sig_wait()
1450 {
1451 	/*
1452 	 * Wait for parent to write our utmp entry.
1453 	 */
1454 	sigoff();
1455 	while (caught == 0) {
1456 		pause();	/* wait until we get a signal (sigon) */
1457 		sigoff();	/* turn off signals while we check caught */
1458 	}
1459 	sigon();		/* turn on signals again */
1460 }
1461 
1462 	void
1463 utmp_sig_notify(pid)
1464 {
1465 	kill(pid, SIGUSR1);
1466 }
1467 
1468 static int gotsigjob = 0;
1469 
1470 	/*ARGSUSED*/
1471 	void
1472 sigjob(sig)
1473 	int sig;
1474 {
1475 	register int jid;
1476 	register struct jobtemp *jp;
1477 
1478 	while ((jid = waitjob(NULL)) != -1) {
1479 		if (jid == 0) {
1480 			return;
1481 		}
1482 		gotsigjob++;
1483 		jobend(jid, NULL, NULL);
1484 	}
1485 }
1486 
1487 /*
1488  * Clean up the TMPDIR that login created.
1489  * The first time this is called we pick up the info
1490  * from the utmp.  If the job has already gone away,
1491  * then we'll clean up and be done.  If not, then
1492  * when this is called the second time it will wait
1493  * for the signal that the job is done.
1494  */
1495 	int
1496 cleantmp(wtp)
1497 	register struct utmp *wtp;
1498 {
1499 	struct utmp *utp;
1500 	static int first = 1;
1501 	register int mask, omask, ret;
1502 	extern struct utmp *getutid P((struct utmp *));
1503 
1504 	mask = sigmask(WJSIGNAL);
1505 
1506 	if (first == 0) {
1507 		omask = sigblock(mask);
1508 		while (gotsigjob == 0)
1509 			sigpause(omask);
1510 		return(1);
1511 	}
1512 	first = 0;
1513 	setutent();	/* just to make sure */
1514 
1515 	utp = getutid(wtp);
1516 	if (utp == 0) {
1517 		syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1518 		return(-1);
1519 	}
1520 	/*
1521 	 * Nothing to clean up if the user shell was never started.
1522 	 */
1523 	if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1524 		return(1);
1525 
1526 	/*
1527 	 * Block the WJSIGNAL while we are in jobend().
1528 	 */
1529 	omask = sigblock(mask);
1530 	ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1531 	sigsetmask(omask);
1532 	return(ret);
1533 }
1534 
1535 	int
1536 jobend(jid, path, user)
1537 	register int jid;
1538 	register char *path;
1539 	register char *user;
1540 {
1541 	static int saved_jid = 0;
1542 	static char saved_path[sizeof(wtmp.ut_tpath)+1];
1543 	static char saved_user[sizeof(wtmp.ut_user)+1];
1544 
1545 	if (path) {
1546 		strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
1547 		strncpy(saved_user, user, sizeof(wtmp.ut_user));
1548 		saved_path[sizeof(saved_path)] = '\0';
1549 		saved_user[sizeof(saved_user)] = '\0';
1550 	}
1551 	if (saved_jid == 0) {
1552 		saved_jid = jid;
1553 		return(0);
1554 	}
1555 	cleantmpdir(jid, saved_path, saved_user);
1556 	return(1);
1557 }
1558 
1559 /*
1560  * Fork a child process to clean up the TMPDIR
1561  */
1562 cleantmpdir(jid, tpath, user)
1563 	register int jid;
1564 	register char *tpath;
1565 	register char *user;
1566 {
1567 	switch(fork()) {
1568 	case -1:
1569 		syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1570 							tpath);
1571 		break;
1572 	case 0:
1573 		execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
1574 		syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1575 							tpath, CLEANTMPCMD);
1576 		exit(1);
1577 	default:
1578 		/*
1579 		 * Forget about child.  We will exit, and
1580 		 * /etc/init will pick it up.
1581 		 */
1582 		break;
1583 	}
1584 }
1585 #endif	/* defined(CRAY) && !defined(NEWINIT) */
1586 
1587 /*
1588  * rmut()
1589  *
1590  * This is the function called by cleanup() to
1591  * remove the utmp entry for this person.
1592  */
1593 
1594 #if	!defined(CRAY) && BSD <= 43
1595 	void
1596 rmut()
1597 {
1598 	register f;
1599 	int found = 0;
1600 	struct utmp *u, *utmp;
1601 	int nutmp;
1602 	struct stat statbf;
1603 
1604 	f = open(utmpf, O_RDWR);
1605 	if (f >= 0) {
1606 		(void) fstat(f, &statbf);
1607 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1608 		if (!utmp)
1609 			syslog(LOG_ERR, "utmp malloc failed");
1610 		if (statbf.st_size && utmp) {
1611 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
1612 			nutmp /= sizeof(struct utmp);
1613 
1614 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
1615 				if (SCMPN(u->ut_line, line+5) ||
1616 				    u->ut_name[0]==0)
1617 					continue;
1618 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
1619 				SCPYN(u->ut_name, "");
1620 				SCPYN(u->ut_host, "");
1621 				(void) time(&u->ut_time);
1622 				(void) write(f, (char *)u, sizeof(wtmp));
1623 				found++;
1624 			}
1625 		}
1626 		(void) close(f);
1627 	}
1628 	if (found) {
1629 		f = open(wtmpf, O_WRONLY|O_APPEND);
1630 		if (f >= 0) {
1631 			SCPYN(wtmp.ut_line, line+5);
1632 			SCPYN(wtmp.ut_name, "");
1633 			SCPYN(wtmp.ut_host, "");
1634 			(void) time(&wtmp.ut_time);
1635 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
1636 			(void) close(f);
1637 		}
1638 	}
1639 	(void) chmod(line, 0666);
1640 	(void) chown(line, 0, 0);
1641 	line[strlen("/dev/")] = 'p';
1642 	(void) chmod(line, 0666);
1643 	(void) chown(line, 0, 0);
1644 }  /* end of rmut */
1645 #endif	/* CRAY */
1646