xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 44545)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)telnetd.c	5.46 (Berkeley) 06/28/90";
16 #endif /* not lint */
17 
18 #include "telnetd.h"
19 
20 /*
21  * I/O data buffers,
22  * pointers, and counters.
23  */
24 char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
25 char	ptyibuf2[BUFSIZ];
26 
27 #ifdef	CRAY
28 int	hostinfo = 1;			/* do we print login banner? */
29 #endif
30 
31 #ifdef	CRAY
32 extern int      newmap; /* nonzero if \n maps to ^M^J */
33 int	lowpty = 0, highpty;	/* low, high pty numbers */
34 #endif /* CRAY */
35 
36 int debug = 0;
37 char *progname;
38 
39 #if	defined(NEED_GETTOS)
40 struct tosent {
41 	char	*t_name;	/* name */
42 	char	**t_aliases;	/* alias list */
43 	char	*t_proto;	/* protocol */
44 	int	t_tos;		/* Type Of Service bits */
45 };
46 
47 struct tosent *
48 gettosbyname(name, proto)
49 char *name, *proto;
50 {
51 	static struct tosent te;
52 	static char *aliasp = 0;
53 
54 	te.t_name = name;
55 	te.t_aliases = &aliasp;
56 	te.t_proto = proto;
57 	te.t_tos = 020;	/* Low Delay bit */
58 	return(&te);
59 }
60 #endif
61 
62 main(argc, argv)
63 	char *argv[];
64 {
65 	struct sockaddr_in from;
66 	int on = 1, fromlen;
67 #if	defined(HAS_IP_TOS) || defined(NEED_GETTOS)
68 	struct tosent *tp;
69 #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
70 
71 	pfrontp = pbackp = ptyobuf;
72 	netip = netibuf;
73 	nfrontp = nbackp = netobuf;
74 
75 	progname = *argv;
76 
77 #ifdef CRAY
78 	/*
79 	 * Get number of pty's before trying to process options,
80 	 * which may include changing pty range.
81 	 */
82 	highpty = getnpty();
83 #endif /* CRAY */
84 
85 top:
86 	argc--, argv++;
87 
88 	if (argc > 0 && strcmp(*argv, "-debug") == 0) {
89 		debug++;
90 		goto top;
91 	}
92 
93 #ifdef	LINEMODE
94 	if (argc > 0 && !strcmp(*argv, "-l")) {
95 		alwayslinemode = 1;
96 		goto top;
97 	}
98 #endif	/* LINEMODE */
99 
100 #ifdef CRAY
101 	if (argc > 0 && !strcmp(*argv, "-h")) {
102 		hostinfo = 0;
103 		goto top;
104 	}
105 
106 	if (argc > 0 && !strncmp(*argv, "-r", 2)) {
107 		char *strchr();
108 		char *c;
109 
110 		/*
111 		 * Allow the specification of alterations to the pty search
112 		 * range.  It is legal to specify only one, and not change the
113 		 * other from its default.
114 		 */
115 		*argv += 2;
116 		if (**argv == '\0' && argc)
117 			argv++, argc--;
118 		c = strchr(*argv, '-');
119 		if (c) {
120 			*c++ = '\0';
121 			highpty = atoi(c);
122 		}
123 		if (**argv != '\0')
124 			lowpty = atoi(*argv);
125 		if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
126 			usage();
127 			/* NOT REACHED */
128 		}
129 		goto top;
130 	}
131 # ifdef	NEWINIT
132 	if (argc > 0 && !strncmp(*argv, "-I", 2)) {
133 		extern char *gen_id;
134 
135 		*argv += 2;
136 		if (**argv == '\0') {
137 			if (argc < 2) {
138 				usage();
139 				/* NOT REACHED */
140 			}
141 			argv++, argc--;
142 			if (**argv == '\0') {
143 				usage();
144 				/* NOT REACHED */
145 			}
146 		}
147 		gen_id = *argv;
148 		goto top;
149 	}
150 # endif	/* NEWINIT */
151 #endif	/* CRAY */
152 
153 #ifdef DIAGNOSTICS
154 	/*
155 	 * Check for desired diagnostics capabilities.
156 	 */
157 	if (argc > 0 && !strncmp(*argv, "-D", 2)) {
158 		*argv += 2;
159 		if (**argv == '\0') {
160 			if (argc < 2) {
161 				usage();
162 				/* NOT REACHED */
163 			}
164 			argv++, argc--;
165 			if (**argv == '\0') {
166 				usage();
167 				/* NOT REACHED */
168 			}
169 		}
170 		if (!strcmp(*argv, "report")) {
171 			diagnostic |= TD_REPORT|TD_OPTIONS;
172 		} else if (!strcmp(*argv, "exercise")) {
173 			diagnostic |= TD_EXERCISE;
174 		} else if (!strcmp(*argv, "netdata")) {
175 			diagnostic |= TD_NETDATA;
176 		} else if (!strcmp(*argv, "ptydata")) {
177 			diagnostic |= TD_PTYDATA;
178 		} else if (!strcmp(*argv, "options")) {
179 			diagnostic |= TD_OPTIONS;
180 		} else {
181 			usage();
182 			/* NOT REACHED */
183 		}
184 		goto top;
185 	}
186 #endif /* DIAGNOSTICS */
187 
188 #ifdef BFTPDAEMON
189 	/*
190 	 * Check for bftp daemon
191 	 */
192 	if (argc > 0 && !strncmp(*argv, "-B", 2)) {
193 		bftpd++;
194 		goto top;
195 	}
196 #endif /* BFTPDAEMON */
197 
198 	if (argc > 0 && **argv == '-') {
199 		fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
200 		usage();
201 		/* NOT REACHED */
202 	}
203 
204 	if (debug) {
205 	    int s, ns, foo;
206 	    struct servent *sp;
207 	    static struct sockaddr_in sin = { AF_INET };
208 
209 	    if (argc > 1) {
210 		usage();
211 		/* NOT REACHED */
212 	    } else if (argc == 1) {
213 		    if (sp = getservbyname(*argv, "tcp")) {
214 			sin.sin_port = sp->s_port;
215 		    } else {
216 			sin.sin_port = atoi(*argv);
217 			if ((int)sin.sin_port <= 0) {
218 			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
219 			    usage();
220 			    /* NOT REACHED */
221 			}
222 			sin.sin_port = htons((u_short)sin.sin_port);
223 		   }
224 	    } else {
225 		sp = getservbyname("telnet", "tcp");
226 		if (sp == 0) {
227 		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
228 		    exit(1);
229 		}
230 		sin.sin_port = sp->s_port;
231 	    }
232 
233 	    s = socket(AF_INET, SOCK_STREAM, 0);
234 	    if (s < 0) {
235 		    perror("telnetd: socket");;
236 		    exit(1);
237 	    }
238 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
239 	    if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
240 		perror("bind");
241 		exit(1);
242 	    }
243 	    if (listen(s, 1) < 0) {
244 		perror("listen");
245 		exit(1);
246 	    }
247 	    foo = sizeof sin;
248 	    ns = accept(s, (struct sockaddr *)&sin, &foo);
249 	    if (ns < 0) {
250 		perror("accept");
251 		exit(1);
252 	    }
253 	    (void) dup2(ns, 0);
254 	    (void) close(ns);
255 	    (void) close(s);
256 	} else if (argc > 0) {
257 		usage();
258 		/* NOT REACHED */
259 	}
260 
261 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
262 	fromlen = sizeof (from);
263 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
264 		fprintf(stderr, "%s: ", progname);
265 		perror("getpeername");
266 		_exit(1);
267 	}
268 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
269 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
270 	}
271 
272 #if	defined(HAS_IP_TOS) || defined(NEED_GETTOS)
273 	if ((tp = gettosbyname("telnet", "tcp")) &&
274 	    (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
275 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
276 #endif	/* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
277 	net = 0;
278 	doit(&from);
279 	/* NOTREACHED */
280 }  /* end of main */
281 
282 usage()
283 {
284 	fprintf(stderr, "Usage: telnetd [-debug] [-h]");
285 #ifdef	NEWINIT
286 	fprintf(stderr, " [-Iinitid]");
287 #endif	/* NEWINIT */
288 #ifdef DIAGNOSTICS
289 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
290 #endif /* DIAGNOSTICS */
291 #ifdef LINEMODE
292 	fprintf(stderr, " [-l]");
293 #endif
294 #ifdef	CRAY
295 	fprintf(stderr, " [-r[lowpty]-[highpty]]");
296 #endif
297 #ifdef BFTPDAEMON
298 	fprintf(stderr, " [-B]");
299 #endif /* BFTPDAEMON */
300 	fprintf(stderr, " [port]\n");
301 	exit(1);
302 }
303 
304 void	cleanup();
305 
306 /*
307  * getterminaltype
308  *
309  *	Ask the other end to send along its terminal type and speed.
310  * Output is the variable terminaltype filled in.
311  */
312 static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
313 void
314 getterminaltype()
315 {
316     void ttloop();
317 
318     settimer(baseline);
319     send_do(TELOPT_TTYPE, 1);
320     send_do(TELOPT_TSPEED, 1);
321     send_do(TELOPT_XDISPLOC, 1);
322     send_do(TELOPT_ENVIRON, 1);
323     while (his_will_wont_is_changing(TELOPT_TTYPE) ||
324 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
325 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
326 	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
327 	ttloop();
328     }
329     if (his_state_is_will(TELOPT_TSPEED)) {
330 	static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
331 
332 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
333 	nfrontp += sizeof sbbuf;
334     }
335     if (his_state_is_will(TELOPT_XDISPLOC)) {
336 	static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
337 
338 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
339 	nfrontp += sizeof sbbuf;
340     }
341     if (his_state_is_will(TELOPT_ENVIRON)) {
342 	static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
343 
344 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
345 	nfrontp += sizeof sbbuf;
346     }
347     if (his_state_is_will(TELOPT_TTYPE)) {
348 
349 	bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
350 	nfrontp += sizeof ttytype_sbbuf;
351     }
352     if (his_state_is_will(TELOPT_TSPEED)) {
353 	while (sequenceIs(tspeedsubopt, baseline))
354 	    ttloop();
355     }
356     if (his_state_is_will(TELOPT_XDISPLOC)) {
357 	while (sequenceIs(xdisplocsubopt, baseline))
358 	    ttloop();
359     }
360     if (his_state_is_will(TELOPT_ENVIRON)) {
361 	while (sequenceIs(environsubopt, baseline))
362 	    ttloop();
363     }
364     if (his_state_is_will(TELOPT_TTYPE)) {
365 	char first[256], last[256];
366 
367 	while (sequenceIs(ttypesubopt, baseline))
368 	    ttloop();
369 
370 	/*
371 	 * If the other side has already disabled the option, then
372 	 * we have to just go with what we (might) have already gotten.
373 	 */
374 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
375 	    (void) strncpy(first, terminaltype, sizeof(first));
376 	    for(;;) {
377 		/*
378 		 * Save the unknown name, and request the next name.
379 		 */
380 		(void) strncpy(last, terminaltype, sizeof(last));
381 		_gettermname();
382 		if (terminaltypeok(terminaltype))
383 		    break;
384 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
385 		    his_state_is_wont(TELOPT_TTYPE)) {
386 		    /*
387 		     * We've hit the end.  If this is the same as
388 		     * the first name, just go with it.
389 		     */
390 		    if (strncmp(first, terminaltype, sizeof(first) == 0))
391 			break;
392 		    /*
393 		     * Get the terminal name one more time, so that
394 		     * RFC1091 compliant telnets will cycle back to
395 		     * the start of the list.
396 		     */
397 		     _gettermname();
398 		    if (strncmp(first, terminaltype, sizeof(first) != 0))
399 			(void) strncpy(terminaltype, first, sizeof(first));
400 		    break;
401 		}
402 	    }
403 	}
404     }
405 }  /* end of getterminaltype */
406 
407 _gettermname()
408 {
409     /*
410      * If the client turned off the option,
411      * we can't send another request, so we
412      * just return.
413      */
414     if (his_state_is_wont(TELOPT_TTYPE))
415 	return;
416     settimer(baseline);
417     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
418     nfrontp += sizeof ttytype_sbbuf;
419     while (sequenceIs(ttypesubopt, baseline))
420 	ttloop();
421 }
422 
423 terminaltypeok(s)
424 char *s;
425 {
426     char buf[1024];
427 
428     if (terminaltype == NULL)
429 	return(1);
430 
431     /*
432      * tgetent() will return 1 if the type is known, and
433      * 0 if it is not known.  If it returns -1, it couldn't
434      * open the database.  But if we can't open the database,
435      * it won't help to say we failed, because we won't be
436      * able to verify anything else.  So, we treat -1 like 1.
437      */
438     if (tgetent(buf, s) == 0)
439 	return(0);
440     return(1);
441 }
442 
443 /*
444  * Get a pty, scan input lines.
445  */
446 doit(who)
447 	struct sockaddr_in *who;
448 {
449 	char *host, *inet_ntoa();
450 	int t;
451 	struct hostent *hp;
452 #if BSD > 43
453 	extern char *line;
454 
455 	if (openpty(&pty, &t, line, NULL, NULL) == -1)
456 		fatal(net, "All network ports in use");
457 	init_termbuf();
458 #else
459 
460 	/*
461 	 * Find an available pty to use.
462 	 */
463 	pty = getpty();
464 	if (pty < 0)
465 		fatal(net, "All network ports in use");
466 
467 	t = getptyslave();
468 #endif
469 
470 	/* get name of connected client */
471 	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
472 		who->sin_family);
473 	if (hp)
474 		host = hp->h_name;
475 	else
476 		host = inet_ntoa(who->sin_addr);
477 
478 	init_env();
479 	/*
480 	 * get terminal type.
481 	 */
482 	getterminaltype();
483 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
484 
485 	/*
486 	 * Start up the login process on the slave side of the terminal
487 	 */
488 	startslave(t, host);
489 
490 	telnet(net, pty);  /* begin server processing */
491 	/*NOTREACHED*/
492 }  /* end of doit */
493 
494 #ifndef	MAXHOSTNAMELEN
495 #define	MAXHOSTNAMELEN 64
496 #endif	MAXHOSTNAMELEN
497 /*
498  * Main loop.  Select from pty and network, and
499  * hand data to telnet receiver finite state machine.
500  */
501 telnet(f, p)
502 int f, p;
503 {
504 	int on = 1;
505 	char hostname[MAXHOSTNAMELEN];
506 #if	defined(CRAY2) && defined(UNICOS5)
507 	int termstat();
508 	int interrupt(), sendbrk();
509 #endif
510 #define	TABBUFSIZ	512
511 	char	defent[TABBUFSIZ];
512 	char	defstrs[TABBUFSIZ];
513 #undef	TABBUFSIZ
514 	char *HE;
515 	char *HN;
516 	char *IM;
517 	void netflush();
518 
519 	/*
520 	 * Initialize the slc mapping table.
521 	 */
522 	get_slc_defaults();
523 
524 	/*
525 	 * Do some tests where it is desireable to wait for a response.
526 	 * Rather than doing them slowly, one at a time, do them all
527 	 * at once.
528 	 */
529 	if (my_state_is_wont(TELOPT_SGA))
530 		send_will(TELOPT_SGA, 1);
531 	/*
532 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
533 	 * because 4.2 clients are unable to deal with TCP urgent data.
534 	 *
535 	 * To find out, we send out a "DO ECHO".  If the remote system
536 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
537 	 * that fact ("WILL ECHO" ==> that the client will echo what
538 	 * WE, the server, sends it; it does NOT mean that the client will
539 	 * echo the terminal input).
540 	 */
541 	send_do(TELOPT_ECHO, 1);
542 
543 #ifdef	LINEMODE
544 	if (his_state_is_wont(TELOPT_LINEMODE)) {
545 		/* Query the peer for linemode support by trying to negotiate
546 		 * the linemode option.
547 		 */
548 		linemode = 0;
549 		editmode = 0;
550 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
551 	}
552 #endif	/* LINEMODE */
553 
554 	/*
555 	 * Send along a couple of other options that we wish to negotiate.
556 	 */
557 	send_do(TELOPT_NAWS, 1);
558 	send_will(TELOPT_STATUS, 1);
559 	flowmode = 1;  /* default flow control state */
560 	send_do(TELOPT_LFLOW, 1);
561 
562 	/*
563 	 * Spin, waiting for a response from the DO ECHO.  However,
564 	 * some REALLY DUMB telnets out there might not respond
565 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
566 	 * telnets so far seem to respond with WONT for a DO that
567 	 * they don't understand...) because by the time we get the
568 	 * response, it will already have processed the DO ECHO.
569 	 * Kludge upon kludge.
570 	 */
571 	while (his_will_wont_is_changing(TELOPT_NAWS))
572 		ttloop();
573 
574 	/*
575 	 * But...
576 	 * The client might have sent a WILL NAWS as part of its
577 	 * startup code; if so, we'll be here before we get the
578 	 * response to the DO ECHO.  We'll make the assumption
579 	 * that any implementation that understands about NAWS
580 	 * is a modern enough implementation that it will respond
581 	 * to our DO ECHO request; hence we'll do another spin
582 	 * waiting for the ECHO option to settle down, which is
583 	 * what we wanted to do in the first place...
584 	 */
585 	if (his_want_state_is_will(TELOPT_ECHO) &&
586 	    his_state_is_will(TELOPT_NAWS)) {
587 		while (his_will_wont_is_changing(TELOPT_ECHO))
588 			ttloop();
589 	}
590 	/*
591 	 * On the off chance that the telnet client is broken and does not
592 	 * respond to the DO ECHO we sent, (after all, we did send the
593 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
594 	 * until a response to the DO NAWS comes back) simulate the
595 	 * receipt of a will echo.  This will also send a WONT ECHO
596 	 * to the client, since we assume that the client failed to
597 	 * respond because it believes that it is already in DO ECHO
598 	 * mode, which we do not want.
599 	 */
600 	if (his_want_state_is_will(TELOPT_ECHO)) {
601 #ifdef DIAGNOSTICS
602 		if (diagnostic & TD_OPTIONS) {
603 			sprintf(nfrontp, "td: simulating recv\r\n");
604 			nfrontp += strlen(nfrontp);
605 		}
606 #endif /* DIAGNOSTICS */
607 		willoption(TELOPT_ECHO);
608 	}
609 
610 	/*
611 	 * Finally, to clean things up, we turn on our echo.  This
612 	 * will break stupid 4.2 telnets out of local terminal echo.
613 	 */
614 
615 	if (my_state_is_wont(TELOPT_ECHO))
616 		send_will(TELOPT_ECHO, 1);
617 
618 	/*
619 	 * Turn on packet mode, and default to line at at time mode.
620 	 */
621 	(void) ioctl(p, TIOCPKT, (char *)&on);
622 #ifdef	LINEMODE
623 	tty_setlinemode(1);
624 
625 # ifdef	KLUDGELINEMODE
626 	/*
627 	 * Continuing line mode support.  If client does not support
628 	 * real linemode, attempt to negotiate kludge linemode by sending
629 	 * the do timing mark sequence.
630 	 */
631 	if (lmodetype < REAL_LINEMODE)
632 		send_do(TELOPT_TM, 1);
633 # endif	/* KLUDGELINEMODE */
634 #endif	/* LINEMODE */
635 
636 	/*
637 	 * Call telrcv() once to pick up anything received during
638 	 * terminal type negotiation, 4.2/4.3 determination, and
639 	 * linemode negotiation.
640 	 */
641 	telrcv();
642 
643 	(void) ioctl(f, FIONBIO, (char *)&on);
644 	(void) ioctl(p, FIONBIO, (char *)&on);
645 #if	defined(CRAY2) && defined(UNICOS5)
646 	init_termdriver(f, p, interrupt, sendbrk);
647 #endif
648 
649 #if	defined(SO_OOBINLINE)
650 	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
651 #endif	/* defined(SO_OOBINLINE) */
652 
653 #ifdef	SIGTSTP
654 	(void) signal(SIGTSTP, SIG_IGN);
655 #endif
656 #ifdef	SIGTTOU
657 	/*
658 	 * Ignoring SIGTTOU keeps the kernel from blocking us
659 	 * in ttioct() in /sys/tty.c.
660 	 */
661 	(void) signal(SIGTTOU, SIG_IGN);
662 #endif
663 
664 	(void) signal(SIGCHLD, cleanup);
665 
666 #if	defined(CRAY2) && defined(UNICOS5)
667 	/*
668 	 * Cray-2 will send a signal when pty modes are changed by slave
669 	 * side.  Set up signal handler now.
670 	 */
671 	if ((int)signal(SIGUSR1, termstat) < 0)
672 		perror("signal");
673 	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
674 		perror("ioctl:TCSIGME");
675 	/*
676 	 * Make processing loop check terminal characteristics early on.
677 	 */
678 	termstat();
679 #endif
680 
681 #ifdef	NO_SETSID
682 	(void) setpgrp(0, 0);
683 #else
684 	(void) setsid();
685 #endif
686 #if	defined(TIOCSCTTY) && defined(CRAY)
687 	ioctl(p, TIOCSCTTY, 0);
688 #endif
689 
690 	/*
691 	 * Show banner that getty never gave.
692 	 *
693 	 * We put the banner in the pty input buffer.  This way, it
694 	 * gets carriage return null processing, etc., just like all
695 	 * other pty --> client data.
696 	 */
697 
698 	(void) gethostname(hostname, sizeof (hostname));
699 
700 	if (getent(defent, "default") == 1) {
701 		char *getstr();
702 		char *cp=defstrs;
703 
704 		HE = getstr("he", &cp);
705 		HN = getstr("hn", &cp);
706 		IM = getstr("im", &cp);
707 		if (HN && *HN)
708 			(void) strcpy(hostname, HN);
709 		if (IM == 0)
710 			IM = "";
711 	} else {
712 #ifdef	CRAY
713 		if (hostinfo == 0)
714 			IM = 0;
715 		else
716 #endif
717 			IM = DEFAULT_IM;
718 		HE = 0;
719 	}
720 	edithost(HE, hostname);
721 	if (IM && *IM)
722 		putf(IM, ptyibuf2);
723 
724 	if (pcc)
725 		(void) strncat(ptyibuf2, ptyip, pcc+1);
726 	ptyip = ptyibuf2;
727 	pcc = strlen(ptyip);
728 #ifdef	LINEMODE
729 	/*
730 	 * Last check to make sure all our states are correct.
731 	 */
732 	init_termbuf();
733 	localstat();
734 #endif	/* LINEMODE */
735 
736 #ifdef DIAGNOSTICS
737 	if (diagnostic & TD_REPORT) {
738 		sprintf(nfrontp, "td: Entering processing loop\r\n");
739 		nfrontp += strlen(nfrontp);
740 	}
741 #endif /* DIAGNOSTICS */
742 
743 	for (;;) {
744 		fd_set ibits, obits, xbits;
745 		register int c;
746 
747 		if (ncc < 0 && pcc < 0)
748 			break;
749 
750 #if	defined(CRAY2) && defined(UNICOS5)
751 		if (needtermstat)
752 			_termstat();
753 #endif	/* defined(CRAY2) && defined(UNICOS5) */
754 		FD_ZERO(&ibits);
755 		FD_ZERO(&obits);
756 		FD_ZERO(&xbits);
757 		/*
758 		 * Never look for input if there's still
759 		 * stuff in the corresponding output buffer
760 		 */
761 		if (nfrontp - nbackp || pcc > 0) {
762 			FD_SET(f, &obits);
763 		} else {
764 			FD_SET(p, &ibits);
765 		}
766 		if (pfrontp - pbackp || ncc > 0) {
767 			FD_SET(p, &obits);
768 		} else {
769 			FD_SET(f, &ibits);
770 		}
771 		if (!SYNCHing) {
772 			FD_SET(f, &xbits);
773 		}
774 		if ((c = select(16, &ibits, &obits, &xbits,
775 						(struct timeval *)0)) < 1) {
776 			if (c == -1) {
777 				if (errno == EINTR) {
778 					continue;
779 				}
780 			}
781 			sleep(5);
782 			continue;
783 		}
784 
785 		/*
786 		 * Any urgent data?
787 		 */
788 		if (FD_ISSET(net, &xbits)) {
789 		    SYNCHing = 1;
790 		}
791 
792 		/*
793 		 * Something to read from the network...
794 		 */
795 		if (FD_ISSET(net, &ibits)) {
796 #if	!defined(SO_OOBINLINE)
797 			/*
798 			 * In 4.2 (and 4.3 beta) systems, the
799 			 * OOB indication and data handling in the kernel
800 			 * is such that if two separate TCP Urgent requests
801 			 * come in, one byte of TCP data will be overlaid.
802 			 * This is fatal for Telnet, but we try to live
803 			 * with it.
804 			 *
805 			 * In addition, in 4.2 (and...), a special protocol
806 			 * is needed to pick up the TCP Urgent data in
807 			 * the correct sequence.
808 			 *
809 			 * What we do is:  if we think we are in urgent
810 			 * mode, we look to see if we are "at the mark".
811 			 * If we are, we do an OOB receive.  If we run
812 			 * this twice, we will do the OOB receive twice,
813 			 * but the second will fail, since the second
814 			 * time we were "at the mark", but there wasn't
815 			 * any data there (the kernel doesn't reset
816 			 * "at the mark" until we do a normal read).
817 			 * Once we've read the OOB data, we go ahead
818 			 * and do normal reads.
819 			 *
820 			 * There is also another problem, which is that
821 			 * since the OOB byte we read doesn't put us
822 			 * out of OOB state, and since that byte is most
823 			 * likely the TELNET DM (data mark), we would
824 			 * stay in the TELNET SYNCH (SYNCHing) state.
825 			 * So, clocks to the rescue.  If we've "just"
826 			 * received a DM, then we test for the
827 			 * presence of OOB data when the receive OOB
828 			 * fails (and AFTER we did the normal mode read
829 			 * to clear "at the mark").
830 			 */
831 		    if (SYNCHing) {
832 			int atmark;
833 
834 			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
835 			if (atmark) {
836 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
837 			    if ((ncc == -1) && (errno == EINVAL)) {
838 				ncc = read(net, netibuf, sizeof (netibuf));
839 				if (sequenceIs(didnetreceive, gotDM)) {
840 				    SYNCHing = stilloob(net);
841 				}
842 			    }
843 			} else {
844 			    ncc = read(net, netibuf, sizeof (netibuf));
845 			}
846 		    } else {
847 			ncc = read(net, netibuf, sizeof (netibuf));
848 		    }
849 		    settimer(didnetreceive);
850 #else	/* !defined(SO_OOBINLINE)) */
851 		    ncc = read(net, netibuf, sizeof (netibuf));
852 #endif	/* !defined(SO_OOBINLINE)) */
853 		    if (ncc < 0 && errno == EWOULDBLOCK)
854 			ncc = 0;
855 		    else {
856 			if (ncc <= 0) {
857 			    break;
858 			}
859 			netip = netibuf;
860 		    }
861 #ifdef DIAGNOSTICS
862 		    if (diagnostic & (TD_REPORT | TD_NETDATA)) {
863 			    sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
864 			    nfrontp += strlen(nfrontp);
865 		    }
866 		    if (diagnostic & TD_NETDATA) {
867 			    printdata("nd", netip, ncc);
868 		    }
869 #endif /* DIAGNOSTICS */
870 		}
871 
872 		/*
873 		 * Something to read from the pty...
874 		 */
875 		if (FD_ISSET(p, &ibits)) {
876 			pcc = read(p, ptyibuf, BUFSIZ);
877 			if (pcc < 0 && errno == EWOULDBLOCK)
878 				pcc = 0;
879 			else {
880 				if (pcc <= 0)
881 					break;
882 #if	!defined(CRAY2) || !defined(UNICOS5)
883 #ifdef	LINEMODE
884 				/*
885 				 * If ioctl from pty, pass it through net
886 				 */
887 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
888 					copy_termbuf(ptyibuf+1, pcc-1);
889 					localstat();
890 					pcc = 1;
891 				}
892 #endif	LINEMODE
893 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
894 					netclear();	/* clear buffer back */
895 #ifdef	notdef
896 					/*
897 					 * We really should have this in, but
898 					 * there are client telnets on some
899 					 * operating systems get screwed up
900 					 * royally if we send them urgent
901 					 * mode data.  So, for now, we'll not
902 					 * do this...
903 					 */
904 					*nfrontp++ = IAC;
905 					*nfrontp++ = DM;
906 					neturg = nfrontp-1; /* off by one XXX */
907 #endif
908 				}
909 				if (his_state_is_will(TELOPT_LFLOW) &&
910 				    (ptyibuf[0] &
911 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
912 					(void) sprintf(nfrontp, "%c%c%c%c%c%c",
913 					    IAC, SB, TELOPT_LFLOW,
914 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
915 					    IAC, SE);
916 					nfrontp += 6;
917 				}
918 				pcc--;
919 				ptyip = ptyibuf+1;
920 #else	/* defined(CRAY2) && defined(UNICOS5) */
921 				if (!uselinemode) {
922 					unpcc = pcc;
923 					unptyip = ptyibuf;
924 					pcc = term_output(&unptyip, ptyibuf2,
925 								&unpcc, BUFSIZ);
926 					ptyip = ptyibuf2;
927 				} else
928 					ptyip = ptyibuf;
929 #endif	/* defined(CRAY2) && defined(UNICOS5) */
930 			}
931 		}
932 
933 		while (pcc > 0) {
934 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
935 				break;
936 			c = *ptyip++ & 0377, pcc--;
937 			if (c == IAC)
938 				*nfrontp++ = c;
939 #if	defined(CRAY2) && defined(UNICOS5)
940 			else if (c == '\n' &&
941 				     my_state_is_wont(TELOPT_BINARY) && newmap)
942 				*nfrontp++ = '\r';
943 #endif	/* defined(CRAY2) && defined(UNICOS5) */
944 			*nfrontp++ = c;
945 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
946 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
947 					*nfrontp++ = *ptyip++ & 0377;
948 					pcc--;
949 				} else
950 					*nfrontp++ = '\0';
951 			}
952 		}
953 #if	defined(CRAY2) && defined(UNICOS5)
954 		/*
955 		 * If chars were left over from the terminal driver,
956 		 * note their existence.
957 		 */
958 		 if (!uselinemode && unpcc) {
959 			pcc = unpcc;
960 			unpcc = 0;
961 			ptyip = unptyip;
962 		}
963 #endif	/* defined(CRAY2) && defined(UNICOS5) */
964 
965 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
966 			netflush();
967 		if (ncc > 0)
968 			telrcv();
969 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
970 			ptyflush();
971 	}
972 	cleanup();
973 }  /* end of telnet */
974 
975 #ifndef	TCSIG
976 # ifdef	TIOCSIG
977 #  define TCSIG TIOCSIG
978 # endif
979 #endif
980 
981 /*
982  * Send interrupt to process on other side of pty.
983  * If it is in raw mode, just write NULL;
984  * otherwise, write intr char.
985  */
986 interrupt()
987 {
988 	ptyflush();	/* half-hearted */
989 
990 #ifdef	TCSIG
991 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
992 #else	/* TCSIG */
993 	init_termbuf();
994 	*pfrontp++ = slctab[SLC_IP].sptr ?
995 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
996 #endif	/* TCSIG */
997 }
998 
999 /*
1000  * Send quit to process on other side of pty.
1001  * If it is in raw mode, just write NULL;
1002  * otherwise, write quit char.
1003  */
1004 sendbrk()
1005 {
1006 	ptyflush();	/* half-hearted */
1007 #ifdef	TCSIG
1008 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1009 #else	/* TCSIG */
1010 	init_termbuf();
1011 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
1012 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1013 #endif	/* TCSIG */
1014 }
1015 
1016 sendsusp()
1017 {
1018 #ifdef	SIGTSTP
1019 	ptyflush();	/* half-hearted */
1020 # ifdef	TCSIG
1021 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1022 # else	/* TCSIG */
1023 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
1024 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1025 # endif	/* TCSIG */
1026 #endif	/* SIGTSTP */
1027 }
1028 
1029 doeof()
1030 {
1031 #if	defined(USE_TERMIO) && defined(SYSV_TERMIO)
1032 	extern char oldeofc;
1033 #endif
1034 	init_termbuf();
1035 
1036 #if	defined(USE_TERMIO) && defined(SYSV_TERMIO)
1037 	if (!tty_isediting()) {
1038 		*pfrontp++ = oldeofc;
1039 		return;
1040 	}
1041 #endif
1042 	*pfrontp++ = slctab[SLC_EOF].sptr ?
1043 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
1044 }
1045