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