sys_term.c revision 45428
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)sys_term.c	8.4+1 (Berkeley) 5/30/95";
37#endif
38static const char rcsid[] =
39	"$Id: sys_term.c,v 1.5 1998/09/01 15:17:28 gpalmer Exp $";
40#endif /* not lint */
41
42#include "telnetd.h"
43#include "pathnames.h"
44
45#if	defined(AUTHENTICATION)
46#include <libtelnet/auth.h>
47#endif
48
49extern char *altlogin;
50int cleanopen(char *line);
51void scrub_env(void);
52
53#if defined(CRAY) || defined(__hpux)
54# define PARENT_DOES_UTMP
55#endif
56
57#ifdef	NEWINIT
58#include <initreq.h>
59#else	/* NEWINIT*/
60# ifdef	UTMPX
61# include <utmpx.h>
62struct	utmpx wtmp;
63# else
64# include <utmp.h>
65struct	utmp wtmp;
66# endif /* UTMPX */
67
68# ifndef PARENT_DOES_UTMP
69#ifdef _PATH_WTMP
70char    wtmpf[] = _PATH_WTMP;
71#else
72char	wtmpf[]	= "/usr/adm/wtmp";
73#endif
74#ifdef _PATH_UTMP
75char    utmpf[] = _PATH_UTMP;
76#else
77char	utmpf[] = "/etc/utmp";
78#endif
79# else /* PARENT_DOES_UTMP */
80char	wtmpf[]	= "/etc/wtmp";
81# endif /* PARENT_DOES_UTMP */
82
83#include <libutil.h>
84
85# ifdef CRAY
86#include <tmpdir.h>
87#include <sys/wait.h>
88#  if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1')
89#   define UNICOS7x
90#  endif
91
92#  ifdef UNICOS7x
93#include <sys/sysv.h>
94#include <sys/secstat.h>
95extern int secflag;
96extern struct sysv sysv;
97#  endif /* UNICOS7x */
98# endif	/* CRAY */
99#endif	/* NEWINIT */
100
101#ifdef	STREAMSPTY
102#include <sac.h>
103#include <sys/stropts.h>
104#endif
105
106#define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
107#define SCMPN(a, b)	strncmp(a, b, sizeof(a))
108
109#ifdef	STREAMS
110#include <sys/stream.h>
111#endif
112#ifdef __hpux
113#include <sys/resource.h>
114#include <sys/proc.h>
115#endif
116#include <sys/tty.h>
117#ifdef	t_erase
118#undef	t_erase
119#undef	t_kill
120#undef	t_intrc
121#undef	t_quitc
122#undef	t_startc
123#undef	t_stopc
124#undef	t_eofc
125#undef	t_brkc
126#undef	t_suspc
127#undef	t_dsuspc
128#undef	t_rprntc
129#undef	t_flushc
130#undef	t_werasc
131#undef	t_lnextc
132#endif
133
134#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
135# define EXTPROC 0400
136#endif
137
138#ifndef	USE_TERMIO
139struct termbuf {
140	struct sgttyb sg;
141	struct tchars tc;
142	struct ltchars ltc;
143	int state;
144	int lflags;
145} termbuf, termbuf2;
146# define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
147# define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
148# define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
149# define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
150#else	/* USE_TERMIO */
151# ifdef	SYSV_TERMIO
152#	define termios termio
153# endif
154# ifndef	TCSANOW
155#  ifdef TCSETS
156#   define	TCSANOW		TCSETS
157#   define	TCSADRAIN	TCSETSW
158#   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
159#  else
160#   ifdef TCSETA
161#    define	TCSANOW		TCSETA
162#    define	TCSADRAIN	TCSETAW
163#    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
164#   else
165#    define	TCSANOW		TIOCSETA
166#    define	TCSADRAIN	TIOCSETAW
167#    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
168#   endif
169#  endif
170#  define	tcsetattr(f, a, t)	ioctl(f, a, t)
171#  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
172					(tp)->c_cflag |= (val)
173#  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
174#  ifdef CIBAUD
175#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
176					(tp)->c_cflag |= ((val)<<IBSHIFT)
177#   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
178#  else
179#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
180					(tp)->c_cflag |= (val)
181#   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
182#  endif
183# endif /* TCSANOW */
184struct termios termbuf, termbuf2;	/* pty control structure */
185# ifdef  STREAMSPTY
186int ttyfd = -1;
187# endif
188#endif	/* USE_TERMIO */
189
190#include <sys/types.h>
191#include <libutil.h>
192
193int cleanopen __P((char *));
194void scrub_env __P((void));
195
196/*
197 * init_termbuf()
198 * copy_termbuf(cp)
199 * set_termbuf()
200 *
201 * These three routines are used to get and set the "termbuf" structure
202 * to and from the kernel.  init_termbuf() gets the current settings.
203 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
204 * set_termbuf() writes the structure into the kernel.
205 */
206
207	void
208init_termbuf()
209{
210#ifndef	USE_TERMIO
211	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
212	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
213	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
214# ifdef	TIOCGSTATE
215	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
216# endif
217#else
218# ifdef  STREAMSPTY
219	(void) tcgetattr(ttyfd, &termbuf);
220# else
221	(void) tcgetattr(pty, &termbuf);
222# endif
223#endif
224	termbuf2 = termbuf;
225}
226
227#if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
228	void
229copy_termbuf(cp, len)
230	char *cp;
231	int len;
232{
233	if (len > sizeof(termbuf))
234		len = sizeof(termbuf);
235	memmove((char *)&termbuf, cp, len);
236	termbuf2 = termbuf;
237}
238#endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
239
240	void
241set_termbuf()
242{
243	/*
244	 * Only make the necessary changes.
245	 */
246#ifndef	USE_TERMIO
247	if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
248							sizeof(termbuf.sg)))
249		(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
250	if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
251							sizeof(termbuf.tc)))
252		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
253	if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
254							sizeof(termbuf.ltc)))
255		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
256	if (termbuf.lflags != termbuf2.lflags)
257		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
258#else	/* USE_TERMIO */
259	if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
260# ifdef  STREAMSPTY
261		(void) tcsetattr(ttyfd, TCSANOW, &termbuf);
262# else
263		(void) tcsetattr(pty, TCSANOW, &termbuf);
264# endif
265# if	defined(CRAY2) && defined(UNICOS5)
266	needtermstat = 1;
267# endif
268#endif	/* USE_TERMIO */
269}
270
271
272/*
273 * spcset(func, valp, valpp)
274 *
275 * This function takes various special characters (func), and
276 * sets *valp to the current value of that character, and
277 * *valpp to point to where in the "termbuf" structure that
278 * value is kept.
279 *
280 * It returns the SLC_ level of support for this function.
281 */
282
283#ifndef	USE_TERMIO
284	int
285spcset(func, valp, valpp)
286	int func;
287	cc_t *valp;
288	cc_t **valpp;
289{
290	switch(func) {
291	case SLC_EOF:
292		*valp = termbuf.tc.t_eofc;
293		*valpp = (cc_t *)&termbuf.tc.t_eofc;
294		return(SLC_VARIABLE);
295	case SLC_EC:
296		*valp = termbuf.sg.sg_erase;
297		*valpp = (cc_t *)&termbuf.sg.sg_erase;
298		return(SLC_VARIABLE);
299	case SLC_EL:
300		*valp = termbuf.sg.sg_kill;
301		*valpp = (cc_t *)&termbuf.sg.sg_kill;
302		return(SLC_VARIABLE);
303	case SLC_IP:
304		*valp = termbuf.tc.t_intrc;
305		*valpp = (cc_t *)&termbuf.tc.t_intrc;
306		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
307	case SLC_ABORT:
308		*valp = termbuf.tc.t_quitc;
309		*valpp = (cc_t *)&termbuf.tc.t_quitc;
310		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
311	case SLC_XON:
312		*valp = termbuf.tc.t_startc;
313		*valpp = (cc_t *)&termbuf.tc.t_startc;
314		return(SLC_VARIABLE);
315	case SLC_XOFF:
316		*valp = termbuf.tc.t_stopc;
317		*valpp = (cc_t *)&termbuf.tc.t_stopc;
318		return(SLC_VARIABLE);
319	case SLC_AO:
320		*valp = termbuf.ltc.t_flushc;
321		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
322		return(SLC_VARIABLE);
323	case SLC_SUSP:
324		*valp = termbuf.ltc.t_suspc;
325		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
326		return(SLC_VARIABLE);
327	case SLC_EW:
328		*valp = termbuf.ltc.t_werasc;
329		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
330		return(SLC_VARIABLE);
331	case SLC_RP:
332		*valp = termbuf.ltc.t_rprntc;
333		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
334		return(SLC_VARIABLE);
335	case SLC_LNEXT:
336		*valp = termbuf.ltc.t_lnextc;
337		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
338		return(SLC_VARIABLE);
339	case SLC_FORW1:
340		*valp = termbuf.tc.t_brkc;
341		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
342		return(SLC_VARIABLE);
343	case SLC_BRK:
344	case SLC_SYNCH:
345	case SLC_AYT:
346	case SLC_EOR:
347		*valp = (cc_t)0;
348		*valpp = (cc_t *)0;
349		return(SLC_DEFAULT);
350	default:
351		*valp = (cc_t)0;
352		*valpp = (cc_t *)0;
353		return(SLC_NOSUPPORT);
354	}
355}
356
357#else	/* USE_TERMIO */
358
359	int
360spcset(func, valp, valpp)
361	int func;
362	cc_t *valp;
363	cc_t **valpp;
364{
365
366#define	setval(a, b)	*valp = termbuf.c_cc[a]; \
367			*valpp = &termbuf.c_cc[a]; \
368			return(b);
369#define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
370
371	switch(func) {
372	case SLC_EOF:
373		setval(VEOF, SLC_VARIABLE);
374	case SLC_EC:
375		setval(VERASE, SLC_VARIABLE);
376	case SLC_EL:
377		setval(VKILL, SLC_VARIABLE);
378	case SLC_IP:
379		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
380	case SLC_ABORT:
381		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
382	case SLC_XON:
383#ifdef	VSTART
384		setval(VSTART, SLC_VARIABLE);
385#else
386		defval(0x13);
387#endif
388	case SLC_XOFF:
389#ifdef	VSTOP
390		setval(VSTOP, SLC_VARIABLE);
391#else
392		defval(0x11);
393#endif
394	case SLC_EW:
395#ifdef	VWERASE
396		setval(VWERASE, SLC_VARIABLE);
397#else
398		defval(0);
399#endif
400	case SLC_RP:
401#ifdef	VREPRINT
402		setval(VREPRINT, SLC_VARIABLE);
403#else
404		defval(0);
405#endif
406	case SLC_LNEXT:
407#ifdef	VLNEXT
408		setval(VLNEXT, SLC_VARIABLE);
409#else
410		defval(0);
411#endif
412	case SLC_AO:
413#if	!defined(VDISCARD) && defined(VFLUSHO)
414# define VDISCARD VFLUSHO
415#endif
416#ifdef	VDISCARD
417		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
418#else
419		defval(0);
420#endif
421	case SLC_SUSP:
422#ifdef	VSUSP
423		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
424#else
425		defval(0);
426#endif
427#ifdef	VEOL
428	case SLC_FORW1:
429		setval(VEOL, SLC_VARIABLE);
430#endif
431#ifdef	VEOL2
432	case SLC_FORW2:
433		setval(VEOL2, SLC_VARIABLE);
434#endif
435	case SLC_AYT:
436#ifdef	VSTATUS
437		setval(VSTATUS, SLC_VARIABLE);
438#else
439		defval(0);
440#endif
441
442	case SLC_BRK:
443	case SLC_SYNCH:
444	case SLC_EOR:
445		defval(0);
446
447	default:
448		*valp = 0;
449		*valpp = 0;
450		return(SLC_NOSUPPORT);
451	}
452}
453#endif	/* USE_TERMIO */
454
455#ifdef CRAY
456/*
457 * getnpty()
458 *
459 * Return the number of pty's configured into the system.
460 */
461	int
462getnpty()
463{
464#ifdef _SC_CRAY_NPTY
465	int numptys;
466
467	if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
468		return numptys;
469	else
470#endif /* _SC_CRAY_NPTY */
471		return 128;
472}
473#endif /* CRAY */
474
475#ifndef	convex
476/*
477 * getpty()
478 *
479 * Allocate a pty.  As a side effect, the external character
480 * array "line" contains the name of the slave side.
481 *
482 * Returns the file descriptor of the opened pty.
483 */
484#ifndef	__GNUC__
485char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
486#else
487static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
488char *line = Xline;
489#endif
490#ifdef	CRAY
491char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
492#endif	/* CRAY */
493
494	int
495getpty(ptynum)
496int *ptynum;
497{
498	register int p;
499#ifdef	STREAMSPTY
500	int t;
501	char *ptsname();
502
503	p = open("/dev/ptmx", 2);
504	if (p > 0) {
505		grantpt(p);
506		unlockpt(p);
507		strcpy(line, ptsname(p));
508		return(p);
509	}
510
511#else	/* ! STREAMSPTY */
512#ifndef CRAY
513	register char *cp, *p1, *p2;
514	register int i;
515#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
516	int dummy;
517#endif
518
519#ifndef	__hpux
520	(void) strcpy(line, "/dev/ptyXX");
521	p1 = &line[8];
522	p2 = &line[9];
523#else
524	(void) strcpy(line, "/dev/ptym/ptyXX");
525	p1 = &line[13];
526	p2 = &line[14];
527#endif
528
529	for (cp = "pqrsPQRS"; *cp; cp++) {
530		struct stat stb;
531
532		*p1 = *cp;
533		*p2 = '0';
534		/*
535		 * This stat() check is just to keep us from
536		 * looping through all 256 combinations if there
537		 * aren't that many ptys available.
538		 */
539		if (stat(line, &stb) < 0)
540			break;
541		for (i = 0; i < 32; i++) {
542			*p2 = "0123456789abcdefghijklmnopqrstuv"[i];
543			p = open(line, 2);
544			if (p > 0) {
545#ifndef	__hpux
546				line[5] = 't';
547#else
548				for (p1 = &line[8]; *p1; p1++)
549					*p1 = *(p1+1);
550				line[9] = 't';
551#endif
552				chown(line, 0, 0);
553				chmod(line, 0600);
554#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
555				if (ioctl(p, TIOCGPGRP, &dummy) == 0
556				    || errno != EIO) {
557					chmod(line, 0666);
558					close(p);
559					line[5] = 'p';
560				} else
561#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
562					return(p);
563			}
564		}
565	}
566#else	/* CRAY */
567	extern lowpty, highpty;
568	struct stat sb;
569
570	for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
571		(void) sprintf(myline, "/dev/pty/%03d", *ptynum);
572		p = open(myline, 2);
573		if (p < 0)
574			continue;
575		(void) sprintf(line, "/dev/ttyp%03d", *ptynum);
576		/*
577		 * Here are some shenanigans to make sure that there
578		 * are no listeners lurking on the line.
579		 */
580		if(stat(line, &sb) < 0) {
581			(void) close(p);
582			continue;
583		}
584		if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
585			chown(line, 0, 0);
586			chmod(line, 0600);
587			(void)close(p);
588			p = open(myline, 2);
589			if (p < 0)
590				continue;
591		}
592		/*
593		 * Now it should be safe...check for accessability.
594		 */
595		if (access(line, 6) == 0)
596			return(p);
597		else {
598			/* no tty side to pty so skip it */
599			(void) close(p);
600		}
601	}
602#endif	/* CRAY */
603#endif	/* STREAMSPTY */
604	return(-1);
605}
606#endif	/* convex */
607
608#ifdef	LINEMODE
609/*
610 * tty_flowmode()	Find out if flow control is enabled or disabled.
611 * tty_linemode()	Find out if linemode (external processing) is enabled.
612 * tty_setlinemod(on)	Turn on/off linemode.
613 * tty_isecho()		Find out if echoing is turned on.
614 * tty_setecho(on)	Enable/disable character echoing.
615 * tty_israw()		Find out if terminal is in RAW mode.
616 * tty_binaryin(on)	Turn on/off BINARY on input.
617 * tty_binaryout(on)	Turn on/off BINARY on output.
618 * tty_isediting()	Find out if line editing is enabled.
619 * tty_istrapsig()	Find out if signal trapping is enabled.
620 * tty_setedit(on)	Turn on/off line editing.
621 * tty_setsig(on)	Turn on/off signal trapping.
622 * tty_issofttab()	Find out if tab expansion is enabled.
623 * tty_setsofttab(on)	Turn on/off soft tab expansion.
624 * tty_islitecho()	Find out if typed control chars are echoed literally
625 * tty_setlitecho()	Turn on/off literal echo of control chars
626 * tty_tspeed(val)	Set transmit speed to val.
627 * tty_rspeed(val)	Set receive speed to val.
628 */
629
630#ifdef convex
631static int linestate;
632#endif
633
634	int
635tty_linemode()
636{
637#ifndef convex
638#ifndef	USE_TERMIO
639	return(termbuf.state & TS_EXTPROC);
640#else
641	return(termbuf.c_lflag & EXTPROC);
642#endif
643#else
644	return(linestate);
645#endif
646}
647
648	void
649tty_setlinemode(on)
650	int on;
651{
652#ifdef	TIOCEXT
653# ifndef convex
654	set_termbuf();
655# else
656	linestate = on;
657# endif
658	(void) ioctl(pty, TIOCEXT, (char *)&on);
659# ifndef convex
660	init_termbuf();
661# endif
662#else	/* !TIOCEXT */
663# ifdef	EXTPROC
664	if (on)
665		termbuf.c_lflag |= EXTPROC;
666	else
667		termbuf.c_lflag &= ~EXTPROC;
668# endif
669#endif	/* TIOCEXT */
670}
671#endif	/* LINEMODE */
672
673	int
674tty_isecho()
675{
676#ifndef USE_TERMIO
677	return (termbuf.sg.sg_flags & ECHO);
678#else
679	return (termbuf.c_lflag & ECHO);
680#endif
681}
682
683	int
684tty_flowmode()
685{
686#ifndef USE_TERMIO
687	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
688#else
689	return((termbuf.c_iflag & IXON) ? 1 : 0);
690#endif
691}
692
693	int
694tty_restartany()
695{
696#ifndef USE_TERMIO
697# ifdef	DECCTQ
698	return((termbuf.lflags & DECCTQ) ? 0 : 1);
699# else
700	return(-1);
701# endif
702#else
703	return((termbuf.c_iflag & IXANY) ? 1 : 0);
704#endif
705}
706
707	void
708tty_setecho(on)
709	int on;
710{
711#ifndef	USE_TERMIO
712	if (on)
713		termbuf.sg.sg_flags |= ECHO|CRMOD;
714	else
715		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
716#else
717	if (on)
718		termbuf.c_lflag |= ECHO;
719	else
720		termbuf.c_lflag &= ~ECHO;
721#endif
722}
723
724	int
725tty_israw()
726{
727#ifndef USE_TERMIO
728	return(termbuf.sg.sg_flags & RAW);
729#else
730	return(!(termbuf.c_lflag & ICANON));
731#endif
732}
733
734#if	defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
735	int
736tty_setraw(on)
737{
738#  ifndef USE_TERMIO
739	if (on)
740		termbuf.sg.sg_flags |= RAW;
741	else
742		termbuf.sg.sg_flags &= ~RAW;
743#  else
744	if (on)
745		termbuf.c_lflag &= ~ICANON;
746	else
747		termbuf.c_lflag |= ICANON;
748#  endif
749}
750#endif
751
752	void
753tty_binaryin(on)
754	int on;
755{
756#ifndef	USE_TERMIO
757	if (on)
758		termbuf.lflags |= LPASS8;
759	else
760		termbuf.lflags &= ~LPASS8;
761#else
762	if (on) {
763		termbuf.c_iflag &= ~ISTRIP;
764	} else {
765		termbuf.c_iflag |= ISTRIP;
766	}
767#endif
768}
769
770	void
771tty_binaryout(on)
772	int on;
773{
774#ifndef	USE_TERMIO
775	if (on)
776		termbuf.lflags |= LLITOUT;
777	else
778		termbuf.lflags &= ~LLITOUT;
779#else
780	if (on) {
781		termbuf.c_cflag &= ~(CSIZE|PARENB);
782		termbuf.c_cflag |= CS8;
783		termbuf.c_oflag &= ~OPOST;
784	} else {
785		termbuf.c_cflag &= ~CSIZE;
786		termbuf.c_cflag |= CS7|PARENB;
787		termbuf.c_oflag |= OPOST;
788	}
789#endif
790}
791
792	int
793tty_isbinaryin()
794{
795#ifndef	USE_TERMIO
796	return(termbuf.lflags & LPASS8);
797#else
798	return(!(termbuf.c_iflag & ISTRIP));
799#endif
800}
801
802	int
803tty_isbinaryout()
804{
805#ifndef	USE_TERMIO
806	return(termbuf.lflags & LLITOUT);
807#else
808	return(!(termbuf.c_oflag&OPOST));
809#endif
810}
811
812#ifdef	LINEMODE
813	int
814tty_isediting()
815{
816#ifndef USE_TERMIO
817	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
818#else
819	return(termbuf.c_lflag & ICANON);
820#endif
821}
822
823	int
824tty_istrapsig()
825{
826#ifndef USE_TERMIO
827	return(!(termbuf.sg.sg_flags&RAW));
828#else
829	return(termbuf.c_lflag & ISIG);
830#endif
831}
832
833	void
834tty_setedit(on)
835	int on;
836{
837#ifndef USE_TERMIO
838	if (on)
839		termbuf.sg.sg_flags &= ~CBREAK;
840	else
841		termbuf.sg.sg_flags |= CBREAK;
842#else
843	if (on)
844		termbuf.c_lflag |= ICANON;
845	else
846		termbuf.c_lflag &= ~ICANON;
847#endif
848}
849
850	void
851tty_setsig(on)
852	int on;
853{
854#ifndef	USE_TERMIO
855	if (on)
856		;
857#else
858	if (on)
859		termbuf.c_lflag |= ISIG;
860	else
861		termbuf.c_lflag &= ~ISIG;
862#endif
863}
864#endif	/* LINEMODE */
865
866	int
867tty_issofttab()
868{
869#ifndef	USE_TERMIO
870	return (termbuf.sg.sg_flags & XTABS);
871#else
872# ifdef	OXTABS
873	return (termbuf.c_oflag & OXTABS);
874# endif
875# ifdef	TABDLY
876	return ((termbuf.c_oflag & TABDLY) == TAB3);
877# endif
878#endif
879}
880
881	void
882tty_setsofttab(on)
883	int on;
884{
885#ifndef	USE_TERMIO
886	if (on)
887		termbuf.sg.sg_flags |= XTABS;
888	else
889		termbuf.sg.sg_flags &= ~XTABS;
890#else
891	if (on) {
892# ifdef	OXTABS
893		termbuf.c_oflag |= OXTABS;
894# endif
895# ifdef	TABDLY
896		termbuf.c_oflag &= ~TABDLY;
897		termbuf.c_oflag |= TAB3;
898# endif
899	} else {
900# ifdef	OXTABS
901		termbuf.c_oflag &= ~OXTABS;
902# endif
903# ifdef	TABDLY
904		termbuf.c_oflag &= ~TABDLY;
905		termbuf.c_oflag |= TAB0;
906# endif
907	}
908#endif
909}
910
911	int
912tty_islitecho()
913{
914#ifndef	USE_TERMIO
915	return (!(termbuf.lflags & LCTLECH));
916#else
917# ifdef	ECHOCTL
918	return (!(termbuf.c_lflag & ECHOCTL));
919# endif
920# ifdef	TCTLECH
921	return (!(termbuf.c_lflag & TCTLECH));
922# endif
923# if	!defined(ECHOCTL) && !defined(TCTLECH)
924	return (0);	/* assumes ctl chars are echoed '^x' */
925# endif
926#endif
927}
928
929	void
930tty_setlitecho(on)
931	int on;
932{
933#ifndef	USE_TERMIO
934	if (on)
935		termbuf.lflags &= ~LCTLECH;
936	else
937		termbuf.lflags |= LCTLECH;
938#else
939# ifdef	ECHOCTL
940	if (on)
941		termbuf.c_lflag &= ~ECHOCTL;
942	else
943		termbuf.c_lflag |= ECHOCTL;
944# endif
945# ifdef	TCTLECH
946	if (on)
947		termbuf.c_lflag &= ~TCTLECH;
948	else
949		termbuf.c_lflag |= TCTLECH;
950# endif
951#endif
952}
953
954	int
955tty_iscrnl()
956{
957#ifndef	USE_TERMIO
958	return (termbuf.sg.sg_flags & CRMOD);
959#else
960	return (termbuf.c_iflag & ICRNL);
961#endif
962}
963
964/*
965 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
966 */
967#if B4800 != 4800
968#define	DECODE_BAUD
969#endif
970
971#ifdef	DECODE_BAUD
972
973/*
974 * A table of available terminal speeds
975 */
976struct termspeeds {
977	int	speed;
978	int	value;
979} termspeeds[] = {
980	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
981	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
982	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
983	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
984	{ 4800,   B4800 },
985#ifdef	B7200
986	{ 7200,  B7200 },
987#endif
988	{ 9600,   B9600 },
989#ifdef	B14400
990	{ 14400,  B14400 },
991#endif
992#ifdef	B19200
993	{ 19200,  B19200 },
994#endif
995#ifdef	B28800
996	{ 28800,  B28800 },
997#endif
998#ifdef	B38400
999	{ 38400,  B38400 },
1000#endif
1001#ifdef	B57600
1002	{ 57600,  B57600 },
1003#endif
1004#ifdef	B115200
1005	{ 115200, B115200 },
1006#endif
1007#ifdef	B230400
1008	{ 230400, B230400 },
1009#endif
1010	{ -1,     0 }
1011};
1012#endif	/* DECODE_BAUD */
1013
1014	void
1015tty_tspeed(val)
1016	int val;
1017{
1018#ifdef	DECODE_BAUD
1019	register struct termspeeds *tp;
1020
1021	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
1022		;
1023	if (tp->speed == -1)	/* back up to last valid value */
1024		--tp;
1025	cfsetospeed(&termbuf, tp->value);
1026#else	/* DECODE_BAUD */
1027	cfsetospeed(&termbuf, val);
1028#endif	/* DECODE_BAUD */
1029}
1030
1031	void
1032tty_rspeed(val)
1033	int val;
1034{
1035#ifdef	DECODE_BAUD
1036	register struct termspeeds *tp;
1037
1038	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
1039		;
1040	if (tp->speed == -1)	/* back up to last valid value */
1041		--tp;
1042	cfsetispeed(&termbuf, tp->value);
1043#else	/* DECODE_BAUD */
1044	cfsetispeed(&termbuf, val);
1045#endif	/* DECODE_BAUD */
1046}
1047
1048#if	defined(CRAY2) && defined(UNICOS5)
1049	int
1050tty_isnewmap()
1051{
1052	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
1053			!(termbuf.c_oflag & ONLRET));
1054}
1055#endif
1056
1057#ifdef PARENT_DOES_UTMP
1058# ifndef NEWINIT
1059extern	struct utmp wtmp;
1060extern char wtmpf[];
1061# else	/* NEWINIT */
1062int	gotalarm;
1063
1064	/* ARGSUSED */
1065	void
1066nologinproc(sig)
1067	int sig;
1068{
1069	gotalarm++;
1070}
1071# endif	/* NEWINIT */
1072#endif /* PARENT_DOES_UTMP */
1073
1074#ifndef	NEWINIT
1075# ifdef PARENT_DOES_UTMP
1076extern void utmp_sig_init P((void));
1077extern void utmp_sig_reset P((void));
1078extern void utmp_sig_wait P((void));
1079extern void utmp_sig_notify P((int));
1080# endif /* PARENT_DOES_UTMP */
1081#endif
1082
1083/*
1084 * getptyslave()
1085 *
1086 * Open the slave side of the pty, and do any initialization
1087 * that is necessary.
1088 */
1089	void
1090getptyslave()
1091{
1092	register int t = -1;
1093	char erase;
1094
1095#if	!defined(CRAY) || !defined(NEWINIT)
1096# ifdef	LINEMODE
1097	int waslm;
1098# endif
1099# ifdef	TIOCGWINSZ
1100	struct winsize ws;
1101	extern int def_row, def_col;
1102# endif
1103	extern int def_tspeed, def_rspeed;
1104	/*
1105	 * Opening the slave side may cause initilization of the
1106	 * kernel tty structure.  We need remember the state of
1107	 * 	if linemode was turned on
1108	 *	terminal window size
1109	 *	terminal speed
1110	 *	erase character
1111	 * so that we can re-set them if we need to.
1112	 */
1113# ifdef	LINEMODE
1114	waslm = tty_linemode();
1115# endif
1116	erase = termbuf.c_cc[VERASE];
1117
1118	/*
1119	 * Make sure that we don't have a controlling tty, and
1120	 * that we are the session (process group) leader.
1121	 */
1122# ifdef	TIOCNOTTY
1123	t = open(_PATH_TTY, O_RDWR);
1124	if (t >= 0) {
1125		(void) ioctl(t, TIOCNOTTY, (char *)0);
1126		(void) close(t);
1127	}
1128# endif
1129
1130
1131# ifdef PARENT_DOES_UTMP
1132	/*
1133	 * Wait for our parent to get the utmp stuff to get done.
1134	 */
1135	utmp_sig_wait();
1136# endif
1137
1138	t = cleanopen(line);
1139	if (t < 0)
1140		fatalperror(net, line);
1141
1142#ifdef  STREAMSPTY
1143#ifdef	USE_TERMIO
1144	ttyfd = t;
1145#endif
1146	if (ioctl(t, I_PUSH, "ptem") < 0)
1147		fatal(net, "I_PUSH ptem");
1148	if (ioctl(t, I_PUSH, "ldterm") < 0)
1149		fatal(net, "I_PUSH ldterm");
1150	if (ioctl(t, I_PUSH, "ttcompat") < 0)
1151		fatal(net, "I_PUSH ttcompat");
1152	if (ioctl(pty, I_PUSH, "pckt") < 0)
1153		fatal(net, "I_PUSH pckt");
1154#endif
1155
1156	/*
1157	 * set up the tty modes as we like them to be.
1158	 */
1159	init_termbuf();
1160# ifdef	TIOCGWINSZ
1161	if (def_row || def_col) {
1162		memset((char *)&ws, 0, sizeof(ws));
1163		ws.ws_col = def_col;
1164		ws.ws_row = def_row;
1165		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
1166	}
1167# endif
1168
1169	/*
1170	 * Settings for sgtty based systems
1171	 */
1172# ifndef	USE_TERMIO
1173	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
1174# endif	/* USE_TERMIO */
1175
1176	/*
1177	 * Settings for UNICOS (and HPUX)
1178	 */
1179# if defined(CRAY) || defined(__hpux)
1180	termbuf.c_oflag = OPOST|ONLCR|TAB3;
1181	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
1182	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1183	termbuf.c_cflag = EXTB|HUPCL|CS8;
1184# endif
1185
1186	/*
1187	 * Settings for all other termios/termio based
1188	 * systems, other than 4.4BSD.  In 4.4BSD the
1189	 * kernel does the initial terminal setup.
1190	 */
1191# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
1192#  ifndef	OXTABS
1193#   define OXTABS	0
1194#  endif
1195	termbuf.c_lflag |= ECHO;
1196	termbuf.c_oflag |= ONLCR|OXTABS;
1197	termbuf.c_iflag |= ICRNL;
1198	termbuf.c_iflag &= ~IXOFF;
1199# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
1200	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
1201	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
1202	if (erase)
1203		termbuf.c_cc[VERASE] = erase;
1204# ifdef	LINEMODE
1205	if (waslm)
1206		tty_setlinemode(1);
1207# endif	/* LINEMODE */
1208
1209	/*
1210	 * Set the tty modes, and make this our controlling tty.
1211	 */
1212	set_termbuf();
1213	if (login_tty(t) == -1)
1214		fatalperror(net, "login_tty");
1215#endif	/* !defined(CRAY) || !defined(NEWINIT) */
1216	if (net > 2)
1217		(void) close(net);
1218#if	defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1219	/*
1220	 * Leave the pty open so that we can write out the rlogin
1221	 * protocol for /bin/login, if the authentication works.
1222	 */
1223#else
1224	if (pty > 2) {
1225		(void) close(pty);
1226		pty = -1;
1227	}
1228#endif
1229}
1230
1231#if	!defined(CRAY) || !defined(NEWINIT)
1232#ifndef	O_NOCTTY
1233#define	O_NOCTTY	0
1234#endif
1235/*
1236 * Open the specified slave side of the pty,
1237 * making sure that we have a clean tty.
1238 */
1239	int
1240cleanopen(line)
1241	char *line;
1242{
1243	register int t;
1244#ifdef	UNICOS7x
1245	struct secstat secbuf;
1246#endif	/* UNICOS7x */
1247
1248#ifndef STREAMSPTY
1249	/*
1250	 * Make sure that other people can't open the
1251	 * slave side of the connection.
1252	 */
1253	(void) chown(line, 0, 0);
1254	(void) chmod(line, 0600);
1255#endif
1256
1257# if !defined(CRAY) && (BSD > 43)
1258	(void) revoke(line);
1259# endif
1260#ifdef	UNICOS7x
1261	if (secflag) {
1262		if (secstat(line, &secbuf) < 0)
1263			return(-1);
1264		if (setulvl(secbuf.st_slevel) < 0)
1265			return(-1);
1266		if (setucmp(secbuf.st_compart) < 0)
1267			return(-1);
1268	}
1269#endif	/* UNICOS7x */
1270
1271	t = open(line, O_RDWR|O_NOCTTY);
1272
1273#ifdef	UNICOS7x
1274	if (secflag) {
1275		if (setulvl(sysv.sy_minlvl) < 0)
1276			return(-1);
1277		if (setucmp(0) < 0)
1278			return(-1);
1279	}
1280#endif	/* UNICOS7x */
1281
1282	if (t < 0)
1283		return(-1);
1284
1285	/*
1286	 * Hangup anybody else using this ttyp, then reopen it for
1287	 * ourselves.
1288	 */
1289# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
1290	(void) signal(SIGHUP, SIG_IGN);
1291	vhangup();
1292	(void) signal(SIGHUP, SIG_DFL);
1293	t = open(line, O_RDWR|O_NOCTTY);
1294	if (t < 0)
1295		return(-1);
1296# endif
1297# if	defined(CRAY) && defined(TCVHUP)
1298	{
1299		register int i;
1300		(void) signal(SIGHUP, SIG_IGN);
1301		(void) ioctl(t, TCVHUP, (char *)0);
1302		(void) signal(SIGHUP, SIG_DFL);
1303
1304#ifdef	UNICOS7x
1305		if (secflag) {
1306			if (secstat(line, &secbuf) < 0)
1307				return(-1);
1308			if (setulvl(secbuf.st_slevel) < 0)
1309				return(-1);
1310			if (setucmp(secbuf.st_compart) < 0)
1311				return(-1);
1312		}
1313#endif	/* UNICOS7x */
1314
1315		i = open(line, O_RDWR);
1316
1317#ifdef	UNICOS7x
1318		if (secflag) {
1319			if (setulvl(sysv.sy_minlvl) < 0)
1320				return(-1);
1321			if (setucmp(0) < 0)
1322				return(-1);
1323		}
1324#endif	/* UNICOS7x */
1325
1326		if (i < 0)
1327			return(-1);
1328		(void) close(t);
1329		t = i;
1330	}
1331# endif	/* defined(CRAY) && defined(TCVHUP) */
1332	return(t);
1333}
1334#endif	/* !defined(CRAY) || !defined(NEWINIT) */
1335
1336#if BSD <= 43
1337
1338	int
1339login_tty(t)
1340	int t;
1341{
1342	if (setsid() < 0) {
1343#ifdef ultrix
1344		/*
1345		 * The setsid() may have failed because we
1346		 * already have a pgrp == pid.  Zero out
1347		 * our pgrp and try again...
1348		 */
1349		if ((setpgrp(0, 0) < 0) || (setsid() < 0))
1350#endif
1351			fatalperror(net, "setsid()");
1352	}
1353# ifdef	TIOCSCTTY
1354	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
1355		fatalperror(net, "ioctl(sctty)");
1356#  if defined(CRAY)
1357	/*
1358	 * Close the hard fd to /dev/ttypXXX, and re-open through
1359	 * the indirect /dev/tty interface.
1360	 */
1361	close(t);
1362	if ((t = open("/dev/tty", O_RDWR)) < 0)
1363		fatalperror(net, "open(/dev/tty)");
1364#  endif
1365# else
1366	/*
1367	 * We get our controlling tty assigned as a side-effect
1368	 * of opening up a tty device.  But on BSD based systems,
1369	 * this only happens if our process group is zero.  The
1370	 * setsid() call above may have set our pgrp, so clear
1371	 * it out before opening the tty...
1372	 */
1373#  ifndef SOLARIS
1374	(void) setpgrp(0, 0);
1375#  else
1376	(void) setpgrp();
1377#  endif
1378	close(open(line, O_RDWR));
1379# endif
1380	if (t != 0)
1381		(void) dup2(t, 0);
1382	if (t != 1)
1383		(void) dup2(t, 1);
1384	if (t != 2)
1385		(void) dup2(t, 2);
1386	if (t > 2)
1387		close(t);
1388	return(0);
1389}
1390#endif	/* BSD <= 43 */
1391
1392#ifdef	NEWINIT
1393char *gen_id = "fe";
1394#endif
1395
1396/*
1397 * startslave(host)
1398 *
1399 * Given a hostname, do whatever
1400 * is necessary to startup the login process on the slave side of the pty.
1401 */
1402
1403/* ARGSUSED */
1404	void
1405startslave(host, autologin, autoname)
1406	char *host;
1407	int autologin;
1408	char *autoname;
1409{
1410	register int i;
1411#ifdef	NEWINIT
1412	extern char *ptyip;
1413	struct init_request request;
1414	void nologinproc();
1415	register int n;
1416#endif	/* NEWINIT */
1417
1418#if	defined(AUTHENTICATION)
1419	if (!autoname || !autoname[0])
1420		autologin = 0;
1421
1422	if (autologin < auth_level) {
1423		fatal(net, "Authorization failed");
1424		exit(1);
1425	}
1426#endif
1427
1428#ifndef	NEWINIT
1429# ifdef	PARENT_DOES_UTMP
1430	utmp_sig_init();
1431# endif	/* PARENT_DOES_UTMP */
1432
1433	if ((i = fork()) < 0)
1434		fatalperror(net, "fork");
1435	if (i) {
1436# ifdef PARENT_DOES_UTMP
1437		/*
1438		 * Cray parent will create utmp entry for child and send
1439		 * signal to child to tell when done.  Child waits for signal
1440		 * before doing anything important.
1441		 */
1442		register int pid = i;
1443		void sigjob P((int));
1444
1445		setpgrp();
1446		utmp_sig_reset();		/* reset handler to default */
1447		/*
1448		 * Create utmp entry for child
1449		 */
1450		(void) time(&wtmp.ut_time);
1451		wtmp.ut_type = LOGIN_PROCESS;
1452		wtmp.ut_pid = pid;
1453		SCPYN(wtmp.ut_user, "LOGIN");
1454		SCPYN(wtmp.ut_host, host);
1455		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
1456#ifndef	__hpux
1457		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
1458#else
1459		SCPYN(wtmp.ut_id, wtmp.ut_line+7);
1460#endif
1461		pututline(&wtmp);
1462		endutent();
1463		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1464			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
1465			(void) close(i);
1466		}
1467#ifdef	CRAY
1468		(void) signal(WJSIGNAL, sigjob);
1469#endif
1470		utmp_sig_notify(pid);
1471# endif	/* PARENT_DOES_UTMP */
1472	} else {
1473		getptyslave(autologin);
1474		start_login(host, autologin, autoname);
1475		/*NOTREACHED*/
1476	}
1477#else	/* NEWINIT */
1478
1479	/*
1480	 * Init will start up login process if we ask nicely.  We only wait
1481	 * for it to start up and begin normal telnet operation.
1482	 */
1483	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
1484		char tbuf[128];
1485		(void) snprintf(tbuf, sizeof(tbuf), "Can't open %s\n", INIT_FIFO);
1486		fatalperror(net, tbuf);
1487	}
1488	memset((char *)&request, 0, sizeof(request));
1489	request.magic = INIT_MAGIC;
1490	SCPYN(request.gen_id, gen_id);
1491	SCPYN(request.tty_id, &line[8]);
1492	SCPYN(request.host, host);
1493	SCPYN(request.term_type, terminaltype ? terminaltype : "network");
1494#if	!defined(UNICOS5)
1495	request.signal = SIGCLD;
1496	request.pid = getpid();
1497#endif
1498#ifdef BFTPDAEMON
1499	/*
1500	 * Are we working as the bftp daemon?
1501	 */
1502	if (bftpd) {
1503		SCPYN(request.exec_name, BFTPPATH);
1504	}
1505#endif /* BFTPDAEMON */
1506	if (write(i, (char *)&request, sizeof(request)) < 0) {
1507		char tbuf[128];
1508		(void) snprintf(tbuf, sizeof(tbuf), "Can't write to %s\n", INIT_FIFO);
1509		fatalperror(net, tbuf);
1510	}
1511	(void) close(i);
1512	(void) signal(SIGALRM, nologinproc);
1513	for (i = 0; ; i++) {
1514		char tbuf[128];
1515		alarm(15);
1516		n = read(pty, ptyip, BUFSIZ);
1517		if (i == 3 || n >= 0 || !gotalarm)
1518			break;
1519		gotalarm = 0;
1520		snprintf(tbuf, sizeof(tbuf), "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
1521		(void) write(net, tbuf, strlen(tbuf));
1522	}
1523	if (n < 0 && gotalarm)
1524		fatal(net, "/etc/init didn't start login process");
1525	pcc += n;
1526	alarm(0);
1527	(void) signal(SIGALRM, SIG_DFL);
1528
1529	return;
1530#endif	/* NEWINIT */
1531}
1532
1533char	*envinit[3];
1534extern char **environ;
1535
1536	void
1537init_env()
1538{
1539	extern char *getenv();
1540	char **envp;
1541
1542	envp = envinit;
1543	if ((*envp = getenv("TZ")))
1544		*envp++ -= 3;
1545#if	defined(CRAY) || defined(__hpux)
1546	else
1547		*envp++ = "TZ=GMT0";
1548#endif
1549	*envp = 0;
1550	environ = envinit;
1551}
1552
1553#ifndef	NEWINIT
1554
1555/*
1556 * start_login(host)
1557 *
1558 * Assuming that we are now running as a child processes, this
1559 * function will turn us into the login process.
1560 */
1561
1562	void
1563start_login(host, autologin, name)
1564	char *host;
1565	int autologin;
1566	char *name;
1567{
1568	register char **argv;
1569	char **addarg(), *user;
1570	extern char *getenv();
1571#ifdef	UTMPX
1572	register int pid = getpid();
1573	struct utmpx utmpx;
1574#endif
1575#ifdef SOLARIS
1576	char *term;
1577	char termbuf[64];
1578#endif
1579
1580#ifdef	UTMPX
1581	/*
1582	 * Create utmp entry for child
1583	 */
1584
1585	memset(&utmpx, 0, sizeof(utmpx));
1586	SCPYN(utmpx.ut_user, ".telnet");
1587	SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
1588	utmpx.ut_pid = pid;
1589	utmpx.ut_id[0] = 't';
1590	utmpx.ut_id[1] = 'n';
1591	utmpx.ut_id[2] = SC_WILDC;
1592	utmpx.ut_id[3] = SC_WILDC;
1593	utmpx.ut_type = LOGIN_PROCESS;
1594	(void) time(&utmpx.ut_tv.tv_sec);
1595	if (makeutx(&utmpx) == NULL)
1596		fatal(net, "makeutx failed");
1597#endif
1598
1599	scrub_env();
1600
1601	/*
1602	 * -h : pass on name of host.
1603	 *		WARNING:  -h is accepted by login if and only if
1604	 *			getuid() == 0.
1605	 * -p : don't clobber the environment (so terminal type stays set).
1606	 *
1607	 * -f : force this login, he has already been authenticated
1608	 */
1609	argv = addarg(0, "login");
1610
1611#if	!defined(NO_LOGIN_H)
1612
1613# if	defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1614	/*
1615	 * Don't add the "-h host" option if we are going
1616	 * to be adding the "-r host" option down below...
1617	 */
1618	if ((auth_level < 0) || (autologin != AUTH_VALID))
1619# endif
1620	{
1621		argv = addarg(argv, "-h");
1622		argv = addarg(argv, host);
1623#ifdef	SOLARIS
1624		/*
1625		 * SVR4 version of -h takes TERM= as second arg, or -
1626		 */
1627		term = getenv("TERM");
1628		if (term == NULL || term[0] == 0) {
1629			term = "-";
1630		} else {
1631			strcpy(termbuf, "TERM=");
1632			strncat(termbuf, term, sizeof(termbuf) - 6);
1633			term = termbuf;
1634		}
1635		argv = addarg(argv, term);
1636#endif
1637	}
1638#endif
1639#if	!defined(NO_LOGIN_P)
1640	argv = addarg(argv, "-p");
1641#endif
1642#ifdef	LINEMODE
1643	/*
1644	 * Set the environment variable "LINEMODE" to either
1645	 * "real" or "kludge" if we are operating in either
1646	 * real or kludge linemode.
1647	 */
1648	if (lmodetype == REAL_LINEMODE)
1649		setenv("LINEMODE", "real", 1);
1650# ifdef KLUDGELINEMODE
1651	else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
1652		setenv("LINEMODE", "kludge", 1);
1653# endif
1654#endif
1655#ifdef	BFTPDAEMON
1656	/*
1657	 * Are we working as the bftp daemon?  If so, then ask login
1658	 * to start bftp instead of shell.
1659	 */
1660	if (bftpd) {
1661		argv = addarg(argv, "-e");
1662		argv = addarg(argv, BFTPPATH);
1663	} else
1664#endif
1665#if	defined (SecurID)
1666	/*
1667	 * don't worry about the -f that might get sent.
1668	 * A -s is supposed to override it anyhow.
1669	 */
1670	if (require_SecurID)
1671		argv = addarg(argv, "-s");
1672#endif
1673#if	defined (AUTHENTICATION)
1674	if (auth_level >= 0 && autologin == AUTH_VALID) {
1675# if	!defined(NO_LOGIN_F)
1676		argv = addarg(argv, "-f");
1677		argv = addarg(argv, "--");
1678		argv = addarg(argv, name);
1679# else
1680#  if defined(LOGIN_R)
1681		/*
1682		 * We don't have support for "login -f", but we
1683		 * can fool /bin/login into thinking that we are
1684		 * rlogind, and allow us to log in without a
1685		 * password.  The rlogin protocol expects
1686		 *	local-user\0remote-user\0term/speed\0
1687		 */
1688
1689		if (pty > 2) {
1690			register char *cp;
1691			char speed[128];
1692			int isecho, israw, xpty, len;
1693			extern int def_rspeed;
1694#  ifndef LOGIN_HOST
1695			/*
1696			 * Tell login that we are coming from "localhost".
1697			 * If we passed in the real host name, then the
1698			 * user would have to allow .rhost access from
1699			 * every machine that they want authenticated
1700			 * access to work from, which sort of defeats
1701			 * the purpose of an authenticated login...
1702			 * So, we tell login that the session is coming
1703			 * from "localhost", and the user will only have
1704			 * to have "localhost" in their .rhost file.
1705			 */
1706#			define LOGIN_HOST "localhost"
1707#  endif
1708			argv = addarg(argv, "-r");
1709			argv = addarg(argv, LOGIN_HOST);
1710
1711			xpty = pty;
1712# ifndef  STREAMSPTY
1713			pty = 0;
1714# else
1715			ttyfd = 0;
1716# endif
1717			init_termbuf();
1718			isecho = tty_isecho();
1719			israw = tty_israw();
1720			if (isecho || !israw) {
1721				tty_setecho(0);		/* Turn off echo */
1722				tty_setraw(1);		/* Turn on raw */
1723				set_termbuf();
1724			}
1725			len = strlen(name)+1;
1726			write(xpty, name, len);
1727			write(xpty, name, len);
1728			snprintf(speed, sizeof(speed),
1729				"%s/%d", (cp = getenv("TERM")) ? cp : "",
1730				(def_rspeed > 0) ? def_rspeed : 9600);
1731			len = strlen(speed)+1;
1732			write(xpty, speed, len);
1733
1734			if (isecho || !israw) {
1735				init_termbuf();
1736				tty_setecho(isecho);
1737				tty_setraw(israw);
1738				set_termbuf();
1739				if (!israw) {
1740					/*
1741					 * Write a newline to ensure
1742					 * that login will be able to
1743					 * read the line...
1744					 */
1745					write(xpty, "\n", 1);
1746				}
1747			}
1748			pty = xpty;
1749		}
1750#  else
1751		argv = addarg(argv, "--");
1752		argv = addarg(argv, name);
1753#  endif
1754# endif
1755	} else
1756#endif
1757	if (getenv("USER")) {
1758 		argv = addarg(argv, "--");
1759		argv = addarg(argv, getenv("USER"));
1760#if	defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
1761		{
1762			register char **cpp;
1763			for (cpp = environ; *cpp; cpp++)
1764				argv = addarg(argv, *cpp);
1765		}
1766#endif
1767		/*
1768		 * Assume that login will set the USER variable
1769		 * correctly.  For SysV systems, this means that
1770		 * USER will no longer be set, just LOGNAME by
1771		 * login.  (The problem is that if the auto-login
1772		 * fails, and the user then specifies a different
1773		 * account name, he can get logged in with both
1774		 * LOGNAME and USER in his environment, but the
1775		 * USER value will be wrong.
1776		 */
1777		unsetenv("USER");
1778	}
1779#ifdef	SOLARIS
1780	else {
1781		char **p;
1782
1783		argv = addarg(argv, "");	/* no login name */
1784		for (p = environ; *p; p++) {
1785			argv = addarg(argv, *p);
1786		}
1787	}
1788#endif	/* SOLARIS */
1789#if	defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
1790	if (pty > 2)
1791		close(pty);
1792#endif
1793	closelog();
1794
1795	if (altlogin == NULL) {
1796		altlogin = _PATH_LOGIN;
1797	}
1798	execv(altlogin, argv);
1799
1800	syslog(LOG_ERR, "%s: %m", altlogin);
1801	fatalperror(net, altlogin);
1802	/*NOTREACHED*/
1803}
1804
1805	char **
1806addarg(argv, val)
1807	register char **argv;
1808	register char *val;
1809{
1810	register char **cpp;
1811
1812	if (argv == NULL) {
1813		/*
1814		 * 10 entries, a leading length, and a null
1815		 */
1816		argv = (char **)malloc(sizeof(*argv) * 12);
1817		if (argv == NULL)
1818			return(NULL);
1819		*argv++ = (char *)10;
1820		*argv = (char *)0;
1821	}
1822	for (cpp = argv; *cpp; cpp++)
1823		;
1824	if (cpp == &argv[(int)argv[-1]]) {
1825		--argv;
1826		*argv = (char *)((int)(*argv) + 10);
1827		argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2));
1828		if (argv == NULL)
1829			return(NULL);
1830		argv++;
1831		cpp = &argv[(int)argv[-1] - 10];
1832	}
1833	*cpp++ = val;
1834	*cpp = 0;
1835	return(argv);
1836}
1837#endif	/* NEWINIT */
1838
1839/*
1840 * scrub_env()
1841 *
1842 * Remove a few things from the environment that
1843 * don't need to be there.
1844 */
1845	void
1846scrub_env()
1847{
1848	register char **cpp, **cpp2;
1849
1850	for (cpp2 = cpp = environ; *cpp; cpp++) {
1851#ifdef __FreeBSD__
1852		if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) &&
1853		    strncmp(*cpp, "LD_PRELOAD=", 11) &&
1854#else
1855		if (strncmp(*cpp, "LD_", 3) &&
1856		    strncmp(*cpp, "_RLD_", 5) &&
1857		    strncmp(*cpp, "LIBPATH=", 8) &&
1858#endif
1859		    strncmp(*cpp, "IFS=", 4))
1860			*cpp2++ = *cpp;
1861	}
1862	*cpp2 = 0;
1863}
1864
1865/*
1866 * cleanup()
1867 *
1868 * This is the routine to call when we are all through, to
1869 * clean up anything that needs to be cleaned up.
1870 */
1871	/* ARGSUSED */
1872	void
1873cleanup(sig)
1874	int sig;
1875{
1876#ifndef	PARENT_DOES_UTMP
1877# if (BSD > 43) || defined(convex)
1878	char *p;
1879
1880	p = line + sizeof("/dev/") - 1;
1881	if (logout(p))
1882		logwtmp(p, "", "");
1883	(void)chmod(line, 0666);
1884	(void)chown(line, 0, 0);
1885	*p = 'p';
1886	(void)chmod(line, 0666);
1887	(void)chown(line, 0, 0);
1888	(void) shutdown(net, 2);
1889	exit(1);
1890# else
1891	void rmut();
1892
1893	rmut();
1894	vhangup();	/* XXX */
1895	(void) shutdown(net, 2);
1896	exit(1);
1897# endif
1898#else	/* PARENT_DOES_UTMP */
1899# ifdef	NEWINIT
1900	(void) shutdown(net, 2);
1901	exit(1);
1902# else	/* NEWINIT */
1903#  ifdef CRAY
1904	static int incleanup = 0;
1905	register int t;
1906	int child_status; /* status of child process as returned by waitpid */
1907	int flags = WNOHANG|WUNTRACED;
1908
1909	/*
1910	 * 1: Pick up the zombie, if we are being called
1911	 *    as the signal handler.
1912	 * 2: If we are a nested cleanup(), return.
1913	 * 3: Try to clean up TMPDIR.
1914	 * 4: Fill in utmp with shutdown of process.
1915	 * 5: Close down the network and pty connections.
1916	 * 6: Finish up the TMPDIR cleanup, if needed.
1917	 */
1918	if (sig == SIGCHLD) {
1919		while (waitpid(-1, &child_status, flags) > 0)
1920			;	/* VOID */
1921		/* Check if the child process was stopped
1922		 * rather than exited.  We want cleanup only if
1923		 * the child has died.
1924		 */
1925		if (WIFSTOPPED(child_status)) {
1926			return;
1927		}
1928	}
1929	t = sigblock(sigmask(SIGCHLD));
1930	if (incleanup) {
1931		sigsetmask(t);
1932		return;
1933	}
1934	incleanup = 1;
1935	sigsetmask(t);
1936#ifdef	UNICOS7x
1937	if (secflag) {
1938		/*
1939		 *	We need to set ourselves back to a null
1940		 *	label to clean up.
1941		 */
1942
1943		setulvl(sysv.sy_minlvl);
1944		setucmp((long)0);
1945	}
1946#endif	/* UNICOS7x */
1947
1948	t = cleantmp(&wtmp);
1949	setutent();	/* just to make sure */
1950#  endif /* CRAY */
1951	rmut(line);
1952	close(pty);
1953	(void) shutdown(net, 2);
1954#  ifdef CRAY
1955	if (t == 0)
1956		cleantmp(&wtmp);
1957#  endif /* CRAY */
1958	exit(1);
1959# endif	/* NEWINT */
1960#endif	/* PARENT_DOES_UTMP */
1961}
1962
1963#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
1964/*
1965 * _utmp_sig_rcv
1966 * utmp_sig_init
1967 * utmp_sig_wait
1968 *	These three functions are used to coordinate the handling of
1969 *	the utmp file between the server and the soon-to-be-login shell.
1970 *	The server actually creates the utmp structure, the child calls
1971 *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
1972 *	signals the future-login shell to proceed.
1973 */
1974static int caught=0;		/* NZ when signal intercepted */
1975static void (*func)();		/* address of previous handler */
1976
1977	void
1978_utmp_sig_rcv(sig)
1979	int sig;
1980{
1981	caught = 1;
1982	(void) signal(SIGUSR1, func);
1983}
1984
1985	void
1986utmp_sig_init()
1987{
1988	/*
1989	 * register signal handler for UTMP creation
1990	 */
1991	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1992		fatalperror(net, "telnetd/signal");
1993}
1994
1995	void
1996utmp_sig_reset()
1997{
1998	(void) signal(SIGUSR1, func);	/* reset handler to default */
1999}
2000
2001# ifdef __hpux
2002# define sigoff() /* do nothing */
2003# define sigon() /* do nothing */
2004# endif
2005
2006	void
2007utmp_sig_wait()
2008{
2009	/*
2010	 * Wait for parent to write our utmp entry.
2011	 */
2012	sigoff();
2013	while (caught == 0) {
2014		pause();	/* wait until we get a signal (sigon) */
2015		sigoff();	/* turn off signals while we check caught */
2016	}
2017	sigon();		/* turn on signals again */
2018}
2019
2020	void
2021utmp_sig_notify(pid)
2022{
2023	kill(pid, SIGUSR1);
2024}
2025
2026# ifdef CRAY
2027static int gotsigjob = 0;
2028
2029	/*ARGSUSED*/
2030	void
2031sigjob(sig)
2032	int sig;
2033{
2034	register int jid;
2035	register struct jobtemp *jp;
2036
2037	while ((jid = waitjob(NULL)) != -1) {
2038		if (jid == 0) {
2039			return;
2040		}
2041		gotsigjob++;
2042		jobend(jid, NULL, NULL);
2043	}
2044}
2045
2046/*
2047 *	jid_getutid:
2048 *		called by jobend() before calling cleantmp()
2049 *		to find the correct $TMPDIR to cleanup.
2050 */
2051
2052	struct utmp *
2053jid_getutid(jid)
2054	int jid;
2055{
2056	struct utmp *cur = NULL;
2057
2058	setutent();	/* just to make sure */
2059	while (cur = getutent()) {
2060		if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
2061			return(cur);
2062		}
2063	}
2064
2065	return(0);
2066}
2067
2068/*
2069 * Clean up the TMPDIR that login created.
2070 * The first time this is called we pick up the info
2071 * from the utmp.  If the job has already gone away,
2072 * then we'll clean up and be done.  If not, then
2073 * when this is called the second time it will wait
2074 * for the signal that the job is done.
2075 */
2076	int
2077cleantmp(wtp)
2078	register struct utmp *wtp;
2079{
2080	struct utmp *utp;
2081	static int first = 1;
2082	register int mask, omask, ret;
2083	extern struct utmp *getutid P((const struct utmp *_Id));
2084
2085
2086	mask = sigmask(WJSIGNAL);
2087
2088	if (first == 0) {
2089		omask = sigblock(mask);
2090		while (gotsigjob == 0)
2091			sigpause(omask);
2092		return(1);
2093	}
2094	first = 0;
2095	setutent();	/* just to make sure */
2096
2097	utp = getutid(wtp);
2098	if (utp == 0) {
2099		syslog(LOG_ERR, "can't get /etc/utmp entry to clean TMPDIR");
2100		return(-1);
2101	}
2102	/*
2103	 * Nothing to clean up if the user shell was never started.
2104	 */
2105	if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
2106		return(1);
2107
2108	/*
2109	 * Block the WJSIGNAL while we are in jobend().
2110	 */
2111	omask = sigblock(mask);
2112	ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
2113	sigsetmask(omask);
2114	return(ret);
2115}
2116
2117	int
2118jobend(jid, path, user)
2119	register int jid;
2120	register char *path;
2121	register char *user;
2122{
2123	static int saved_jid = 0;
2124	static int pty_saved_jid = 0;
2125	static char saved_path[sizeof(wtmp.ut_tpath)+1];
2126	static char saved_user[sizeof(wtmp.ut_user)+1];
2127
2128	/*
2129	 * this little piece of code comes into play
2130	 * only when ptyreconnect is used to reconnect
2131	 * to an previous session.
2132	 *
2133	 * this is the only time when the
2134	 * "saved_jid != jid" code is executed.
2135	 */
2136
2137	if ( saved_jid && saved_jid != jid ) {
2138		if (!path) {	/* called from signal handler */
2139			pty_saved_jid = jid;
2140		} else {
2141			pty_saved_jid = saved_jid;
2142		}
2143	}
2144
2145	if (path) {
2146		strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
2147		strncpy(saved_user, user, sizeof(wtmp.ut_user));
2148		saved_path[sizeof(saved_path)] = '\0';
2149		saved_user[sizeof(saved_user)] = '\0';
2150	}
2151	if (saved_jid == 0) {
2152		saved_jid = jid;
2153		return(0);
2154	}
2155
2156	/* if the jid has changed, get the correct entry from the utmp file */
2157
2158	if ( saved_jid != jid ) {
2159		struct utmp *utp = NULL;
2160		struct utmp *jid_getutid();
2161
2162		utp = jid_getutid(pty_saved_jid);
2163
2164		if (utp == 0) {
2165			syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
2166			return(-1);
2167		}
2168
2169		cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
2170		return(1);
2171	}
2172
2173	cleantmpdir(jid, saved_path, saved_user);
2174	return(1);
2175}
2176
2177/*
2178 * Fork a child process to clean up the TMPDIR
2179 */
2180cleantmpdir(jid, tpath, user)
2181	register int jid;
2182	register char *tpath;
2183	register char *user;
2184{
2185	switch(fork()) {
2186	case -1:
2187		syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m",
2188							tpath);
2189		break;
2190	case 0:
2191		execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
2192		syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m",
2193							tpath, CLEANTMPCMD);
2194		exit(1);
2195	default:
2196		/*
2197		 * Forget about child.  We will exit, and
2198		 * /etc/init will pick it up.
2199		 */
2200		break;
2201	}
2202}
2203# endif /* CRAY */
2204#endif	/* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
2205
2206/*
2207 * rmut()
2208 *
2209 * This is the function called by cleanup() to
2210 * remove the utmp entry for this person.
2211 */
2212
2213#ifdef	UTMPX
2214	void
2215rmut()
2216{
2217	register f;
2218	int found = 0;
2219	struct utmp *u, *utmp;
2220	int nutmp;
2221	struct stat statbf;
2222
2223	struct utmpx *utxp, utmpx;
2224
2225	/*
2226	 * This updates the utmpx and utmp entries and make a wtmp/x entry
2227	 */
2228
2229	SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
2230	utxp = getutxline(&utmpx);
2231	if (utxp) {
2232		utxp->ut_type = DEAD_PROCESS;
2233		utxp->ut_exit.e_termination = 0;
2234		utxp->ut_exit.e_exit = 0;
2235		(void) time(&utmpx.ut_tv.tv_sec);
2236		utmpx.ut_tv.tv_usec = 0;
2237		modutx(utxp);
2238	}
2239	endutxent();
2240}  /* end of rmut */
2241#endif
2242
2243#if	!defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
2244	void
2245rmut()
2246{
2247	register f;
2248	int found = 0;
2249	struct utmp *u, *utmp;
2250	int nutmp;
2251	struct stat statbf;
2252
2253	f = open(utmpf, O_RDWR);
2254	if (f >= 0) {
2255		(void) fstat(f, &statbf);
2256		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
2257		if (!utmp)
2258			syslog(LOG_ERR, "utmp malloc failed");
2259		if (statbf.st_size && utmp) {
2260			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
2261			nutmp /= sizeof(struct utmp);
2262
2263			for (u = utmp ; u < &utmp[nutmp] ; u++) {
2264				if (SCMPN(u->ut_line, line+5) ||
2265				    u->ut_name[0]==0)
2266					continue;
2267				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
2268				SCPYN(u->ut_name, "");
2269				SCPYN(u->ut_host, "");
2270				(void) time(&u->ut_time);
2271				(void) write(f, (char *)u, sizeof(wtmp));
2272				found++;
2273			}
2274		}
2275		(void) close(f);
2276	}
2277	if (found) {
2278		f = open(wtmpf, O_WRONLY|O_APPEND);
2279		if (f >= 0) {
2280			SCPYN(wtmp.ut_line, line+5);
2281			SCPYN(wtmp.ut_name, "");
2282			SCPYN(wtmp.ut_host, "");
2283			(void) time(&wtmp.ut_time);
2284			(void) write(f, (char *)&wtmp, sizeof(wtmp));
2285			(void) close(f);
2286		}
2287	}
2288	(void) chmod(line, 0666);
2289	(void) chown(line, 0, 0);
2290	line[strlen("/dev/")] = 'p';
2291	(void) chmod(line, 0666);
2292	(void) chown(line, 0, 0);
2293}  /* end of rmut */
2294#endif	/* CRAY */
2295
2296#ifdef __hpux
2297rmut (line)
2298char *line;
2299{
2300	struct utmp utmp;
2301	struct utmp *utptr;
2302	int fd;			/* for /etc/wtmp */
2303
2304	utmp.ut_type = USER_PROCESS;
2305	(void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id));
2306	(void) setutent();
2307	utptr = getutid(&utmp);
2308	/* write it out only if it exists */
2309	if (utptr) {
2310		utptr->ut_type = DEAD_PROCESS;
2311		utptr->ut_time = time((long *) 0);
2312		(void) pututline(utptr);
2313		/* set wtmp entry if wtmp file exists */
2314		if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
2315			(void) write(fd, utptr, sizeof(utmp));
2316			(void) close(fd);
2317		}
2318	}
2319	(void) endutent();
2320
2321	(void) chmod(line, 0666);
2322	(void) chown(line, 0, 0);
2323	line[14] = line[13];
2324	line[13] = line[12];
2325	line[8] = 'm';
2326	line[9] = '/';
2327	line[10] = 'p';
2328	line[11] = 't';
2329	line[12] = 'y';
2330	(void) chmod(line, 0666);
2331	(void) chown(line, 0, 0);
2332}
2333#endif
2334