xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 46809)
121182Sdist /*
238904Sborman  * Copyright (c) 1989 Regents of the University of California.
333687Sbostic  * All rights reserved.
433687Sbostic  *
542673Sbostic  * %sccs.include.redist.c%
621182Sdist  */
721182Sdist 
86295Sroot #ifndef lint
921182Sdist char copyright[] =
1038904Sborman "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1121182Sdist  All rights reserved.\n";
1233687Sbostic #endif /* not lint */
136295Sroot 
1421182Sdist #ifndef lint
15*46809Sdab static char sccsid[] = "@(#)telnetd.c	5.48 (Berkeley) 03/01/91";
1633687Sbostic #endif /* not lint */
1721182Sdist 
1838904Sborman #include "telnetd.h"
1945234Sborman #include "pathnames.h"
2038904Sborman 
21*46809Sdab #if	defined(AUTHENTICATE)
22*46809Sdab #include <libtelnet/auth.h>
23*46809Sdab int	auth_level = 0;
24*46809Sdab #endif
25*46809Sdab #if	defined(SecurID)
26*46809Sdab int	require_SecurID = 0;
27*46809Sdab #endif
28*46809Sdab 
296002Sroot /*
3038904Sborman  * I/O data buffers,
3138904Sborman  * pointers, and counters.
326002Sroot  */
3338904Sborman char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
3438904Sborman char	ptyibuf2[BUFSIZ];
359218Ssam 
3638904Sborman int	hostinfo = 1;			/* do we print login banner? */
379218Ssam 
3838904Sborman #ifdef	CRAY
3938904Sborman extern int      newmap; /* nonzero if \n maps to ^M^J */
4040242Sborman int	lowpty = 0, highpty;	/* low, high pty numbers */
4138904Sborman #endif /* CRAY */
4212216Ssam 
4338904Sborman int debug = 0;
44*46809Sdab int keepalive = 1;
4538904Sborman char *progname;
469218Ssam 
47*46809Sdab extern void usage P((void));
4844363Sborman 
4938904Sborman main(argc, argv)
5038904Sborman 	char *argv[];
5138904Sborman {
5238904Sborman 	struct sockaddr_in from;
5338904Sborman 	int on = 1, fromlen;
54*46809Sdab 	register int ch;
55*46809Sdab 	extern char *optarg;
56*46809Sdab 	extern int optind;
57*46809Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
58*46809Sdab 	int tos = -1;
59*46809Sdab #endif
606002Sroot 
6138904Sborman 	pfrontp = pbackp = ptyobuf;
6238904Sborman 	netip = netibuf;
6338904Sborman 	nfrontp = nbackp = netobuf;
64*46809Sdab #if	defined(ENCRYPT)
65*46809Sdab 	nclearto = 0;
66*46809Sdab #endif
676002Sroot 
6838904Sborman 	progname = *argv;
6940242Sborman 
7040242Sborman #ifdef CRAY
7140242Sborman 	/*
7240242Sborman 	 * Get number of pty's before trying to process options,
7340242Sborman 	 * which may include changing pty range.
7440242Sborman 	 */
7540242Sborman 	highpty = getnpty();
7640242Sborman #endif /* CRAY */
7740242Sborman 
78*46809Sdab 	while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:")) != EOF) {
79*46809Sdab 		switch(ch) {
8027649Sminshall 
81*46809Sdab #ifdef	AUTHENTICATE
82*46809Sdab 		case 'a':
83*46809Sdab 			/*
84*46809Sdab 			 * Check for required authentication level
85*46809Sdab 			 */
86*46809Sdab 			if (strcmp(optarg, "debug") == 0) {
87*46809Sdab 				extern int auth_debug_mode;
88*46809Sdab 				auth_debug_mode = 1;
89*46809Sdab 			} else if (strcasecmp(optarg, "none") == 0) {
90*46809Sdab 				auth_level = 0;
91*46809Sdab 			} else if (strcasecmp(optarg, "other") == 0) {
92*46809Sdab 				auth_level = AUTH_OTHER;
93*46809Sdab 			} else if (strcasecmp(optarg, "user") == 0) {
94*46809Sdab 				auth_level = AUTH_USER;
95*46809Sdab 			} else if (strcasecmp(optarg, "valid") == 0) {
96*46809Sdab 				auth_level = AUTH_VALID;
97*46809Sdab 			} else if (strcasecmp(optarg, "off") == 0) {
98*46809Sdab 				/*
99*46809Sdab 				 * This hack turns off authentication
100*46809Sdab 				 */
101*46809Sdab 				auth_level = -1;
102*46809Sdab 			} else {
103*46809Sdab 				fprintf(stderr,
104*46809Sdab 			    "telnetd: unknown authorization level for -a\n");
105*46809Sdab 			}
106*46809Sdab 			break;
107*46809Sdab #endif	/* AUTHENTICATE */
10827649Sminshall 
109*46809Sdab #ifdef BFTPDAEMON
110*46809Sdab 		case 'B':
111*46809Sdab 			bftpd++;
112*46809Sdab 			break;
113*46809Sdab #endif /* BFTPDAEMON */
114*46809Sdab 
115*46809Sdab 		case 'd':
116*46809Sdab 			if (strcmp(optarg, "ebug") == 0) {
117*46809Sdab 				debug++;
118*46809Sdab 				break;
119*46809Sdab 			}
120*46809Sdab 			usage();
121*46809Sdab 			/* NOTREACHED */
122*46809Sdab 			break;
123*46809Sdab 
124*46809Sdab #ifdef DIAGNOSTICS
125*46809Sdab 		case 'D':
126*46809Sdab 			/*
127*46809Sdab 			 * Check for desired diagnostics capabilities.
128*46809Sdab 			 */
129*46809Sdab 			if (!strcmp(optarg, "report")) {
130*46809Sdab 				diagnostic |= TD_REPORT|TD_OPTIONS;
131*46809Sdab 			} else if (!strcmp(optarg, "exercise")) {
132*46809Sdab 				diagnostic |= TD_EXERCISE;
133*46809Sdab 			} else if (!strcmp(optarg, "netdata")) {
134*46809Sdab 				diagnostic |= TD_NETDATA;
135*46809Sdab 			} else if (!strcmp(optarg, "ptydata")) {
136*46809Sdab 				diagnostic |= TD_PTYDATA;
137*46809Sdab 			} else if (!strcmp(optarg, "options")) {
138*46809Sdab 				diagnostic |= TD_OPTIONS;
139*46809Sdab 			} else {
140*46809Sdab 				usage();
141*46809Sdab 				/* NOT REACHED */
142*46809Sdab 			}
143*46809Sdab 			break;
144*46809Sdab #endif /* DIAGNOSTICS */
145*46809Sdab 
146*46809Sdab #ifdef	AUTHENTICATE
147*46809Sdab 		case 'e':
148*46809Sdab 			if (strcmp(optarg, "debug") == 0) {
149*46809Sdab 				extern int encrypt_debug_mode;
150*46809Sdab 				encrypt_debug_mode = 1;
151*46809Sdab 				break;
152*46809Sdab 			}
153*46809Sdab 			usage();
154*46809Sdab 			/* NOTREACHED */
155*46809Sdab 			break;
156*46809Sdab #endif	/* AUTHENTICATE */
157*46809Sdab 
158*46809Sdab 		case 'h':
159*46809Sdab 			hostinfo = 0;
160*46809Sdab 			break;
161*46809Sdab 
162*46809Sdab #if	defined(CRAY) && defined(NEWINIT)
163*46809Sdab 		case 'I':
164*46809Sdab 		    {
165*46809Sdab 			extern char *gen_id;
166*46809Sdab 			gen_id = optarg;
167*46809Sdab 			break;
168*46809Sdab 		    }
169*46809Sdab #endif	/* defined(CRAY) && defined(NEWINIT) */
170*46809Sdab 
17138904Sborman #ifdef	LINEMODE
172*46809Sdab 		case 'l':
173*46809Sdab 			alwayslinemode = 1;
174*46809Sdab 			break;
17538904Sborman #endif	/* LINEMODE */
17627649Sminshall 
177*46809Sdab 		case 'n':
178*46809Sdab 			keepalive = 0;
179*46809Sdab 			break;
18027649Sminshall 
18145234Sborman #ifdef CRAY
182*46809Sdab 		case 'r':
183*46809Sdab 		    {
184*46809Sdab 			char *strchr();
185*46809Sdab 			char *c;
18627649Sminshall 
187*46809Sdab 			/*
188*46809Sdab 			 * Allow the specification of alterations
189*46809Sdab 			 * to the pty search range.  It is legal to
190*46809Sdab 			 * specify only one, and not change the
191*46809Sdab 			 * other from its default.
192*46809Sdab 			 */
193*46809Sdab 			c = strchr(optarg, '-');
194*46809Sdab 			if (c) {
195*46809Sdab 				*c++ = '\0';
196*46809Sdab 				highpty = atoi(c);
19744363Sborman 			}
198*46809Sdab 			if (*optarg != '\0')
199*46809Sdab 				lowpty = atoi(optarg);
200*46809Sdab 			if ((lowpty > highpty) || (lowpty < 0) ||
201*46809Sdab 							(highpty > 32767)) {
20244363Sborman 				usage();
20344363Sborman 				/* NOT REACHED */
20444363Sborman 			}
205*46809Sdab 			break;
206*46809Sdab 		    }
20738904Sborman #endif	/* CRAY */
2086002Sroot 
209*46809Sdab #ifdef	SecurID
210*46809Sdab 		case 's':
211*46809Sdab 			/* SecurID required */
212*46809Sdab 			require_SecurID = 1;
213*46809Sdab 			break;
214*46809Sdab #endif	/* SecurID */
215*46809Sdab 		case 'S':
216*46809Sdab #ifdef	HAS_GETTOS
217*46809Sdab 			if ((tos = parsetos(optarg, "tcp")) < 0)
218*46809Sdab 				fprintf(stderr, "%s%s%s\n",
219*46809Sdab 					"telnetd: Bad TOS argument '", optarg,
220*46809Sdab 					"'; will try to use default TOS");
221*46809Sdab #else
222*46809Sdab 			fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
223*46809Sdab 						"-S flag not supported\n");
224*46809Sdab #endif
225*46809Sdab 			break;
226*46809Sdab 
227*46809Sdab #ifdef	AUTHENTICATE
228*46809Sdab 		case 'X':
229*46809Sdab 			/*
230*46809Sdab 			 * Check for invalid authentication types
231*46809Sdab 			 */
232*46809Sdab 			auth_disable_name(optarg);
233*46809Sdab 			break;
234*46809Sdab #endif	/* AUTHENTICATE */
235*46809Sdab 
236*46809Sdab 		default:
237*46809Sdab 			fprintf(stderr, "telnetd: %s: unknown option\n", ch);
238*46809Sdab 			/* FALLTHROUGH */
239*46809Sdab 		case '?':
24044363Sborman 			usage();
241*46809Sdab 			/* NOTREACHED */
24244363Sborman 		}
24344363Sborman 	}
24444363Sborman 
245*46809Sdab 	argc -= optind;
246*46809Sdab 	argv += optind;
24744363Sborman 
24838904Sborman 	if (debug) {
24927185Sminshall 	    int s, ns, foo;
25027185Sminshall 	    struct servent *sp;
25127185Sminshall 	    static struct sockaddr_in sin = { AF_INET };
25227185Sminshall 
25344363Sborman 	    if (argc > 1) {
25444363Sborman 		usage();
25544363Sborman 		/* NOT REACHED */
25644363Sborman 	    } else if (argc == 1) {
25738904Sborman 		    if (sp = getservbyname(*argv, "tcp")) {
25838904Sborman 			sin.sin_port = sp->s_port;
25938904Sborman 		    } else {
26038904Sborman 			sin.sin_port = atoi(*argv);
26138904Sborman 			if ((int)sin.sin_port <= 0) {
26238904Sborman 			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
26344363Sborman 			    usage();
26444363Sborman 			    /* NOT REACHED */
26538904Sborman 			}
26638904Sborman 			sin.sin_port = htons((u_short)sin.sin_port);
26738904Sborman 		   }
26837210Sminshall 	    } else {
26937210Sminshall 		sp = getservbyname("telnet", "tcp");
27037210Sminshall 		if (sp == 0) {
27144363Sborman 		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
27238904Sborman 		    exit(1);
27337210Sminshall 		}
27437210Sminshall 		sin.sin_port = sp->s_port;
27527185Sminshall 	    }
27627185Sminshall 
27727185Sminshall 	    s = socket(AF_INET, SOCK_STREAM, 0);
27827185Sminshall 	    if (s < 0) {
27927185Sminshall 		    perror("telnetd: socket");;
28027185Sminshall 		    exit(1);
28127185Sminshall 	    }
28238904Sborman 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
28338904Sborman 	    if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
28427185Sminshall 		perror("bind");
28527185Sminshall 		exit(1);
28627185Sminshall 	    }
28727185Sminshall 	    if (listen(s, 1) < 0) {
28827185Sminshall 		perror("listen");
28927185Sminshall 		exit(1);
29027185Sminshall 	    }
29127185Sminshall 	    foo = sizeof sin;
29238904Sborman 	    ns = accept(s, (struct sockaddr *)&sin, &foo);
29327185Sminshall 	    if (ns < 0) {
29427185Sminshall 		perror("accept");
29527185Sminshall 		exit(1);
29627185Sminshall 	    }
29738904Sborman 	    (void) dup2(ns, 0);
29838904Sborman 	    (void) close(ns);
29938904Sborman 	    (void) close(s);
300*46809Sdab #ifdef convex
301*46809Sdab 	} else if (argc == 1) {
302*46809Sdab 		; /* VOID*/		/* Just ignore the host/port name */
303*46809Sdab #endif
30444363Sborman 	} else if (argc > 0) {
30544363Sborman 		usage();
30644363Sborman 		/* NOT REACHED */
30727185Sminshall 	}
30838904Sborman 
30924855Seric 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
31016371Skarels 	fromlen = sizeof (from);
31138904Sborman 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
31238904Sborman 		fprintf(stderr, "%s: ", progname);
31316371Skarels 		perror("getpeername");
31416371Skarels 		_exit(1);
3158346Ssam 	}
316*46809Sdab 	if (keepalive &&
317*46809Sdab 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
31817187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
31910418Ssam 	}
32040242Sborman 
321*46809Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
322*46809Sdab 	{
323*46809Sdab # if	defined(HAS_GETTOS)
324*46809Sdab 		struct tosent *tp;
325*46809Sdab 		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
326*46809Sdab 			tos = tp->t_tos;
327*46809Sdab # endif
328*46809Sdab 		if (tos < 0)
329*46809Sdab 			tos = 020;	/* Low Delay bit */
330*46809Sdab 		if (tos
331*46809Sdab 		   && (setsockopt(0, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
332*46809Sdab 		   && (errno != ENOPROTOOPT) )
333*46809Sdab 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
334*46809Sdab 	}
335*46809Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
33638904Sborman 	net = 0;
33738904Sborman 	doit(&from);
33838904Sborman 	/* NOTREACHED */
33938904Sborman }  /* end of main */
3406002Sroot 
341*46809Sdab 	void
34244363Sborman usage()
34344363Sborman {
344*46809Sdab 	fprintf(stderr, "Usage: telnetd");
345*46809Sdab #ifdef	AUTHENTICATE
346*46809Sdab 	fprintf(stderr, " [-a (debug|other|user|valid|off)]\n\t");
347*46809Sdab #endif
348*46809Sdab #ifdef BFTPDAEMON
349*46809Sdab 	fprintf(stderr, " [-B]");
350*46809Sdab #endif
351*46809Sdab 	fprintf(stderr, " [-debug]");
352*46809Sdab #ifdef DIAGNOSTICS
353*46809Sdab 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
354*46809Sdab #endif
355*46809Sdab #ifdef	AUTHENTICATE
356*46809Sdab 	fprintf(stderr, " [-edebug]");
357*46809Sdab #endif
358*46809Sdab 	fprintf(stderr, " [-h]");
359*46809Sdab #if	defined(CRAY) && defined(NEWINIT)
36044363Sborman 	fprintf(stderr, " [-Iinitid]");
361*46809Sdab #endif
36244363Sborman #ifdef LINEMODE
36344363Sborman 	fprintf(stderr, " [-l]");
36444363Sborman #endif
365*46809Sdab 	fprintf(stderr, " [-n]");
36644363Sborman #ifdef	CRAY
36744363Sborman 	fprintf(stderr, " [-r[lowpty]-[highpty]]");
36844363Sborman #endif
369*46809Sdab #ifdef	SecurID
370*46809Sdab 	fprintf(stderr, " [-s]");
371*46809Sdab #endif
372*46809Sdab #ifdef	AUTHENTICATE
373*46809Sdab 	fprintf(stderr, " [-X auth-type]");
374*46809Sdab #endif
37544363Sborman 	fprintf(stderr, " [port]\n");
37644363Sborman 	exit(1);
37744363Sborman }
37844363Sborman 
37927649Sminshall /*
38027983Sminshall  * getterminaltype
38127649Sminshall  *
38238904Sborman  *	Ask the other end to send along its terminal type and speed.
38327983Sminshall  * Output is the variable terminaltype filled in.
38427649Sminshall  */
38538904Sborman static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
386*46809Sdab 
387*46809Sdab     int
388*46809Sdab getterminaltype(name)
389*46809Sdab     char *name;
39027649Sminshall {
391*46809Sdab     int retval = -1;
392*46809Sdab     void _gettermname();
39327649Sminshall 
39438904Sborman     settimer(baseline);
395*46809Sdab #if	defined(AUTHENTICATE)
396*46809Sdab     /*
397*46809Sdab      * Handle the Authentication option before we do anything else.
398*46809Sdab      */
399*46809Sdab     send_do(TELOPT_AUTHENTICATION, 1);
400*46809Sdab     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
401*46809Sdab 	ttloop();
402*46809Sdab     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
403*46809Sdab 	retval = auth_wait(name);
404*46809Sdab     }
405*46809Sdab #endif
406*46809Sdab 
407*46809Sdab #if	defined(ENCRYPT)
408*46809Sdab     send_will(TELOPT_ENCRYPT, 1);
409*46809Sdab #endif
41039503Sborman     send_do(TELOPT_TTYPE, 1);
41139503Sborman     send_do(TELOPT_TSPEED, 1);
41244363Sborman     send_do(TELOPT_XDISPLOC, 1);
41344363Sborman     send_do(TELOPT_ENVIRON, 1);
414*46809Sdab     while (
415*46809Sdab #if	defined(ENCRYPT)
416*46809Sdab 	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
417*46809Sdab #endif
418*46809Sdab 	   his_will_wont_is_changing(TELOPT_TTYPE) ||
41944363Sborman 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
42044363Sborman 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
42144363Sborman 	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
42227983Sminshall 	ttloop();
42327649Sminshall     }
424*46809Sdab #if	defined(ENCRYPT)
425*46809Sdab     /*
426*46809Sdab      * Wait for the negotiation of what type of encryption we can
427*46809Sdab      * send with.  If autoencrypt is not set, this will just return.
428*46809Sdab      */
429*46809Sdab     if (his_state_is_will(TELOPT_ENCRYPT)) {
430*46809Sdab 	encrypt_wait();
431*46809Sdab     }
432*46809Sdab #endif
43344363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
43438904Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
43527983Sminshall 
43627983Sminshall 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
43727983Sminshall 	nfrontp += sizeof sbbuf;
43838904Sborman     }
43944363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
44044363Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
44138904Sborman 
44244363Sborman 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
44344363Sborman 	nfrontp += sizeof sbbuf;
44444363Sborman     }
44544363Sborman     if (his_state_is_will(TELOPT_ENVIRON)) {
44644363Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
44744363Sborman 
44844363Sborman 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
44944363Sborman 	nfrontp += sizeof sbbuf;
45044363Sborman     }
45144363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
45244363Sborman 
45338904Sborman 	bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
45438904Sborman 	nfrontp += sizeof ttytype_sbbuf;
45538904Sborman     }
45644363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
45738904Sborman 	while (sequenceIs(tspeedsubopt, baseline))
45827983Sminshall 	    ttloop();
45938904Sborman     }
46044363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
46144363Sborman 	while (sequenceIs(xdisplocsubopt, baseline))
46244363Sborman 	    ttloop();
46344363Sborman     }
46444363Sborman     if (his_state_is_will(TELOPT_ENVIRON)) {
46544363Sborman 	while (sequenceIs(environsubopt, baseline))
46644363Sborman 	    ttloop();
46744363Sborman     }
46844363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
46938904Sborman 	char first[256], last[256];
47038904Sborman 
47138904Sborman 	while (sequenceIs(ttypesubopt, baseline))
47238904Sborman 	    ttloop();
47338904Sborman 
47444363Sborman 	/*
47544363Sborman 	 * If the other side has already disabled the option, then
47644363Sborman 	 * we have to just go with what we (might) have already gotten.
47744363Sborman 	 */
47844363Sborman 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
47938904Sborman 	    (void) strncpy(first, terminaltype, sizeof(first));
48038904Sborman 	    for(;;) {
48138904Sborman 		/*
48238904Sborman 		 * Save the unknown name, and request the next name.
48338904Sborman 		 */
48438904Sborman 		(void) strncpy(last, terminaltype, sizeof(last));
48538904Sborman 		_gettermname();
48644363Sborman 		if (terminaltypeok(terminaltype))
48738904Sborman 		    break;
48844363Sborman 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
48944363Sborman 		    his_state_is_wont(TELOPT_TTYPE)) {
49038904Sborman 		    /*
49138904Sborman 		     * We've hit the end.  If this is the same as
49238904Sborman 		     * the first name, just go with it.
49338904Sborman 		     */
49445234Sborman 		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
49538904Sborman 			break;
49638904Sborman 		    /*
49744363Sborman 		     * Get the terminal name one more time, so that
49838904Sborman 		     * RFC1091 compliant telnets will cycle back to
49938904Sborman 		     * the start of the list.
50038904Sborman 		     */
50144363Sborman 		     _gettermname();
50245234Sborman 		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
50338904Sborman 			(void) strncpy(terminaltype, first, sizeof(first));
50438904Sborman 		    break;
50538904Sborman 		}
50638904Sborman 	    }
50727983Sminshall 	}
50827983Sminshall     }
509*46809Sdab     return(retval);
51038904Sborman }  /* end of getterminaltype */
51138904Sborman 
512*46809Sdab     void
51338904Sborman _gettermname()
51438904Sborman {
51544363Sborman     /*
51644363Sborman      * If the client turned off the option,
51744363Sborman      * we can't send another request, so we
51844363Sborman      * just return.
51944363Sborman      */
52044363Sborman     if (his_state_is_wont(TELOPT_TTYPE))
52144363Sborman 	return;
52238904Sborman     settimer(baseline);
52338904Sborman     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
52438904Sborman     nfrontp += sizeof ttytype_sbbuf;
52538904Sborman     while (sequenceIs(ttypesubopt, baseline))
52638904Sborman 	ttloop();
52727649Sminshall }
52827649Sminshall 
529*46809Sdab     int
53038904Sborman terminaltypeok(s)
531*46809Sdab     char *s;
53238904Sborman {
53338904Sborman     char buf[1024];
53438904Sborman 
53538904Sborman     if (terminaltype == NULL)
53638904Sborman 	return(1);
53738904Sborman 
53838904Sborman     /*
53938904Sborman      * tgetent() will return 1 if the type is known, and
54038904Sborman      * 0 if it is not known.  If it returns -1, it couldn't
54138904Sborman      * open the database.  But if we can't open the database,
54238904Sborman      * it won't help to say we failed, because we won't be
54338904Sborman      * able to verify anything else.  So, we treat -1 like 1.
54438904Sborman      */
54538904Sborman     if (tgetent(buf, s) == 0)
54638904Sborman 	return(0);
54738904Sborman     return(1);
54838904Sborman }
54938904Sborman 
550*46809Sdab #ifndef	MAXHOSTNAMELEN
551*46809Sdab #define	MAXHOSTNAMELEN 64
552*46809Sdab #endif	/* MAXHOSTNAMELEN */
553*46809Sdab 
554*46809Sdab char *hostname;
555*46809Sdab char host_name[MAXHOSTNAMELEN];
556*46809Sdab char remote_host_name[MAXHOSTNAMELEN];
557*46809Sdab 
558*46809Sdab #ifndef	convex
559*46809Sdab extern void telnet P((int, int));
560*46809Sdab #else
561*46809Sdab extern void telnet P((int, int, char *));
562*46809Sdab #endif
563*46809Sdab 
5646002Sroot /*
5656002Sroot  * Get a pty, scan input lines.
5666002Sroot  */
56738904Sborman doit(who)
56812683Ssam 	struct sockaddr_in *who;
5696002Sroot {
57020188Skarels 	char *host, *inet_ntoa();
57138904Sborman 	int t;
57212683Ssam 	struct hostent *hp;
573*46809Sdab 	int level;
574*46809Sdab 	char user_name[256];
5756002Sroot 
57638904Sborman 	/*
57738904Sborman 	 * Find an available pty to use.
57838904Sborman 	 */
57945234Sborman #ifndef	convex
58038904Sborman 	pty = getpty();
58138904Sborman 	if (pty < 0)
58238904Sborman 		fatal(net, "All network ports in use");
58345234Sborman #else
58445234Sborman 	for (;;) {
58545234Sborman 		char *lp;
58645234Sborman 		extern char *line, *getpty();
58720188Skarels 
58845234Sborman 		if ((lp = getpty()) == NULL)
58945234Sborman 			fatal(net, "Out of ptys");
59045234Sborman 
59145234Sborman 		if ((pty = open(lp, 2)) >= 0) {
59245234Sborman 			strcpy(line,lp);
59345234Sborman 			line[5] = 't';
59445234Sborman 			break;
59545234Sborman 		}
59645234Sborman 	}
59744545Smarc #endif
59838904Sborman 
59938904Sborman 	/* get name of connected client */
60038904Sborman 	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
60112683Ssam 		who->sin_family);
60212683Ssam 	if (hp)
60312683Ssam 		host = hp->h_name;
60412683Ssam 	else
60517444Sralph 		host = inet_ntoa(who->sin_addr);
606*46809Sdab 	/*
607*46809Sdab 	 * We must make a copy because Kerberos is probably going
608*46809Sdab 	 * to also do a gethost* and overwrite the static data...
609*46809Sdab 	 */
610*46809Sdab 	strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
611*46809Sdab 	remote_host_name[sizeof(remote_host_name)-1] = 0;
612*46809Sdab 	host = remote_host_name;
61327983Sminshall 
614*46809Sdab 	(void) gethostname(host_name, sizeof (host_name));
615*46809Sdab 	hostname = host_name;
616*46809Sdab 
617*46809Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
618*46809Sdab 	auth_encrypt_init(hostname, host, "TELNETD", 1);
619*46809Sdab #endif
620*46809Sdab 
62144363Sborman 	init_env();
62227983Sminshall 	/*
62338904Sborman 	 * get terminal type.
62427983Sminshall 	 */
625*46809Sdab 	*user_name = 0;
626*46809Sdab 	level = getterminaltype(user_name);
62744363Sborman 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
62827983Sminshall 
62927649Sminshall 	/*
63038904Sborman 	 * Start up the login process on the slave side of the terminal
63127649Sminshall 	 */
63245234Sborman #ifndef	convex
633*46809Sdab 	startslave(host, level, user_name);
63438904Sborman 
63538904Sborman 	telnet(net, pty);  /* begin server processing */
63645234Sborman #else
63745234Sborman 	telnet(net, pty, host);
63845234Sborman #endif
6399244Ssam 	/*NOTREACHED*/
64038904Sborman }  /* end of doit */
6419244Ssam 
642*46809Sdab #if	defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
643*46809Sdab 	int
644*46809Sdab Xterm_output(ibufp, obuf, icountp, ocount)
645*46809Sdab 	char **ibufp, *obuf;
646*46809Sdab 	int *icountp, ocount;
647*46809Sdab {
648*46809Sdab 	int ret;
649*46809Sdab 	ret = term_output(*ibufp, obuf, *icountp, ocount);
650*46809Sdab 	*ibufp += *icountp;
651*46809Sdab 	*icountp = 0;
652*46809Sdab 	return(ret);
653*46809Sdab }
654*46809Sdab #define	term_output	Xterm_output
655*46809Sdab #endif	/* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
656*46809Sdab 
6576002Sroot /*
6586002Sroot  * Main loop.  Select from pty and network, and
6596002Sroot  * hand data to telnet receiver finite state machine.
6606002Sroot  */
661*46809Sdab 	void
66245234Sborman #ifndef	convex
6636002Sroot telnet(f, p)
66445234Sborman #else
66545234Sborman telnet(f, p, host)
66645234Sborman #endif
667*46809Sdab 	int f, p;
66845234Sborman #ifdef convex
669*46809Sdab 	char *host;
67045234Sborman #endif
6716002Sroot {
6726002Sroot 	int on = 1;
67333271Sminshall #define	TABBUFSIZ	512
67433271Sminshall 	char	defent[TABBUFSIZ];
67533271Sminshall 	char	defstrs[TABBUFSIZ];
67633271Sminshall #undef	TABBUFSIZ
67733271Sminshall 	char *HE;
67833271Sminshall 	char *HN;
67933271Sminshall 	char *IM;
68038904Sborman 	void netflush();
681*46809Sdab 
68232400Sminshall 	/*
68338904Sborman 	 * Initialize the slc mapping table.
68432400Sminshall 	 */
68538904Sborman 	get_slc_defaults();
6866002Sroot 
6878379Ssam 	/*
68838904Sborman 	 * Do some tests where it is desireable to wait for a response.
68938904Sborman 	 * Rather than doing them slowly, one at a time, do them all
69038904Sborman 	 * at once.
6918379Ssam 	 */
69244363Sborman 	if (my_state_is_wont(TELOPT_SGA))
69339503Sborman 		send_will(TELOPT_SGA, 1);
69412713Ssam 	/*
69527649Sminshall 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
69627649Sminshall 	 * because 4.2 clients are unable to deal with TCP urgent data.
69727649Sminshall 	 *
69827649Sminshall 	 * To find out, we send out a "DO ECHO".  If the remote system
69927649Sminshall 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
70027649Sminshall 	 * that fact ("WILL ECHO" ==> that the client will echo what
70127649Sminshall 	 * WE, the server, sends it; it does NOT mean that the client will
70227649Sminshall 	 * echo the terminal input).
70327649Sminshall 	 */
70439503Sborman 	send_do(TELOPT_ECHO, 1);
70527649Sminshall 
70638904Sborman #ifdef	LINEMODE
70744363Sborman 	if (his_state_is_wont(TELOPT_LINEMODE)) {
70838904Sborman 		/* Query the peer for linemode support by trying to negotiate
70938904Sborman 		 * the linemode option.
71038904Sborman 		 */
71144363Sborman 		linemode = 0;
71238904Sborman 		editmode = 0;
71339503Sborman 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
71438904Sborman 	}
71538904Sborman #endif	/* LINEMODE */
71638904Sborman 
71727649Sminshall 	/*
71838904Sborman 	 * Send along a couple of other options that we wish to negotiate.
71938904Sborman 	 */
72039503Sborman 	send_do(TELOPT_NAWS, 1);
72139503Sborman 	send_will(TELOPT_STATUS, 1);
72238904Sborman 	flowmode = 1;  /* default flow control state */
72339503Sborman 	send_do(TELOPT_LFLOW, 1);
72438904Sborman 
72538904Sborman 	/*
72638904Sborman 	 * Spin, waiting for a response from the DO ECHO.  However,
72738904Sborman 	 * some REALLY DUMB telnets out there might not respond
72838904Sborman 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
72938904Sborman 	 * telnets so far seem to respond with WONT for a DO that
73038904Sborman 	 * they don't understand...) because by the time we get the
73138904Sborman 	 * response, it will already have processed the DO ECHO.
73238904Sborman 	 * Kludge upon kludge.
73338904Sborman 	 */
73444363Sborman 	while (his_will_wont_is_changing(TELOPT_NAWS))
73538904Sborman 		ttloop();
73638904Sborman 
73738904Sborman 	/*
73844363Sborman 	 * But...
73944363Sborman 	 * The client might have sent a WILL NAWS as part of its
74044363Sborman 	 * startup code; if so, we'll be here before we get the
74144363Sborman 	 * response to the DO ECHO.  We'll make the assumption
74244363Sborman 	 * that any implementation that understands about NAWS
74344363Sborman 	 * is a modern enough implementation that it will respond
74444363Sborman 	 * to our DO ECHO request; hence we'll do another spin
74544363Sborman 	 * waiting for the ECHO option to settle down, which is
74644363Sborman 	 * what we wanted to do in the first place...
74744363Sborman 	 */
74844363Sborman 	if (his_want_state_is_will(TELOPT_ECHO) &&
74944363Sborman 	    his_state_is_will(TELOPT_NAWS)) {
75044363Sborman 		while (his_will_wont_is_changing(TELOPT_ECHO))
75144363Sborman 			ttloop();
75244363Sborman 	}
75344363Sborman 	/*
75438995Sborman 	 * On the off chance that the telnet client is broken and does not
75538995Sborman 	 * respond to the DO ECHO we sent, (after all, we did send the
75638995Sborman 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
75738995Sborman 	 * until a response to the DO NAWS comes back) simulate the
75838995Sborman 	 * receipt of a will echo.  This will also send a WONT ECHO
75938995Sborman 	 * to the client, since we assume that the client failed to
76038995Sborman 	 * respond because it believes that it is already in DO ECHO
76138995Sborman 	 * mode, which we do not want.
76238995Sborman 	 */
76344363Sborman 	if (his_want_state_is_will(TELOPT_ECHO)) {
764*46809Sdab 		DIAG(TD_OPTIONS,
765*46809Sdab 			{sprintf(nfrontp, "td: simulating recv\r\n");
766*46809Sdab 			 nfrontp += strlen(nfrontp);});
76739503Sborman 		willoption(TELOPT_ECHO);
76840242Sborman 	}
76938995Sborman 
77038995Sborman 	/*
77138995Sborman 	 * Finally, to clean things up, we turn on our echo.  This
77238995Sborman 	 * will break stupid 4.2 telnets out of local terminal echo.
77338995Sborman 	 */
77438995Sborman 
77544363Sborman 	if (my_state_is_wont(TELOPT_ECHO))
77639503Sborman 		send_will(TELOPT_ECHO, 1);
77738995Sborman 
77838995Sborman 	/*
77945234Sborman 	 * Turn on packet mode
78038904Sborman 	 */
78138904Sborman 	(void) ioctl(p, TIOCPKT, (char *)&on);
782*46809Sdab #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
78338904Sborman 	/*
78438904Sborman 	 * Continuing line mode support.  If client does not support
78538904Sborman 	 * real linemode, attempt to negotiate kludge linemode by sending
78638904Sborman 	 * the do timing mark sequence.
78738904Sborman 	 */
78838904Sborman 	if (lmodetype < REAL_LINEMODE)
78939503Sborman 		send_do(TELOPT_TM, 1);
790*46809Sdab #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
79138904Sborman 
79238904Sborman 	/*
79338904Sborman 	 * Call telrcv() once to pick up anything received during
79438904Sborman 	 * terminal type negotiation, 4.2/4.3 determination, and
79538904Sborman 	 * linemode negotiation.
79638904Sborman 	 */
79738904Sborman 	telrcv();
79838904Sborman 
79938904Sborman 	(void) ioctl(f, FIONBIO, (char *)&on);
80038904Sborman 	(void) ioctl(p, FIONBIO, (char *)&on);
80140242Sborman #if	defined(CRAY2) && defined(UNICOS5)
80238904Sborman 	init_termdriver(f, p, interrupt, sendbrk);
80338904Sborman #endif
80438904Sborman 
80538904Sborman #if	defined(SO_OOBINLINE)
80638904Sborman 	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
80738904Sborman #endif	/* defined(SO_OOBINLINE) */
80838904Sborman 
80938904Sborman #ifdef	SIGTSTP
81038904Sborman 	(void) signal(SIGTSTP, SIG_IGN);
81138904Sborman #endif
81238904Sborman #ifdef	SIGTTOU
81338904Sborman 	/*
81438904Sborman 	 * Ignoring SIGTTOU keeps the kernel from blocking us
81538904Sborman 	 * in ttioct() in /sys/tty.c.
81638904Sborman 	 */
81738904Sborman 	(void) signal(SIGTTOU, SIG_IGN);
81838904Sborman #endif
81938904Sborman 
82038904Sborman 	(void) signal(SIGCHLD, cleanup);
82138904Sborman 
82240242Sborman #if	defined(CRAY2) && defined(UNICOS5)
82338904Sborman 	/*
82438904Sborman 	 * Cray-2 will send a signal when pty modes are changed by slave
82538904Sborman 	 * side.  Set up signal handler now.
82638904Sborman 	 */
82738904Sborman 	if ((int)signal(SIGUSR1, termstat) < 0)
82838904Sborman 		perror("signal");
82938904Sborman 	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
83038904Sborman 		perror("ioctl:TCSIGME");
83138904Sborman 	/*
83238904Sborman 	 * Make processing loop check terminal characteristics early on.
83338904Sborman 	 */
83438904Sborman 	termstat();
83538904Sborman #endif
83638904Sborman 
83745234Sborman #ifdef  TIOCNOTTY
83845234Sborman 	{
83945234Sborman 		register int t;
84045234Sborman 		t = open(_PATH_TTY, O_RDWR);
84145234Sborman 		if (t >= 0) {
84245234Sborman 			(void) ioctl(t, TIOCNOTTY, (char *)0);
84345234Sborman 			(void) close(t);
84445234Sborman 		}
84545234Sborman 	}
84640242Sborman #endif
84745234Sborman 
848*46809Sdab #if	defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
84945234Sborman 	(void) setsid();
85044363Sborman 	ioctl(p, TIOCSCTTY, 0);
85144363Sborman #endif
85238904Sborman 
85338904Sborman 	/*
85412713Ssam 	 * Show banner that getty never gave.
85527797Sminshall 	 *
85633271Sminshall 	 * We put the banner in the pty input buffer.  This way, it
85733271Sminshall 	 * gets carriage return null processing, etc., just like all
85833271Sminshall 	 * other pty --> client data.
85912713Ssam 	 */
86027797Sminshall 
86145234Sborman #if	!defined(CRAY) || !defined(NEWINIT)
86245234Sborman 	if (getenv("USER"))
86345234Sborman 		hostinfo = 0;
86445234Sborman #endif
86538904Sborman 
86633271Sminshall 	if (getent(defent, "default") == 1) {
86733271Sminshall 		char *getstr();
86838904Sborman 		char *cp=defstrs;
86927649Sminshall 
87038904Sborman 		HE = getstr("he", &cp);
87138904Sborman 		HN = getstr("hn", &cp);
87238904Sborman 		IM = getstr("im", &cp);
87333271Sminshall 		if (HN && *HN)
874*46809Sdab 			(void) strcpy(host_name, HN);
87538904Sborman 		if (IM == 0)
87638904Sborman 			IM = "";
87733271Sminshall 	} else {
87845234Sborman 		IM = DEFAULT_IM;
87938904Sborman 		HE = 0;
88033271Sminshall 	}
881*46809Sdab 	edithost(HE, host_name);
88245234Sborman 	if (hostinfo && *IM)
88338904Sborman 		putf(IM, ptyibuf2);
88427797Sminshall 
88538904Sborman 	if (pcc)
88638904Sborman 		(void) strncat(ptyibuf2, ptyip, pcc+1);
88738904Sborman 	ptyip = ptyibuf2;
88838904Sborman 	pcc = strlen(ptyip);
88940242Sborman #ifdef	LINEMODE
89040242Sborman 	/*
89140242Sborman 	 * Last check to make sure all our states are correct.
89240242Sborman 	 */
89340242Sborman 	init_termbuf();
89440242Sborman 	localstat();
89540242Sborman #endif	/* LINEMODE */
89633271Sminshall 
897*46809Sdab 	DIAG(TD_REPORT,
898*46809Sdab 		{sprintf(nfrontp, "td: Entering processing loop\r\n");
899*46809Sdab 		 nfrontp += strlen(nfrontp);});
90044363Sborman 
90145234Sborman #ifdef	convex
90245234Sborman 	startslave(host);
90345234Sborman #endif
90445234Sborman 
9056002Sroot 	for (;;) {
90627185Sminshall 		fd_set ibits, obits, xbits;
9076002Sroot 		register int c;
9086002Sroot 
90927185Sminshall 		if (ncc < 0 && pcc < 0)
91027185Sminshall 			break;
91127185Sminshall 
91240242Sborman #if	defined(CRAY2) && defined(UNICOS5)
91338904Sborman 		if (needtermstat)
91438904Sborman 			_termstat();
91540242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
91627185Sminshall 		FD_ZERO(&ibits);
91727185Sminshall 		FD_ZERO(&obits);
91827185Sminshall 		FD_ZERO(&xbits);
9196002Sroot 		/*
9206002Sroot 		 * Never look for input if there's still
9216002Sroot 		 * stuff in the corresponding output buffer
9226002Sroot 		 */
92327185Sminshall 		if (nfrontp - nbackp || pcc > 0) {
92427185Sminshall 			FD_SET(f, &obits);
92527185Sminshall 		} else {
92627185Sminshall 			FD_SET(p, &ibits);
92727185Sminshall 		}
92827185Sminshall 		if (pfrontp - pbackp || ncc > 0) {
92927185Sminshall 			FD_SET(p, &obits);
93027185Sminshall 		} else {
93127185Sminshall 			FD_SET(f, &ibits);
93227185Sminshall 		}
93327185Sminshall 		if (!SYNCHing) {
93427185Sminshall 			FD_SET(f, &xbits);
93527185Sminshall 		}
93627185Sminshall 		if ((c = select(16, &ibits, &obits, &xbits,
93727185Sminshall 						(struct timeval *)0)) < 1) {
93827185Sminshall 			if (c == -1) {
93927185Sminshall 				if (errno == EINTR) {
94027185Sminshall 					continue;
94127185Sminshall 				}
94227185Sminshall 			}
9436002Sroot 			sleep(5);
9446002Sroot 			continue;
9456002Sroot 		}
9466002Sroot 
9476002Sroot 		/*
94827185Sminshall 		 * Any urgent data?
94927185Sminshall 		 */
95027185Sminshall 		if (FD_ISSET(net, &xbits)) {
95127185Sminshall 		    SYNCHing = 1;
95227185Sminshall 		}
95327185Sminshall 
95427185Sminshall 		/*
9556002Sroot 		 * Something to read from the network...
9566002Sroot 		 */
95727185Sminshall 		if (FD_ISSET(net, &ibits)) {
95827649Sminshall #if	!defined(SO_OOBINLINE)
95927185Sminshall 			/*
96027898Skarels 			 * In 4.2 (and 4.3 beta) systems, the
96127185Sminshall 			 * OOB indication and data handling in the kernel
96227185Sminshall 			 * is such that if two separate TCP Urgent requests
96327185Sminshall 			 * come in, one byte of TCP data will be overlaid.
96427185Sminshall 			 * This is fatal for Telnet, but we try to live
96527185Sminshall 			 * with it.
96627185Sminshall 			 *
96727185Sminshall 			 * In addition, in 4.2 (and...), a special protocol
96827185Sminshall 			 * is needed to pick up the TCP Urgent data in
96927185Sminshall 			 * the correct sequence.
97027185Sminshall 			 *
97127185Sminshall 			 * What we do is:  if we think we are in urgent
97227185Sminshall 			 * mode, we look to see if we are "at the mark".
97327185Sminshall 			 * If we are, we do an OOB receive.  If we run
97427185Sminshall 			 * this twice, we will do the OOB receive twice,
97527185Sminshall 			 * but the second will fail, since the second
97627185Sminshall 			 * time we were "at the mark", but there wasn't
97727185Sminshall 			 * any data there (the kernel doesn't reset
97827185Sminshall 			 * "at the mark" until we do a normal read).
97927185Sminshall 			 * Once we've read the OOB data, we go ahead
98027185Sminshall 			 * and do normal reads.
98127185Sminshall 			 *
98227185Sminshall 			 * There is also another problem, which is that
98327185Sminshall 			 * since the OOB byte we read doesn't put us
98427185Sminshall 			 * out of OOB state, and since that byte is most
98527185Sminshall 			 * likely the TELNET DM (data mark), we would
98627185Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
98727185Sminshall 			 * So, clocks to the rescue.  If we've "just"
98827185Sminshall 			 * received a DM, then we test for the
98927185Sminshall 			 * presence of OOB data when the receive OOB
99027185Sminshall 			 * fails (and AFTER we did the normal mode read
99127185Sminshall 			 * to clear "at the mark").
99227185Sminshall 			 */
99327185Sminshall 		    if (SYNCHing) {
99427185Sminshall 			int atmark;
99527185Sminshall 
99638904Sborman 			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
99727185Sminshall 			if (atmark) {
99827185Sminshall 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
99927185Sminshall 			    if ((ncc == -1) && (errno == EINVAL)) {
100027185Sminshall 				ncc = read(net, netibuf, sizeof (netibuf));
100127983Sminshall 				if (sequenceIs(didnetreceive, gotDM)) {
100227185Sminshall 				    SYNCHing = stilloob(net);
100327185Sminshall 				}
100427185Sminshall 			    }
100527185Sminshall 			} else {
100627185Sminshall 			    ncc = read(net, netibuf, sizeof (netibuf));
10076002Sroot 			}
100827185Sminshall 		    } else {
100927185Sminshall 			ncc = read(net, netibuf, sizeof (netibuf));
101027185Sminshall 		    }
101127185Sminshall 		    settimer(didnetreceive);
101227649Sminshall #else	/* !defined(SO_OOBINLINE)) */
101327185Sminshall 		    ncc = read(net, netibuf, sizeof (netibuf));
101427649Sminshall #endif	/* !defined(SO_OOBINLINE)) */
101527185Sminshall 		    if (ncc < 0 && errno == EWOULDBLOCK)
101627185Sminshall 			ncc = 0;
101727185Sminshall 		    else {
101827185Sminshall 			if (ncc <= 0) {
101927185Sminshall 			    break;
102027185Sminshall 			}
102127185Sminshall 			netip = netibuf;
102227185Sminshall 		    }
1023*46809Sdab 		    DIAG((TD_REPORT | TD_NETDATA),
1024*46809Sdab 			    {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
1025*46809Sdab 			     nfrontp += strlen(nfrontp);});
1026*46809Sdab 		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
10276002Sroot 		}
10286002Sroot 
10296002Sroot 		/*
10306002Sroot 		 * Something to read from the pty...
10316002Sroot 		 */
103238904Sborman 		if (FD_ISSET(p, &ibits)) {
10336002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
1034*46809Sdab 			/*
1035*46809Sdab 			 * On some systems, if we try to read something
1036*46809Sdab 			 * off the master side before the slave side is
1037*46809Sdab 			 * opened, we get EIO.
1038*46809Sdab 			 */
1039*46809Sdab 			if (pcc < 0 && (errno == EWOULDBLOCK || errno == EIO)) {
10406002Sroot 				pcc = 0;
1041*46809Sdab 			} else {
10426002Sroot 				if (pcc <= 0)
10436002Sroot 					break;
104440242Sborman #if	!defined(CRAY2) || !defined(UNICOS5)
104538904Sborman #ifdef	LINEMODE
104638904Sborman 				/*
104738904Sborman 				 * If ioctl from pty, pass it through net
104838904Sborman 				 */
104938904Sborman 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
105038904Sborman 					copy_termbuf(ptyibuf+1, pcc-1);
105138904Sborman 					localstat();
105238904Sborman 					pcc = 1;
105338904Sborman 				}
1054*46809Sdab #endif	/* LINEMODE */
105537210Sminshall 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
105638904Sborman 					netclear();	/* clear buffer back */
105745234Sborman #ifndef	NO_URGENT
105840242Sborman 					/*
105945234Sborman 					 * There are client telnets on some
106040242Sborman 					 * operating systems get screwed up
106140242Sborman 					 * royally if we send them urgent
106245234Sborman 					 * mode data.
106340242Sborman 					 */
106437210Sminshall 					*nfrontp++ = IAC;
106537210Sminshall 					*nfrontp++ = DM;
106637210Sminshall 					neturg = nfrontp-1; /* off by one XXX */
106740242Sborman #endif
106837210Sminshall 				}
106944363Sborman 				if (his_state_is_will(TELOPT_LFLOW) &&
107037210Sminshall 				    (ptyibuf[0] &
107138904Sborman 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
107238904Sborman 					(void) sprintf(nfrontp, "%c%c%c%c%c%c",
107337210Sminshall 					    IAC, SB, TELOPT_LFLOW,
107437210Sminshall 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
107537210Sminshall 					    IAC, SE);
107637210Sminshall 					nfrontp += 6;
107737210Sminshall 				}
107833267Sminshall 				pcc--;
107933267Sminshall 				ptyip = ptyibuf+1;
108040242Sborman #else	/* defined(CRAY2) && defined(UNICOS5) */
108138904Sborman 				if (!uselinemode) {
108239531Sborman 					unpcc = pcc;
108339531Sborman 					unptyip = ptyibuf;
108439531Sborman 					pcc = term_output(&unptyip, ptyibuf2,
108539531Sborman 								&unpcc, BUFSIZ);
108638904Sborman 					ptyip = ptyibuf2;
108738904Sborman 				} else
108838904Sborman 					ptyip = ptyibuf;
108940242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
109038904Sborman 			}
10916002Sroot 		}
10926002Sroot 
10936002Sroot 		while (pcc > 0) {
10946002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
10956002Sroot 				break;
10966002Sroot 			c = *ptyip++ & 0377, pcc--;
10976002Sroot 			if (c == IAC)
10986002Sroot 				*nfrontp++ = c;
109940242Sborman #if	defined(CRAY2) && defined(UNICOS5)
110038904Sborman 			else if (c == '\n' &&
110144363Sborman 				     my_state_is_wont(TELOPT_BINARY) && newmap)
110238904Sborman 				*nfrontp++ = '\r';
110340242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
11046002Sroot 			*nfrontp++ = c;
110544363Sborman 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
110627020Sminshall 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
110727020Sminshall 					*nfrontp++ = *ptyip++ & 0377;
110827020Sminshall 					pcc--;
110927020Sminshall 				} else
111027020Sminshall 					*nfrontp++ = '\0';
111127020Sminshall 			}
11126002Sroot 		}
111340242Sborman #if	defined(CRAY2) && defined(UNICOS5)
111439531Sborman 		/*
111539531Sborman 		 * If chars were left over from the terminal driver,
111639531Sborman 		 * note their existence.
111739531Sborman 		 */
1118*46809Sdab 		if (!uselinemode && unpcc) {
111939531Sborman 			pcc = unpcc;
112039531Sborman 			unpcc = 0;
112139531Sborman 			ptyip = unptyip;
112239531Sborman 		}
112340242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
112439531Sborman 
112527185Sminshall 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
11266002Sroot 			netflush();
11276002Sroot 		if (ncc > 0)
11286002Sroot 			telrcv();
112927185Sminshall 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
11306002Sroot 			ptyflush();
11316002Sroot 	}
1132*46809Sdab 	cleanup(0);
113338904Sborman }  /* end of telnet */
11346002Sroot 
113538904Sborman #ifndef	TCSIG
113638904Sborman # ifdef	TIOCSIG
113738904Sborman #  define TCSIG TIOCSIG
113838904Sborman # endif
113938904Sborman #endif
11406002Sroot 
114137212Sminshall /*
11426002Sroot  * Send interrupt to process on other side of pty.
11436002Sroot  * If it is in raw mode, just write NULL;
11446002Sroot  * otherwise, write intr char.
11456002Sroot  */
1146*46809Sdab 	void
11476002Sroot interrupt()
11486002Sroot {
114938904Sborman 	ptyflush();	/* half-hearted */
11506002Sroot 
115138904Sborman #ifdef	TCSIG
115238904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
115338904Sborman #else	/* TCSIG */
115438904Sborman 	init_termbuf();
115540242Sborman 	*pfrontp++ = slctab[SLC_IP].sptr ?
115640242Sborman 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
115738904Sborman #endif	/* TCSIG */
11586002Sroot }
11596002Sroot 
116027229Sminshall /*
116127229Sminshall  * Send quit to process on other side of pty.
116227229Sminshall  * If it is in raw mode, just write NULL;
116327229Sminshall  * otherwise, write quit char.
116427229Sminshall  */
1165*46809Sdab 	void
116627229Sminshall sendbrk()
116727229Sminshall {
116827229Sminshall 	ptyflush();	/* half-hearted */
116938904Sborman #ifdef	TCSIG
117038904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
117138904Sborman #else	/* TCSIG */
117238904Sborman 	init_termbuf();
117340242Sborman 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
117440242Sborman 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
117538904Sborman #endif	/* TCSIG */
117627229Sminshall }
117727229Sminshall 
1178*46809Sdab 	void
117938904Sborman sendsusp()
11806002Sroot {
118138904Sborman #ifdef	SIGTSTP
118238904Sborman 	ptyflush();	/* half-hearted */
118338904Sborman # ifdef	TCSIG
118438904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
118538904Sborman # else	/* TCSIG */
118640242Sborman 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
118740242Sborman 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
118838904Sborman # endif	/* TCSIG */
118938904Sborman #endif	/* SIGTSTP */
11906002Sroot }
11916002Sroot 
119245234Sborman /*
119345234Sborman  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
119445234Sborman  * just send back "[Yes]".
119545234Sborman  */
1196*46809Sdab 	void
119745234Sborman recv_ayt()
119845234Sborman {
119945234Sborman #if	defined(SIGINFO) && defined(TCSIG)
120045234Sborman 	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
120145234Sborman 		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
120245234Sborman 		return;
120345234Sborman 	}
120445234Sborman #endif
120545234Sborman 	(void) strcpy(nfrontp, "\r\n[Yes]\r\n");
120645234Sborman 	nfrontp += 9;
120745234Sborman }
120845234Sborman 
1209*46809Sdab 	void
121038904Sborman doeof()
12116002Sroot {
121238904Sborman 	init_termbuf();
12136002Sroot 
121445234Sborman #if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
121540242Sborman 	if (!tty_isediting()) {
1216*46809Sdab 		extern char oldeofc;
121740242Sborman 		*pfrontp++ = oldeofc;
121840242Sborman 		return;
121940242Sborman 	}
122040242Sborman #endif
122140242Sborman 	*pfrontp++ = slctab[SLC_EOF].sptr ?
122240242Sborman 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
12236002Sroot }
1224