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