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