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