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