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#include "telnetd.h"
35
36RCSID("$Id$");
37
38#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
39# define PARENT_DOES_UTMP
40#endif
41
42#ifdef HAVE_UTMP_H
43#include <utmp.h>
44#endif
45
46#ifdef HAVE_UTMPX_H
47#include <utmpx.h>
48#endif
49
50#ifdef HAVE_UTMPX_H
51struct	utmpx wtmp;
52#elif defined(HAVE_UTMP_H)
53struct	utmp wtmp;
54#endif /* HAVE_UTMPX_H */
55
56#ifdef HAVE_STRUCT_UTMP_UT_HOST
57int	utmp_len = sizeof(wtmp.ut_host);
58#else
59int	utmp_len = MaxHostNameLen;
60#endif
61
62#ifndef UTMP_FILE
63#ifdef _PATH_UTMP
64#define UTMP_FILE _PATH_UTMP
65#else
66#define UTMP_FILE "/etc/utmp"
67#endif
68#endif
69
70/* really, mac os uses wtmpx (or asl) */
71#ifdef __APPLE__
72#undef _PATH_WTMP
73#endif
74
75#if !defined(WTMP_FILE) && defined(_PATH_WTMP)
76#define WTMP_FILE _PATH_WTMP
77#endif
78
79#ifndef PARENT_DOES_UTMP
80#ifdef WTMP_FILE
81char	wtmpf[] = WTMP_FILE;
82#else
83char	wtmpf[]	= "/usr/adm/wtmp";
84#endif
85char	utmpf[] = UTMP_FILE;
86#else /* PARENT_DOES_UTMP */
87#ifdef WTMP_FILE
88char	wtmpf[] = WTMP_FILE;
89#else
90char	wtmpf[]	= "/etc/wtmp";
91#endif
92#endif /* PARENT_DOES_UTMP */
93
94#ifdef HAVE_TMPDIR_H
95#include <tmpdir.h>
96#endif	/* CRAY */
97
98#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
99#include <sys/tty.h>
100#endif
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#ifdef HAVE_TERMIOS_H
119#include <termios.h>
120#else
121#ifdef HAVE_TERMIO_H
122#include <termio.h>
123#endif
124#endif
125
126#ifdef HAVE_UTIL_H
127#include <util.h>
128#endif
129#ifdef HAVE_LIBUTIL_H
130#include <libutil.h>
131#endif
132
133# ifndef	TCSANOW
134#  ifdef TCSETS
135#   define	TCSANOW		TCSETS
136#   define	TCSADRAIN	TCSETSW
137#   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
138#  else
139#   ifdef TCSETA
140#    define	TCSANOW		TCSETA
141#    define	TCSADRAIN	TCSETAW
142#    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
143#   else
144#    define	TCSANOW		TIOCSETA
145#    define	TCSADRAIN	TIOCSETAW
146#    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
147#   endif
148#  endif
149#  define	tcsetattr(f, a, t)	ioctl(f, a, t)
150#  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
151(tp)->c_cflag |= (val)
152#  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
153#  ifdef CIBAUD
154#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
155     (tp)->c_cflag |= ((val)<<IBSHIFT)
156#   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
157#  else
158#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
159     (tp)->c_cflag |= (val)
160#   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
161#  endif
162# endif /* TCSANOW */
163     struct termios termbuf, termbuf2;	/* pty control structure */
164# ifdef  STREAMSPTY
165     static int ttyfd = -1;
166     int really_stream = 0;
167# else
168#define really_stream 0
169# endif
170
171     const char *new_login = _PATH_LOGIN;
172
173/*
174 * init_termbuf()
175 * copy_termbuf(cp)
176 * set_termbuf()
177 *
178 * These three routines are used to get and set the "termbuf" structure
179 * to and from the kernel.  init_termbuf() gets the current settings.
180 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
181 * set_termbuf() writes the structure into the kernel.
182 */
183
184     void
185     init_termbuf(void)
186{
187# ifdef  STREAMSPTY
188    if (really_stream)
189	tcgetattr(ttyfd, &termbuf);
190    else
191# endif
192	tcgetattr(ourpty, &termbuf);
193    termbuf2 = termbuf;
194}
195
196void
197set_termbuf(void)
198{
199    /*
200     * Only make the necessary changes.
201	 */
202    if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
203# ifdef  STREAMSPTY
204	if (really_stream)
205	    tcsetattr(ttyfd, TCSANOW, &termbuf);
206	else
207# endif
208	    tcsetattr(ourpty, TCSANOW, &termbuf);
209    }
210}
211
212
213/*
214 * spcset(func, valp, valpp)
215 *
216 * This function takes various special characters (func), and
217 * sets *valp to the current value of that character, and
218 * *valpp to point to where in the "termbuf" structure that
219 * value is kept.
220 *
221 * It returns the SLC_ level of support for this function.
222 */
223
224
225int
226spcset(int func, cc_t *valp, cc_t **valpp)
227{
228
229#define	setval(a, b)	*valp = termbuf.c_cc[a]; \
230    *valpp = &termbuf.c_cc[a]; \
231				   return(b);
232#define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
233
234    switch(func) {
235    case SLC_EOF:
236	setval(VEOF, SLC_VARIABLE);
237    case SLC_EC:
238	setval(VERASE, SLC_VARIABLE);
239    case SLC_EL:
240	setval(VKILL, SLC_VARIABLE);
241    case SLC_IP:
242	setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
243    case SLC_ABORT:
244	setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
245    case SLC_XON:
246#ifdef	VSTART
247	setval(VSTART, SLC_VARIABLE);
248#else
249	defval(0x13);
250#endif
251    case SLC_XOFF:
252#ifdef	VSTOP
253	setval(VSTOP, SLC_VARIABLE);
254#else
255	defval(0x11);
256#endif
257    case SLC_EW:
258#ifdef	VWERASE
259	setval(VWERASE, SLC_VARIABLE);
260#else
261	defval(0);
262#endif
263    case SLC_RP:
264#ifdef	VREPRINT
265	setval(VREPRINT, SLC_VARIABLE);
266#else
267	defval(0);
268#endif
269    case SLC_LNEXT:
270#ifdef	VLNEXT
271	setval(VLNEXT, SLC_VARIABLE);
272#else
273	defval(0);
274#endif
275    case SLC_AO:
276#if	!defined(VDISCARD) && defined(VFLUSHO)
277# define VDISCARD VFLUSHO
278#endif
279#ifdef	VDISCARD
280	setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
281#else
282	defval(0);
283#endif
284    case SLC_SUSP:
285#ifdef	VSUSP
286	setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
287#else
288	defval(0);
289#endif
290#ifdef	VEOL
291    case SLC_FORW1:
292	setval(VEOL, SLC_VARIABLE);
293#endif
294#ifdef	VEOL2
295    case SLC_FORW2:
296	setval(VEOL2, SLC_VARIABLE);
297#endif
298    case SLC_AYT:
299#ifdef	VSTATUS
300	setval(VSTATUS, SLC_VARIABLE);
301#else
302	defval(0);
303#endif
304
305    case SLC_BRK:
306    case SLC_SYNCH:
307    case SLC_EOR:
308	defval(0);
309
310    default:
311	*valp = 0;
312	*valpp = 0;
313	return(SLC_NOSUPPORT);
314    }
315}
316
317#ifdef _CRAY
318/*
319 * getnpty()
320 *
321 * Return the number of pty's configured into the system.
322 */
323int
324getnpty()
325{
326#ifdef _SC_CRAY_NPTY
327    int numptys;
328
329    if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
330	return numptys;
331    else
332#endif /* _SC_CRAY_NPTY */
333	return 128;
334}
335#endif /* CRAY */
336
337/*
338 * getpty()
339 *
340 * Allocate a pty.  As a side effect, the external character
341 * array "line" contains the name of the slave side.
342 *
343 * Returns the file descriptor of the opened pty.
344 */
345
346static int ptyslavefd = -1;
347
348static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
349char *line = Xline;
350
351#ifdef	_CRAY
352char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
353#endif	/* CRAY */
354
355#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
356static char *ptsname(int fd)
357{
358#ifdef HAVE_TTYNAME
359    return ttyname(fd);
360#else
361    return NULL;
362#endif
363}
364#endif
365
366int getpty(int *ptynum)
367{
368#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
369    {
370	int master;
371	int slave;
372	if(openpty(&master, &slave, line, 0, 0) == 0){
373	    ptyslavefd = slave;
374	    return master;
375	}
376    }
377#endif /* HAVE_OPENPTY .... */
378#ifdef HAVE__GETPTY
379    {
380	int master;
381	char *p;
382	p = _getpty(&master, O_RDWR, 0600, 1);
383	if(p == NULL)
384	    return -1;
385	strlcpy(line, p, sizeof(Xline));
386	return master;
387    }
388#endif
389
390#ifdef	STREAMSPTY
391    {
392	char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
393			  "/dev/ptym/clone", 0 };
394
395	char **q;
396	int p;
397	for(q=clone; *q; q++){
398	    p=open(*q, O_RDWR);
399	    if(p >= 0){
400#ifdef HAVE_GRANTPT
401		grantpt(p);
402#endif
403#ifdef HAVE_UNLOCKPT
404		unlockpt(p);
405#endif
406		strlcpy(line, ptsname(p), sizeof(Xline));
407		really_stream = 1;
408		return p;
409	    }
410	}
411    }
412#endif /* STREAMSPTY */
413#ifndef _CRAY
414    {
415	int p;
416	char *cp, *p1, *p2;
417	int i;
418
419#ifndef	__hpux
420	snprintf(line, sizeof(Xline), "/dev/ptyXX");
421	p1 = &line[8];
422	p2 = &line[9];
423#else
424	snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
425	p1 = &line[13];
426	p2 = &line[14];
427#endif
428
429
430	for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
431	    struct stat stb;
432
433	    *p1 = *cp;
434	    *p2 = '0';
435	    /*
436	     * This stat() check is just to keep us from
437	     * looping through all 256 combinations if there
438	     * aren't that many ptys available.
439	     */
440	    if (stat(line, &stb) < 0)
441		break;
442	    for (i = 0; i < 16; i++) {
443		*p2 = "0123456789abcdef"[i];
444		p = open(line, O_RDWR);
445		if (p > 0) {
446#if SunOS == 40
447		    int dummy;
448#endif
449
450#ifndef	__hpux
451		    line[5] = 't';
452#else
453		    for (p1 = &line[8]; *p1; p1++)
454			*p1 = *(p1+1);
455		    line[9] = 't';
456#endif
457		    chown(line, 0, 0);
458		    chmod(line, 0600);
459#if SunOS == 40
460		    if (ioctl(p, TIOCGPGRP, &dummy) == 0
461			|| errno != EIO) {
462			chmod(line, 0666);
463			close(p);
464			line[5] = 'p';
465		    } else
466#endif /* SunOS == 40 */
467			return(p);
468		}
469	    }
470	}
471    }
472#else	/* CRAY */
473    {
474	extern lowpty, highpty;
475	struct stat sb;
476	int p;
477
478	for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
479	    snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
480	    p = open(myline, 2);
481	    if (p < 0)
482		continue;
483	    snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
484	    /*
485	     * Here are some shenanigans to make sure that there
486	     * are no listeners lurking on the line.
487	     */
488	    if(stat(line, &sb) < 0) {
489		close(p);
490		continue;
491	    }
492	    if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
493		chown(line, 0, 0);
494		chmod(line, 0600);
495		close(p);
496		p = open(myline, 2);
497		if (p < 0)
498		    continue;
499	    }
500	    /*
501	     * Now it should be safe...check for accessability.
502	     */
503	    if (access(line, 6) == 0)
504		return(p);
505	    else {
506		/* no tty side to pty so skip it */
507		close(p);
508	    }
509	}
510    }
511#endif	/* CRAY */
512    return(-1);
513}
514
515
516int
517tty_isecho(void)
518{
519    return (termbuf.c_lflag & ECHO);
520}
521
522int
523tty_flowmode(void)
524{
525    return((termbuf.c_iflag & IXON) ? 1 : 0);
526}
527
528int
529tty_restartany(void)
530{
531    return((termbuf.c_iflag & IXANY) ? 1 : 0);
532}
533
534void
535tty_setecho(int on)
536{
537    if (on)
538	termbuf.c_lflag |= ECHO;
539    else
540	termbuf.c_lflag &= ~ECHO;
541}
542
543int
544tty_israw(void)
545{
546    return(!(termbuf.c_lflag & ICANON));
547}
548
549void
550tty_binaryin(int on)
551{
552    if (on) {
553	termbuf.c_iflag &= ~ISTRIP;
554    } else {
555	termbuf.c_iflag |= ISTRIP;
556    }
557}
558
559void
560tty_binaryout(int on)
561{
562    if (on) {
563	termbuf.c_cflag &= ~(CSIZE|PARENB);
564	termbuf.c_cflag |= CS8;
565	termbuf.c_oflag &= ~OPOST;
566    } else {
567	termbuf.c_cflag &= ~CSIZE;
568	termbuf.c_cflag |= CS7|PARENB;
569	termbuf.c_oflag |= OPOST;
570    }
571}
572
573int
574tty_isbinaryin(void)
575{
576    return(!(termbuf.c_iflag & ISTRIP));
577}
578
579int
580tty_isbinaryout(void)
581{
582    return(!(termbuf.c_oflag&OPOST));
583}
584
585
586int
587tty_issofttab(void)
588{
589# ifdef	OXTABS
590    return (termbuf.c_oflag & OXTABS);
591# endif
592# ifdef	TABDLY
593    return ((termbuf.c_oflag & TABDLY) == TAB3);
594# endif
595}
596
597void
598tty_setsofttab(int on)
599{
600    if (on) {
601# ifdef	OXTABS
602	termbuf.c_oflag |= OXTABS;
603# endif
604# ifdef	TABDLY
605	termbuf.c_oflag &= ~TABDLY;
606	termbuf.c_oflag |= TAB3;
607# endif
608    } else {
609# ifdef	OXTABS
610	termbuf.c_oflag &= ~OXTABS;
611# endif
612# ifdef	TABDLY
613	termbuf.c_oflag &= ~TABDLY;
614	termbuf.c_oflag |= TAB0;
615# endif
616    }
617}
618
619int
620tty_islitecho(void)
621{
622# ifdef	ECHOCTL
623    return (!(termbuf.c_lflag & ECHOCTL));
624# endif
625# ifdef	TCTLECH
626    return (!(termbuf.c_lflag & TCTLECH));
627# endif
628# if	!defined(ECHOCTL) && !defined(TCTLECH)
629    return (0);	/* assumes ctl chars are echoed '^x' */
630# endif
631}
632
633void
634tty_setlitecho(int on)
635{
636# ifdef	ECHOCTL
637    if (on)
638	termbuf.c_lflag &= ~ECHOCTL;
639    else
640	termbuf.c_lflag |= ECHOCTL;
641# endif
642# ifdef	TCTLECH
643    if (on)
644	termbuf.c_lflag &= ~TCTLECH;
645    else
646	termbuf.c_lflag |= TCTLECH;
647# endif
648}
649
650int
651tty_iscrnl(void)
652{
653    return (termbuf.c_iflag & ICRNL);
654}
655
656/*
657 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
658 */
659#if B4800 != 4800
660#define	DECODE_BAUD
661#endif
662
663#ifdef	DECODE_BAUD
664
665/*
666 * A table of available terminal speeds
667 */
668struct termspeeds {
669    int	speed;
670    int	value;
671} termspeeds[] = {
672    { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
673    { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
674    { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
675    { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
676    { 4800,   B4800 },
677#ifdef	B7200
678    { 7200,  B7200 },
679#endif
680    { 9600,   B9600 },
681#ifdef	B14400
682    { 14400,  B14400 },
683#endif
684#ifdef	B19200
685    { 19200,  B19200 },
686#endif
687#ifdef	B28800
688    { 28800,  B28800 },
689#endif
690#ifdef	B38400
691    { 38400,  B38400 },
692#endif
693#ifdef	B57600
694    { 57600,  B57600 },
695#endif
696#ifdef	B115200
697    { 115200, B115200 },
698#endif
699#ifdef	B230400
700    { 230400, B230400 },
701#endif
702    { -1,     0 }
703};
704#endif	/* DECODE_BUAD */
705
706void
707tty_tspeed(int val)
708{
709#ifdef	DECODE_BAUD
710    struct termspeeds *tp;
711
712    for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
713	;
714    if (tp->speed == -1)	/* back up to last valid value */
715	--tp;
716    cfsetospeed(&termbuf, tp->value);
717#else	/* DECODE_BUAD */
718    cfsetospeed(&termbuf, val);
719#endif	/* DECODE_BUAD */
720}
721
722void
723tty_rspeed(int val)
724{
725#ifdef	DECODE_BAUD
726    struct termspeeds *tp;
727
728    for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
729	;
730    if (tp->speed == -1)	/* back up to last valid value */
731	--tp;
732    cfsetispeed(&termbuf, tp->value);
733#else	/* DECODE_BAUD */
734    cfsetispeed(&termbuf, val);
735#endif	/* DECODE_BAUD */
736}
737
738#ifdef PARENT_DOES_UTMP
739extern	struct utmp wtmp;
740extern char wtmpf[];
741
742extern void utmp_sig_init (void);
743extern void utmp_sig_reset (void);
744extern void utmp_sig_wait (void);
745extern void utmp_sig_notify (int);
746# endif /* PARENT_DOES_UTMP */
747
748#ifdef STREAMSPTY
749
750/* I_FIND seems to live a life of its own */
751static int my_find(int fd, char *module)
752{
753#if defined(I_FIND) && defined(I_LIST)
754    static int flag;
755    static struct str_list sl;
756    int n;
757    int i;
758
759    if(!flag){
760	n = ioctl(fd, I_LIST, 0);
761	if(n < 0){
762	    perror("ioctl(fd, I_LIST, 0)");
763	    return -1;
764	}
765	sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
766	sl.sl_nmods = n;
767	n = ioctl(fd, I_LIST, &sl);
768	if(n < 0){
769	    perror("ioctl(fd, I_LIST, n)");
770	    return -1;
771	}
772	flag = 1;
773    }
774
775    for(i=0; i<sl.sl_nmods; i++)
776	if(!strcmp(sl.sl_modlist[i].l_name, module))
777	    return 1;
778#endif
779    return 0;
780}
781
782static void maybe_push_modules(int fd, char **modules)
783{
784    char **p;
785    int err;
786
787    for(p=modules; *p; p++){
788	err = my_find(fd, *p);
789	if(err == 1)
790	    break;
791	if(err < 0 && errno != EINVAL)
792	    fatalperror(net, "my_find()");
793	/* module not pushed or does not exist */
794    }
795    /* p points to null or to an already pushed module, now push all
796       modules before this one */
797
798    for(p--; p >= modules; p--){
799	err = ioctl(fd, I_PUSH, *p);
800	if(err < 0 && errno != EINVAL)
801	    fatalperror(net, "I_PUSH");
802    }
803}
804#endif
805
806/*
807 * getptyslave()
808 *
809 * Open the slave side of the pty, and do any initialization
810 * that is necessary.  The return value is a file descriptor
811 * for the slave side.
812 */
813void getptyslave(void)
814{
815    int t = -1;
816
817    struct winsize ws;
818    /*
819     * Opening the slave side may cause initilization of the
820     * kernel tty structure.  We need remember the state of
821     * 	if linemode was turned on
822     *	terminal window size
823     *	terminal speed
824     * so that we can re-set them if we need to.
825     */
826
827
828    /*
829     * Make sure that we don't have a controlling tty, and
830     * that we are the session (process group) leader.
831     */
832
833#ifdef HAVE_SETSID
834    if(setsid()<0)
835	fatalperror(net, "setsid()");
836#else
837# ifdef	TIOCNOTTY
838    t = open(_PATH_TTY, O_RDWR);
839    if (t >= 0) {
840	ioctl(t, TIOCNOTTY, (char *)0);
841	close(t);
842    }
843# endif
844#endif
845
846# ifdef PARENT_DOES_UTMP
847    /*
848     * Wait for our parent to get the utmp stuff to get done.
849     */
850    utmp_sig_wait();
851# endif
852
853    t = cleanopen(line);
854    if (t < 0)
855	fatalperror(net, line);
856
857#ifdef  STREAMSPTY
858    ttyfd = t;
859
860
861    /*
862     * Not all systems have (or need) modules ttcompat and pckt so
863     * don't flag it as a fatal error if they don't exist.
864     */
865
866    if (really_stream)
867	{
868	    /* these are the streams modules that we want pushed. note
869	       that they are in reverse order, ptem will be pushed
870	       first. maybe_push_modules() will try to push all modules
871	       before the first one that isn't already pushed. i.e if
872	       ldterm is pushed, only ttcompat will be attempted.
873
874	       all this is because we don't know which modules are
875	       available, and we don't know which modules are already
876	       pushed (via autopush, for instance).
877
878	       */
879
880	    char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
881	    char *ptymodules[] = { "pckt", NULL };
882
883	    maybe_push_modules(t, ttymodules);
884	    maybe_push_modules(ourpty, ptymodules);
885	}
886#endif
887    /*
888     * set up the tty modes as we like them to be.
889     */
890    init_termbuf();
891# ifdef	TIOCSWINSZ
892    if (def_row || def_col) {
893	memset(&ws, 0, sizeof(ws));
894	ws.ws_col = def_col;
895	ws.ws_row = def_row;
896	ioctl(t, TIOCSWINSZ, (char *)&ws);
897    }
898# endif
899
900    /*
901     * Settings for sgtty based systems
902     */
903
904    /*
905     * Settings for UNICOS (and HPUX)
906     */
907# if defined(_CRAY) || defined(__hpux)
908    termbuf.c_oflag = OPOST|ONLCR|TAB3;
909    termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
910    termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
911    termbuf.c_cflag = EXTB|HUPCL|CS8;
912# endif
913
914    /*
915     * Settings for all other termios/termio based
916     * systems, other than 4.4BSD.  In 4.4BSD the
917     * kernel does the initial terminal setup.
918     */
919# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
920#  ifndef	OXTABS
921#   define OXTABS	0
922#  endif
923    termbuf.c_lflag |= ECHO;
924    termbuf.c_oflag |= ONLCR|OXTABS;
925    termbuf.c_iflag |= ICRNL;
926    termbuf.c_iflag &= ~IXOFF;
927# endif
928    tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
929    tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
930
931    /*
932     * Set the tty modes, and make this our controlling tty.
933     */
934    set_termbuf();
935    if (login_tty(t) == -1)
936	fatalperror(net, "login_tty");
937    if (net > 2)
938	close(net);
939    if (ourpty > 2) {
940	close(ourpty);
941	ourpty = -1;
942    }
943}
944
945#ifndef	O_NOCTTY
946#define	O_NOCTTY	0
947#endif
948/*
949 * Open the specified slave side of the pty,
950 * making sure that we have a clean tty.
951 */
952
953int cleanopen(char *line)
954{
955    int t;
956
957    if (ptyslavefd != -1)
958	return ptyslavefd;
959
960#ifdef STREAMSPTY
961    if (!really_stream)
962#endif
963	{
964	    /*
965	     * Make sure that other people can't open the
966	     * slave side of the connection.
967	     */
968	    chown(line, 0, 0);
969	    chmod(line, 0600);
970	}
971
972#ifdef HAVE_REVOKE
973    revoke(line);
974#endif
975
976    t = open(line, O_RDWR|O_NOCTTY);
977
978    if (t < 0)
979	return(-1);
980
981    /*
982     * Hangup anybody else using this ttyp, then reopen it for
983     * ourselves.
984     */
985# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
986    signal(SIGHUP, SIG_IGN);
987#ifdef HAVE_VHANGUP
988    vhangup();
989#else
990#endif
991    signal(SIGHUP, SIG_DFL);
992    t = open(line, O_RDWR|O_NOCTTY);
993    if (t < 0)
994	return(-1);
995# endif
996# if	defined(_CRAY) && defined(TCVHUP)
997    {
998	int i;
999	signal(SIGHUP, SIG_IGN);
1000	ioctl(t, TCVHUP, (char *)0);
1001	signal(SIGHUP, SIG_DFL);
1002
1003	i = open(line, O_RDWR);
1004
1005	if (i < 0)
1006	    return(-1);
1007	close(t);
1008	t = i;
1009    }
1010# endif	/* defined(CRAY) && defined(TCVHUP) */
1011    return(t);
1012}
1013
1014#if !defined(BSD4_4)
1015
1016int login_tty(int t)
1017{
1018    /* Dont need to set this as the controlling PTY on steams sockets,
1019     * don't abort on failure. */
1020# if defined(TIOCSCTTY) && !defined(__hpux)
1021    if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)
1022	fatalperror(net, "ioctl(sctty)");
1023#  ifdef _CRAY
1024    /*
1025     * Close the hard fd to /dev/ttypXXX, and re-open through
1026     * the indirect /dev/tty interface.
1027     */
1028    close(t);
1029    if ((t = open("/dev/tty", O_RDWR)) < 0)
1030	fatalperror(net, "open(/dev/tty)");
1031#  endif
1032# else
1033    /*
1034     * We get our controlling tty assigned as a side-effect
1035     * of opening up a tty device.  But on BSD based systems,
1036     * this only happens if our process group is zero.  The
1037     * setsid() call above may have set our pgrp, so clear
1038     * it out before opening the tty...
1039     */
1040#ifdef HAVE_SETPGID
1041    setpgid(0, 0);
1042#else
1043    setpgrp(0, 0); /* if setpgid isn't available, setpgrp
1044		      probably takes arguments */
1045#endif
1046    close(open(line, O_RDWR));
1047# endif
1048    if (t != 0)
1049	dup2(t, 0);
1050    if (t != 1)
1051	dup2(t, 1);
1052    if (t != 2)
1053	dup2(t, 2);
1054    if (t > 2)
1055	close(t);
1056    return(0);
1057}
1058#endif	/* BSD <= 43 */
1059
1060/*
1061 * This comes from ../../bsd/tty.c and should not really be here.
1062 */
1063
1064/*
1065 * Clean the tty name.  Return a pointer to the cleaned version.
1066 */
1067
1068static char * clean_ttyname (char *) __attribute__((unused));
1069
1070static char *
1071clean_ttyname (char *tty)
1072{
1073  char *res = tty;
1074
1075  if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1076    res += strlen(_PATH_DEV);
1077  if (strncmp (res, "pty/", 4) == 0)
1078    res += 4;
1079  if (strncmp (res, "ptym/", 5) == 0)
1080    res += 5;
1081  return res;
1082}
1083
1084/*
1085 * Generate a name usable as an `ut_id', typically without `tty'.
1086 */
1087
1088#ifdef HAVE_STRUCT_UTMP_UT_ID
1089static char *
1090make_id (char *tty)
1091{
1092  char *res = tty;
1093
1094  if (strncmp (res, "pts/", 4) == 0)
1095    res += 4;
1096  if (strncmp (res, "tty", 3) == 0)
1097    res += 3;
1098  return res;
1099}
1100#endif
1101
1102/*
1103 * startslave(host)
1104 *
1105 * Given a hostname, do whatever
1106 * is necessary to startup the login process on the slave side of the pty.
1107 */
1108
1109/* ARGSUSED */
1110void
1111startslave(const char *host, const char *utmp_host,
1112	   int autologin, char *autoname)
1113{
1114    int i;
1115
1116#ifdef AUTHENTICATION
1117    if (!autoname || !autoname[0])
1118	autologin = 0;
1119
1120    if (autologin < auth_level) {
1121	fatal(net, "Authorization failed");
1122	exit(1);
1123    }
1124#endif
1125
1126    {
1127	char *tbuf =
1128	    "\r\n*** Connection not encrypted! "
1129	    "Communication may be eavesdropped. ***\r\n";
1130#ifdef ENCRYPTION
1131	if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
1132#endif
1133	    writenet(tbuf, strlen(tbuf));
1134    }
1135# ifdef	PARENT_DOES_UTMP
1136    utmp_sig_init();
1137# endif	/* PARENT_DOES_UTMP */
1138
1139    if ((i = fork()) < 0)
1140	fatalperror(net, "fork");
1141    if (i) {
1142# ifdef PARENT_DOES_UTMP
1143	/*
1144	 * Cray parent will create utmp entry for child and send
1145	 * signal to child to tell when done.  Child waits for signal
1146	 * before doing anything important.
1147	 */
1148	int pid = i;
1149	void sigjob (int);
1150
1151	setpgrp();
1152	utmp_sig_reset();		/* reset handler to default */
1153	/*
1154	 * Create utmp entry for child
1155	 */
1156	wtmp.ut_time = time(NULL);
1157	wtmp.ut_type = LOGIN_PROCESS;
1158	wtmp.ut_pid = pid;
1159	strncpy(wtmp.ut_user,  "LOGIN", sizeof(wtmp.ut_user));
1160	strncpy(wtmp.ut_host,  utmp_host, sizeof(wtmp.ut_host));
1161	strncpy(wtmp.ut_line,  clean_ttyname(line), sizeof(wtmp.ut_line));
1162#ifdef HAVE_STRUCT_UTMP_UT_ID
1163	strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
1164#endif
1165
1166	pututline(&wtmp);
1167	endutent();
1168	if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
1169	    write(i, &wtmp, sizeof(struct utmp));
1170	    close(i);
1171	}
1172#ifdef	_CRAY
1173	signal(WJSIGNAL, sigjob);
1174#endif
1175	utmp_sig_notify(pid);
1176# endif	/* PARENT_DOES_UTMP */
1177    } else {
1178	getptyslave();
1179#if defined(DCE)
1180	/* if we authenticated via K5, try and join the PAG */
1181	kerberos5_dfspag();
1182#endif
1183	start_login(host, autologin, autoname);
1184	/*NOTREACHED*/
1185    }
1186}
1187
1188char	*envinit[3];
1189#if !HAVE_DECL_ENVIRON
1190extern char **environ;
1191#endif
1192
1193void
1194init_env(void)
1195{
1196    char **envp;
1197
1198    envp = envinit;
1199    if ((*envp = getenv("TZ")))
1200	*envp++ -= 3;
1201#if defined(_CRAY) || defined(__hpux)
1202    else
1203	*envp++ = "TZ=GMT0";
1204#endif
1205    *envp = 0;
1206    environ = envinit;
1207}
1208
1209/*
1210 * scrub_env()
1211 *
1212 * We only accept the environment variables listed below.
1213 */
1214
1215static void
1216scrub_env(void)
1217{
1218    static const char *reject[] = {
1219	"TERMCAP=/",
1220	NULL
1221    };
1222
1223    static const char *accept[] = {
1224	"XAUTH=", "XAUTHORITY=", "DISPLAY=",
1225	"TERM=",
1226	"EDITOR=",
1227	"PAGER=",
1228	"PRINTER=",
1229	"LOGNAME=",
1230	"POSIXLY_CORRECT=",
1231	"TERMCAP=",
1232	NULL
1233    };
1234
1235    char **cpp, **cpp2;
1236    const char **p;
1237
1238    for (cpp2 = cpp = environ; *cpp; cpp++) {
1239	int reject_it = 0;
1240
1241	for(p = reject; *p; p++)
1242	    if(strncmp(*cpp, *p, strlen(*p)) == 0) {
1243		reject_it = 1;
1244		break;
1245	    }
1246	if (reject_it)
1247	    continue;
1248
1249	for(p = accept; *p; p++)
1250	    if(strncmp(*cpp, *p, strlen(*p)) == 0)
1251		break;
1252	if(*p != NULL)
1253	    *cpp2++ = *cpp;
1254    }
1255    *cpp2 = NULL;
1256}
1257
1258
1259struct arg_val {
1260    int size;
1261    int argc;
1262    char **argv;
1263};
1264
1265static void addarg(struct arg_val*, const char*);
1266
1267/*
1268 * start_login(host)
1269 *
1270 * Assuming that we are now running as a child processes, this
1271 * function will turn us into the login process.
1272 */
1273
1274void
1275start_login(const char *host, int autologin, char *name)
1276{
1277    struct arg_val argv;
1278    char *user;
1279    int save_errno;
1280
1281#ifdef ENCRYPTION
1282    encrypt_output = NULL;
1283    decrypt_input = NULL;
1284#endif
1285
1286#ifdef HAVE_UTMPX_H
1287    {
1288	int pid = getpid();
1289	struct utmpx utmpx;
1290	struct timeval tv;
1291	char *clean_tty;
1292
1293	/*
1294	 * Create utmp entry for child
1295	 */
1296
1297	clean_tty = clean_ttyname(line);
1298	memset(&utmpx, 0, sizeof(utmpx));
1299	strncpy(utmpx.ut_user,  ".telnet", sizeof(utmpx.ut_user));
1300	strncpy(utmpx.ut_line,  clean_tty, sizeof(utmpx.ut_line));
1301#ifdef HAVE_STRUCT_UTMP_UT_ID
1302	strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1303#endif
1304	utmpx.ut_pid = pid;
1305
1306	utmpx.ut_type = LOGIN_PROCESS;
1307
1308	gettimeofday (&tv, NULL);
1309	utmpx.ut_tv.tv_sec = tv.tv_sec;
1310	utmpx.ut_tv.tv_usec = tv.tv_usec;
1311
1312	if (pututxline(&utmpx) == NULL)
1313	    fatal(net, "pututxline failed");
1314    }
1315#endif
1316
1317    scrub_env();
1318
1319    /*
1320     * -h : pass on name of host.
1321     *		WARNING:  -h is accepted by login if and only if
1322     *			getuid() == 0.
1323     * -p : don't clobber the environment (so terminal type stays set).
1324     *
1325     * -f : force this login, he has already been authenticated
1326     */
1327
1328    /* init argv structure */
1329    argv.size=0;
1330    argv.argc=0;
1331    argv.argv=malloc(0); /*so we can call realloc later */
1332    addarg(&argv, "login");
1333    addarg(&argv, "-h");
1334    addarg(&argv, host);
1335    addarg(&argv, "-p");
1336    if(name && name[0])
1337	user = name;
1338    else
1339	user = getenv("USER");
1340#ifdef AUTHENTICATION
1341    if (auth_level < 0 || autologin != AUTH_VALID) {
1342	if(!no_warn) {
1343	    printf("User not authenticated. ");
1344	    if (require_otp)
1345		printf("Using one-time password\r\n");
1346	    else
1347		printf("Using plaintext username and password\r\n");
1348	}
1349	if (require_otp) {
1350	    addarg(&argv, "-a");
1351	    addarg(&argv, "otp");
1352	}
1353	if(log_unauth)
1354	    syslog(LOG_INFO, "unauthenticated access from %s (%s)",
1355		   host, user ? user : "unknown user");
1356    }
1357    if (auth_level >= 0 && autologin == AUTH_VALID)
1358	addarg(&argv, "-f");
1359#endif
1360    if(user){
1361	addarg(&argv, "--");
1362	addarg(&argv, strdup(user));
1363    }
1364    if (getenv("USER")) {
1365	/*
1366	 * Assume that login will set the USER variable
1367	 * correctly.  For SysV systems, this means that
1368	 * USER will no longer be set, just LOGNAME by
1369	 * login.  (The problem is that if the auto-login
1370	 * fails, and the user then specifies a different
1371	 * account name, he can get logged in with both
1372	 * LOGNAME and USER in his environment, but the
1373	 * USER value will be wrong.
1374	 */
1375	unsetenv("USER");
1376    }
1377    closelog();
1378    /*
1379     * This sleep(1) is in here so that telnetd can
1380     * finish up with the tty.  There's a race condition
1381     * the login banner message gets lost...
1382     */
1383    sleep(1);
1384
1385    execv(new_login, argv.argv);
1386    save_errno = errno;
1387    syslog(LOG_ERR, "%s: %m", new_login);
1388    fatalperror_errno(net, new_login, save_errno);
1389    /*NOTREACHED*/
1390}
1391
1392static void
1393addarg(struct arg_val *argv, const char *val)
1394{
1395    if(argv->size <= argv->argc+1) {
1396	argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
1397	if (argv->argv == NULL)
1398	    fatal (net, "realloc: out of memory");
1399	argv->size+=10;
1400    }
1401    if((argv->argv[argv->argc++] = strdup(val)) == NULL)
1402	fatal (net, "strdup: out of memory");
1403    argv->argv[argv->argc]   = NULL;
1404}
1405
1406
1407/*
1408 * rmut()
1409 *
1410 * This is the function called by cleanup() to
1411 * remove the utmp entry for this person.
1412 */
1413
1414#ifdef HAVE_UTMPX_H
1415static void
1416rmut(void)
1417{
1418    struct utmpx utmpx, *non_save_utxp;
1419    char *clean_tty = clean_ttyname(line);
1420
1421    /*
1422     * This updates the utmpx and utmp entries and make a wtmp/x entry
1423     */
1424
1425    setutxent();
1426    memset(&utmpx, 0, sizeof(utmpx));
1427    strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
1428    utmpx.ut_type = LOGIN_PROCESS;
1429    non_save_utxp = getutxline(&utmpx);
1430    if (non_save_utxp) {
1431	struct utmpx *utxp;
1432	struct timeval tv;
1433	char user0;
1434
1435	utxp = malloc(sizeof(struct utmpx));
1436	*utxp = *non_save_utxp;
1437	user0 = utxp->ut_user[0];
1438	utxp->ut_user[0] = '\0';
1439	utxp->ut_type = DEAD_PROCESS;
1440#ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1441#ifdef _STRUCT___EXIT_STATUS
1442	utxp->ut_exit.__e_termination = 0;
1443	utxp->ut_exit.__e_exit = 0;
1444#elif defined(__osf__) /* XXX */
1445	utxp->ut_exit.ut_termination = 0;
1446	utxp->ut_exit.ut_exit = 0;
1447#else
1448	utxp->ut_exit.e_termination = 0;
1449	utxp->ut_exit.e_exit = 0;
1450#endif
1451#endif
1452	gettimeofday (&tv, NULL);
1453	utxp->ut_tv.tv_sec = tv.tv_sec;
1454	utxp->ut_tv.tv_usec = tv.tv_usec;
1455
1456	pututxline(utxp);
1457#ifdef WTMPX_FILE
1458	utxp->ut_user[0] = user0;
1459	updwtmpx(WTMPX_FILE, utxp);
1460#elif defined(WTMP_FILE)
1461	/* This is a strange system with a utmpx and a wtmp! */
1462	{
1463	  int f = open(wtmpf, O_WRONLY|O_APPEND);
1464	  struct utmp wtmp;
1465	  if (f >= 0) {
1466	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
1467	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
1468#ifdef HAVE_STRUCT_UTMP_UT_HOST
1469	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
1470#endif
1471	    wtmp.ut_time = time(NULL);
1472	    write(f, &wtmp, sizeof(wtmp));
1473	    close(f);
1474	  }
1475	}
1476#endif
1477	free (utxp);
1478    }
1479    endutxent();
1480}  /* end of rmut */
1481#endif
1482
1483#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
1484static void
1485rmut(void)
1486{
1487    int f;
1488    int found = 0;
1489    struct utmp *u, *utmp;
1490    int nutmp;
1491    struct stat statbf;
1492    char *clean_tty = clean_ttyname(line);
1493
1494    f = open(utmpf, O_RDWR);
1495    if (f >= 0) {
1496	fstat(f, &statbf);
1497	utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
1498	if (!utmp)
1499	    syslog(LOG_ERR, "utmp malloc failed");
1500	if (statbf.st_size && utmp) {
1501	    nutmp = read(f, utmp, (int)statbf.st_size);
1502	    nutmp /= sizeof(struct utmp);
1503
1504	    for (u = utmp ; u < &utmp[nutmp] ; u++) {
1505		if (strncmp(u->ut_line,
1506			    clean_tty,
1507			    sizeof(u->ut_line)) ||
1508		    u->ut_name[0]==0)
1509		    continue;
1510		lseek(f, ((long)u)-((long)utmp), L_SET);
1511		strncpy(u->ut_name,  "", sizeof(u->ut_name));
1512#ifdef HAVE_STRUCT_UTMP_UT_HOST
1513		strncpy(u->ut_host,  "", sizeof(u->ut_host));
1514#endif
1515		u->ut_time = time(NULL);
1516		write(f, u, sizeof(wtmp));
1517		found++;
1518	    }
1519	}
1520	close(f);
1521    }
1522    if (found) {
1523	f = open(wtmpf, O_WRONLY|O_APPEND);
1524	if (f >= 0) {
1525	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
1526	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
1527#ifdef HAVE_STRUCT_UTMP_UT_HOST
1528	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
1529#endif
1530	    wtmp.ut_time = time(NULL);
1531	    write(f, &wtmp, sizeof(wtmp));
1532	    close(f);
1533	}
1534    }
1535    chmod(line, 0666);
1536    chown(line, 0, 0);
1537    line[strlen("/dev/")] = 'p';
1538    chmod(line, 0666);
1539    chown(line, 0, 0);
1540}  /* end of rmut */
1541#endif	/* CRAY */
1542
1543#if defined(__hpux) && !defined(HAVE_UTMPX_H)
1544static void
1545rmut (char *line)
1546{
1547    struct utmp utmp;
1548    struct utmp *utptr;
1549    int fd;			/* for /etc/wtmp */
1550
1551    utmp.ut_type = USER_PROCESS;
1552    strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
1553    setutent();
1554    utptr = getutline(&utmp);
1555    /* write it out only if it exists */
1556    if (utptr) {
1557	utptr->ut_type = DEAD_PROCESS;
1558	utptr->ut_time = time(NULL);
1559	pututline(utptr);
1560	/* set wtmp entry if wtmp file exists */
1561	if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
1562	    write(fd, utptr, sizeof(utmp));
1563	    close(fd);
1564	}
1565    }
1566    endutent();
1567
1568    chmod(line, 0666);
1569    chown(line, 0, 0);
1570    line[14] = line[13];
1571    line[13] = line[12];
1572    line[8] = 'm';
1573    line[9] = '/';
1574    line[10] = 'p';
1575    line[11] = 't';
1576    line[12] = 'y';
1577    chmod(line, 0666);
1578    chown(line, 0, 0);
1579}
1580#endif
1581
1582/*
1583 * cleanup()
1584 *
1585 * This is the routine to call when we are all through, to
1586 * clean up anything that needs to be cleaned up.
1587 */
1588
1589#ifdef PARENT_DOES_UTMP
1590
1591void
1592cleanup(int sig)
1593{
1594#ifdef _CRAY
1595    static int incleanup = 0;
1596    int t;
1597    int child_status; /* status of child process as returned by waitpid */
1598    int flags = WNOHANG|WUNTRACED;
1599
1600    /*
1601     * 1: Pick up the zombie, if we are being called
1602     *    as the signal handler.
1603     * 2: If we are a nested cleanup(), return.
1604     * 3: Try to clean up TMPDIR.
1605     * 4: Fill in utmp with shutdown of process.
1606     * 5: Close down the network and pty connections.
1607     * 6: Finish up the TMPDIR cleanup, if needed.
1608     */
1609    if (sig == SIGCHLD) {
1610	while (waitpid(-1, &child_status, flags) > 0)
1611	    ;	/* VOID */
1612	/* Check if the child process was stopped
1613	 * rather than exited.  We want cleanup only if
1614	 * the child has died.
1615	 */
1616	if (WIFSTOPPED(child_status)) {
1617	    return;
1618	}
1619    }
1620    t = sigblock(sigmask(SIGCHLD));
1621    if (incleanup) {
1622	sigsetmask(t);
1623	return;
1624    }
1625    incleanup = 1;
1626    sigsetmask(t);
1627
1628    t = cleantmp(&wtmp);
1629    setutent();	/* just to make sure */
1630#endif /* CRAY */
1631    rmut(line);
1632    close(ourpty);
1633    shutdown(net, 2);
1634#ifdef _CRAY
1635    if (t == 0)
1636	cleantmp(&wtmp);
1637#endif /* CRAY */
1638    exit(1);
1639}
1640
1641#else /* PARENT_DOES_UTMP */
1642
1643void
1644cleanup(int sig)
1645{
1646#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
1647    rmut();
1648#ifdef HAVE_VHANGUP
1649#ifndef __sgi
1650    vhangup(); /* XXX */
1651#endif
1652#endif
1653#else
1654    char *p;
1655
1656    p = line + sizeof("/dev/") - 1;
1657    if (logout(p))
1658	logwtmp(p, "", "");
1659    chmod(line, 0666);
1660    chown(line, 0, 0);
1661    *p = 'p';
1662    chmod(line, 0666);
1663    chown(line, 0, 0);
1664#endif
1665    shutdown(net, 2);
1666    exit(1);
1667}
1668
1669#endif /* PARENT_DOES_UTMP */
1670
1671#ifdef PARENT_DOES_UTMP
1672/*
1673 * _utmp_sig_rcv
1674 * utmp_sig_init
1675 * utmp_sig_wait
1676 *	These three functions are used to coordinate the handling of
1677 *	the utmp file between the server and the soon-to-be-login shell.
1678 *	The server actually creates the utmp structure, the child calls
1679 *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
1680 *	signals the future-login shell to proceed.
1681 */
1682static int caught=0;		/* NZ when signal intercepted */
1683static void (*func)();		/* address of previous handler */
1684
1685void
1686_utmp_sig_rcv(sig)
1687     int sig;
1688{
1689    caught = 1;
1690    signal(SIGUSR1, func);
1691}
1692
1693void
1694utmp_sig_init()
1695{
1696    /*
1697     * register signal handler for UTMP creation
1698     */
1699    if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
1700	fatalperror(net, "telnetd/signal");
1701}
1702
1703void
1704utmp_sig_reset()
1705{
1706    signal(SIGUSR1, func);	/* reset handler to default */
1707}
1708
1709# ifdef __hpux
1710# define sigoff() /* do nothing */
1711# define sigon() /* do nothing */
1712# endif
1713
1714void
1715utmp_sig_wait()
1716{
1717    /*
1718     * Wait for parent to write our utmp entry.
1719	 */
1720    sigoff();
1721    while (caught == 0) {
1722	pause();	/* wait until we get a signal (sigon) */
1723	sigoff();	/* turn off signals while we check caught */
1724    }
1725    sigon();		/* turn on signals again */
1726}
1727
1728void
1729utmp_sig_notify(pid)
1730{
1731    kill(pid, SIGUSR1);
1732}
1733
1734#ifdef _CRAY
1735static int gotsigjob = 0;
1736
1737	/*ARGSUSED*/
1738void
1739sigjob(sig)
1740     int sig;
1741{
1742    int jid;
1743    struct jobtemp *jp;
1744
1745    while ((jid = waitjob(NULL)) != -1) {
1746	if (jid == 0) {
1747	    return;
1748	}
1749	gotsigjob++;
1750	jobend(jid, NULL, NULL);
1751    }
1752}
1753
1754/*
1755 *	jid_getutid:
1756 *		called by jobend() before calling cleantmp()
1757 *		to find the correct $TMPDIR to cleanup.
1758 */
1759
1760struct utmp *
1761jid_getutid(jid)
1762     int jid;
1763{
1764    struct utmp *cur = NULL;
1765
1766    setutent();	/* just to make sure */
1767    while (cur = getutent()) {
1768	if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
1769	    return(cur);
1770	}
1771    }
1772
1773    return(0);
1774}
1775
1776/*
1777 * Clean up the TMPDIR that login created.
1778 * The first time this is called we pick up the info
1779 * from the utmp.  If the job has already gone away,
1780 * then we'll clean up and be done.  If not, then
1781 * when this is called the second time it will wait
1782 * for the signal that the job is done.
1783 */
1784int
1785cleantmp(wtp)
1786     struct utmp *wtp;
1787{
1788    struct utmp *utp;
1789    static int first = 1;
1790    int mask, omask, ret;
1791    extern struct utmp *getutid (const struct utmp *_Id);
1792
1793
1794    mask = sigmask(WJSIGNAL);
1795
1796    if (first == 0) {
1797	omask = sigblock(mask);
1798	while (gotsigjob == 0)
1799	    sigpause(omask);
1800	return(1);
1801    }
1802    first = 0;
1803    setutent();	/* just to make sure */
1804
1805    utp = getutid(wtp);
1806    if (utp == 0) {
1807	syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1808	return(-1);
1809    }
1810    /*
1811     * Nothing to clean up if the user shell was never started.
1812     */
1813    if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
1814	return(1);
1815
1816    /*
1817     * Block the WJSIGNAL while we are in jobend().
1818     */
1819    omask = sigblock(mask);
1820    ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
1821    sigsetmask(omask);
1822    return(ret);
1823}
1824
1825int
1826jobend(jid, path, user)
1827     int jid;
1828     char *path;
1829     char *user;
1830{
1831    static int saved_jid = 0;
1832    static int pty_saved_jid = 0;
1833    static char saved_path[sizeof(wtmp.ut_tpath)+1];
1834    static char saved_user[sizeof(wtmp.ut_user)+1];
1835
1836    /*
1837     * this little piece of code comes into play
1838     * only when ptyreconnect is used to reconnect
1839     * to an previous session.
1840     *
1841     * this is the only time when the
1842     * "saved_jid != jid" code is executed.
1843     */
1844
1845    if ( saved_jid && saved_jid != jid ) {
1846	if (!path) {	/* called from signal handler */
1847	    pty_saved_jid = jid;
1848	} else {
1849	    pty_saved_jid = saved_jid;
1850	}
1851    }
1852
1853    if (path) {
1854	strlcpy(saved_path, path, sizeof(saved_path));
1855	strlcpy(saved_user, user, sizeof(saved_user));
1856    }
1857    if (saved_jid == 0) {
1858	saved_jid = jid;
1859	return(0);
1860    }
1861
1862    /* if the jid has changed, get the correct entry from the utmp file */
1863
1864    if ( saved_jid != jid ) {
1865	struct utmp *utp = NULL;
1866	struct utmp *jid_getutid();
1867
1868	utp = jid_getutid(pty_saved_jid);
1869
1870	if (utp == 0) {
1871	    syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
1872	    return(-1);
1873	}
1874
1875	cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
1876	return(1);
1877    }
1878
1879    cleantmpdir(jid, saved_path, saved_user);
1880    return(1);
1881}
1882
1883/*
1884 * Fork a child process to clean up the TMPDIR
1885 */
1886cleantmpdir(jid, tpath, user)
1887     int jid;
1888     char *tpath;
1889     char *user;
1890{
1891    switch(fork()) {
1892    case -1:
1893	syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
1894	       tpath);
1895	break;
1896    case 0:
1897	execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
1898	syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
1899	       tpath, CLEANTMPCMD);
1900	exit(1);
1901    default:
1902	/*
1903	 * Forget about child.  We will exit, and
1904	 * /etc/init will pick it up.
1905	 */
1906	break;
1907    }
1908}
1909#endif /* CRAY */
1910#endif	/* defined(PARENT_DOES_UTMP) */
1911