xref: /dragonfly/libexec/telnetd/telnetd.c (revision 984263bc)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 
36 __FBSDID("$FreeBSD: src/libexec/telnetd/telnetd.c,v 1.22.2.8 2002/04/13 11:07:12 markm Exp $");
37 
38 #ifndef lint
39 static const char sccsid[] = "@(#)telnetd.c	8.4 (Berkeley) 5/30/95";
40 #endif
41 
42 #include "telnetd.h"
43 #include "pathnames.h"
44 
45 #include <sys/mman.h>
46 #include <err.h>
47 #include <libutil.h>
48 #include <paths.h>
49 #include <termcap.h>
50 #include <utmp.h>
51 
52 #include <arpa/inet.h>
53 
54 #include <libtelnet/misc.h>
55 
56 char	remote_hostname[MAXHOSTNAMELEN];
57 size_t	utmp_len = sizeof(remote_hostname) - 1;
58 int	registerd_host_only = 0;
59 
60 
61 /*
62  * I/O data buffers,
63  * pointers, and counters.
64  */
65 char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
66 char	ptyibuf2[BUFSIZ];
67 
68 int readstream(int, char *, int);
69 void doit(struct sockaddr *);
70 int terminaltypeok(char *);
71 
72 int	hostinfo = 1;			/* do we print login banner? */
73 
74 int debug = 0;
75 int keepalive = 1;
76 const char *altlogin;
77 
78 void doit(struct sockaddr *);
79 int terminaltypeok(char *);
80 void startslave(char *, int, char *);
81 extern void usage(void);
82 static void _gettermname(void);
83 
84 /*
85  * The string to pass to getopt().  We do it this way so
86  * that only the actual options that we support will be
87  * passed off to getopt().
88  */
89 char valid_opts[] = {
90 	'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
91 	'4', '6',
92 #ifdef BFTPDAEMON
93 	'B',
94 #endif
95 #ifdef DIAGNOSTICS
96 	'D', ':',
97 #endif
98 #ifdef	LINEMODE
99 	'l',
100 #endif
101 	'\0'
102 };
103 
104 int family = AF_INET;
105 
106 #ifndef	MAXHOSTNAMELEN
107 #define	MAXHOSTNAMELEN 256
108 #endif	/* MAXHOSTNAMELEN */
109 
110 char *hostname;
111 char host_name[MAXHOSTNAMELEN];
112 
113 extern void telnet(int, int, char *);
114 
115 int level;
116 char user_name[256];
117 
118 int
119 main(int argc, char *argv[])
120 {
121 	struct sockaddr_storage from;
122 	int on = 1, fromlen;
123 	int ch;
124 #if	defined(IPPROTO_IP) && defined(IP_TOS)
125 	int tos = -1;
126 #endif
127 
128 	pfrontp = pbackp = ptyobuf;
129 	netip = netibuf;
130 	nfrontp = nbackp = netobuf;
131 
132 	/*
133 	 * This initialization causes linemode to default to a configuration
134 	 * that works on all telnet clients, including the FreeBSD client.
135 	 * This is not quite the same as the telnet client issuing a "mode
136 	 * character" command, but has most of the same benefits, and is
137 	 * preferable since some clients (like usofts) don't have the
138 	 * mode character command anyway and linemode breaks things.
139 	 * The most notable symptom of fix is that csh "set filec" operations
140 	 * like <ESC> (filename completion) and ^D (choices) keys now work
141 	 * in telnet sessions and can be used more than once on the same line.
142 	 * CR/LF handling is also corrected in some termio modes.  This
143 	 * change resolves problem reports bin/771 and bin/1037.
144 	 */
145 
146 	linemode=1;	/*Default to mode that works on bulk of clients*/
147 
148 	while ((ch = getopt(argc, argv, valid_opts)) != -1) {
149 		switch(ch) {
150 
151 
152 #ifdef BFTPDAEMON
153 		case 'B':
154 			bftpd++;
155 			break;
156 #endif /* BFTPDAEMON */
157 
158 		case 'd':
159 			if (strcmp(optarg, "ebug") == 0) {
160 				debug++;
161 				break;
162 			}
163 			usage();
164 			/* NOTREACHED */
165 			break;
166 
167 #ifdef DIAGNOSTICS
168 		case 'D':
169 			/*
170 			 * Check for desired diagnostics capabilities.
171 			 */
172 			if (!strcmp(optarg, "report")) {
173 				diagnostic |= TD_REPORT|TD_OPTIONS;
174 			} else if (!strcmp(optarg, "exercise")) {
175 				diagnostic |= TD_EXERCISE;
176 			} else if (!strcmp(optarg, "netdata")) {
177 				diagnostic |= TD_NETDATA;
178 			} else if (!strcmp(optarg, "ptydata")) {
179 				diagnostic |= TD_PTYDATA;
180 			} else if (!strcmp(optarg, "options")) {
181 				diagnostic |= TD_OPTIONS;
182 			} else {
183 				usage();
184 				/* NOT REACHED */
185 			}
186 			break;
187 #endif /* DIAGNOSTICS */
188 
189 
190 		case 'h':
191 			hostinfo = 0;
192 			break;
193 
194 #ifdef	LINEMODE
195 		case 'l':
196 			alwayslinemode = 1;
197 			break;
198 #endif	/* LINEMODE */
199 
200 		case 'k':
201 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
202 			lmodetype = NO_AUTOKLUDGE;
203 #else
204 			/* ignore -k option if built without kludge linemode */
205 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
206 			break;
207 
208 		case 'n':
209 			keepalive = 0;
210 			break;
211 
212 		case 'p':
213 			altlogin = optarg;
214 			break;
215 
216 		case 'S':
217 #ifdef	HAS_GETTOS
218 			if ((tos = parsetos(optarg, "tcp")) < 0)
219 				warnx("%s%s%s",
220 					"bad TOS argument '", optarg,
221 					"'; will try to use default TOS");
222 #else
223 			warnx("TOS option unavailable; -S flag not supported");
224 #endif
225 			break;
226 
227 		case 'u':
228 			utmp_len = (size_t)atoi(optarg);
229 			if (utmp_len >= sizeof(remote_hostname))
230 				utmp_len = sizeof(remote_hostname) - 1;
231 			break;
232 
233 		case 'U':
234 			registerd_host_only = 1;
235 			break;
236 
237 
238 		case '4':
239 			family = AF_INET;
240 			break;
241 
242 #ifdef INET6
243 		case '6':
244 			family = AF_INET6;
245 			break;
246 #endif
247 
248 		default:
249 			warnx("%c: unknown option", ch);
250 			/* FALLTHROUGH */
251 		case '?':
252 			usage();
253 			/* NOTREACHED */
254 		}
255 	}
256 
257 	argc -= optind;
258 	argv += optind;
259 
260 	if (debug) {
261 	    int s, ns, foo, error;
262 	    const char *service = "telnet";
263 	    struct addrinfo hints, *res;
264 
265 	    if (argc > 1) {
266 		usage();
267 		/* NOT REACHED */
268 	    } else if (argc == 1)
269 		service = *argv;
270 
271 	    memset(&hints, 0, sizeof(hints));
272 	    hints.ai_flags = AI_PASSIVE;
273 	    hints.ai_family = family;
274 	    hints.ai_socktype = SOCK_STREAM;
275 	    hints.ai_protocol = 0;
276 	    error = getaddrinfo(NULL, service, &hints, &res);
277 
278 	    if (error) {
279 		errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
280 		if (error == EAI_SYSTEM)
281 		    errx(1, "tcp/%s: %s\n", service, strerror(errno));
282 		usage();
283 	    }
284 
285 	    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
286 	    if (s < 0)
287 		    err(1, "socket");
288 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
289 				(char *)&on, sizeof(on));
290 	    if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
291 		err(1, "bind");
292 	    if (listen(s, 1) < 0)
293 		err(1, "listen");
294 	    foo = res->ai_addrlen;
295 	    ns = accept(s, res->ai_addr, &foo);
296 	    if (ns < 0)
297 		err(1, "accept");
298 	    (void) dup2(ns, 0);
299 	    (void) close(ns);
300 	    (void) close(s);
301 #ifdef convex
302 	} else if (argc == 1) {
303 		; /* VOID*/		/* Just ignore the host/port name */
304 #endif
305 	} else if (argc > 0) {
306 		usage();
307 		/* NOT REACHED */
308 	}
309 
310 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
311 	fromlen = sizeof (from);
312 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
313 		warn("getpeername");
314 		_exit(1);
315 	}
316 	if (keepalive &&
317 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
318 			(char *)&on, sizeof (on)) < 0) {
319 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
320 	}
321 
322 #if	defined(IPPROTO_IP) && defined(IP_TOS)
323 	if (from.ss_family == AF_INET) {
324 # if	defined(HAS_GETTOS)
325 		struct tosent *tp;
326 		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
327 			tos = tp->t_tos;
328 # endif
329 		if (tos < 0)
330 			tos = 020;	/* Low Delay bit */
331 		if (tos
332 		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
333 				  (char *)&tos, sizeof(tos)) < 0)
334 		   && (errno != ENOPROTOOPT) )
335 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
336 	}
337 #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
338 	net = 0;
339 	doit((struct sockaddr *)&from);
340 	/* NOTREACHED */
341 	return(0);
342 }  /* end of main */
343 
344 	void
345 usage()
346 {
347 	fprintf(stderr, "usage: telnetd");
348 #ifdef BFTPDAEMON
349 	fprintf(stderr, " [-B]");
350 #endif
351 	fprintf(stderr, " [-debug]");
352 #ifdef DIAGNOSTICS
353 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
354 #endif
355 	fprintf(stderr, " [-h]");
356 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
357 	fprintf(stderr, " [-k]");
358 #endif
359 #ifdef LINEMODE
360 	fprintf(stderr, " [-l]");
361 #endif
362 	fprintf(stderr, " [-n]");
363 	fprintf(stderr, "\n\t");
364 #ifdef	HAS_GETTOS
365 	fprintf(stderr, " [-S tos]");
366 #endif
367 	fprintf(stderr, " [-u utmp_hostname_length] [-U]");
368 	fprintf(stderr, " [port]\n");
369 	exit(1);
370 }
371 
372 /*
373  * getterminaltype
374  *
375  *	Ask the other end to send along its terminal type and speed.
376  * Output is the variable terminaltype filled in.
377  */
378 static unsigned char ttytype_sbbuf[] = {
379 	IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
380 };
381 
382 
383 #define undef2 __unused
384 
385 static int
386 getterminaltype(char *name undef2)
387 {
388     int retval = -1;
389 
390     settimer(baseline);
391 
392     send_do(TELOPT_TTYPE, 1);
393     send_do(TELOPT_TSPEED, 1);
394     send_do(TELOPT_XDISPLOC, 1);
395     send_do(TELOPT_NEW_ENVIRON, 1);
396     send_do(TELOPT_OLD_ENVIRON, 1);
397     while (
398 	   his_will_wont_is_changing(TELOPT_TTYPE) ||
399 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
400 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
401 	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
402 	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
403 	ttloop();
404     }
405     if (his_state_is_will(TELOPT_TSPEED)) {
406 	static unsigned char sb[] =
407 			{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
408 
409 	output_datalen(sb, sizeof sb);
410 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
411     }
412     if (his_state_is_will(TELOPT_XDISPLOC)) {
413 	static unsigned char sb[] =
414 			{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
415 
416 	output_datalen(sb, sizeof sb);
417 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
418     }
419     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
420 	static unsigned char sb[] =
421 			{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
422 
423 	output_datalen(sb, sizeof sb);
424 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
425     }
426     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
427 	static unsigned char sb[] =
428 			{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
429 
430 	output_datalen(sb, sizeof sb);
431 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
432     }
433     if (his_state_is_will(TELOPT_TTYPE)) {
434 
435 	output_datalen(ttytype_sbbuf, sizeof ttytype_sbbuf);
436 	DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
437 					sizeof ttytype_sbbuf - 2););
438     }
439     if (his_state_is_will(TELOPT_TSPEED)) {
440 	while (sequenceIs(tspeedsubopt, baseline))
441 	    ttloop();
442     }
443     if (his_state_is_will(TELOPT_XDISPLOC)) {
444 	while (sequenceIs(xdisplocsubopt, baseline))
445 	    ttloop();
446     }
447     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
448 	while (sequenceIs(environsubopt, baseline))
449 	    ttloop();
450     }
451     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
452 	while (sequenceIs(oenvironsubopt, baseline))
453 	    ttloop();
454     }
455     if (his_state_is_will(TELOPT_TTYPE)) {
456 	char first[256], last[256];
457 
458 	while (sequenceIs(ttypesubopt, baseline))
459 	    ttloop();
460 
461 	/*
462 	 * If the other side has already disabled the option, then
463 	 * we have to just go with what we (might) have already gotten.
464 	 */
465 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
466 	    (void) strncpy(first, terminaltype, sizeof(first)-1);
467 	    first[sizeof(first)-1] = '\0';
468 	    for(;;) {
469 		/*
470 		 * Save the unknown name, and request the next name.
471 		 */
472 		(void) strncpy(last, terminaltype, sizeof(last)-1);
473 		last[sizeof(last)-1] = '\0';
474 		_gettermname();
475 		if (terminaltypeok(terminaltype))
476 		    break;
477 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
478 		    his_state_is_wont(TELOPT_TTYPE)) {
479 		    /*
480 		     * We've hit the end.  If this is the same as
481 		     * the first name, just go with it.
482 		     */
483 		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
484 			break;
485 		    /*
486 		     * Get the terminal name one more time, so that
487 		     * RFC1091 compliant telnets will cycle back to
488 		     * the start of the list.
489 		     */
490 		     _gettermname();
491 		    if (strncmp(first, terminaltype, sizeof(first)) != 0) {
492 			(void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
493 			terminaltype[sizeof(terminaltype)-1] = '\0';
494 		    }
495 		    break;
496 		}
497 	    }
498 	}
499     }
500     return(retval);
501 }  /* end of getterminaltype */
502 
503 static void
504 _gettermname(void)
505 {
506     /*
507      * If the client turned off the option,
508      * we can't send another request, so we
509      * just return.
510      */
511     if (his_state_is_wont(TELOPT_TTYPE))
512 	return;
513     settimer(baseline);
514     output_datalen(ttytype_sbbuf, sizeof ttytype_sbbuf);
515     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
516 					sizeof ttytype_sbbuf - 2););
517     while (sequenceIs(ttypesubopt, baseline))
518 	ttloop();
519 }
520 
521 int
522 terminaltypeok(char *s)
523 {
524     char buf[1024];
525 
526     if (terminaltype == NULL)
527 	return(1);
528 
529     /*
530      * tgetent() will return 1 if the type is known, and
531      * 0 if it is not known.  If it returns -1, it couldn't
532      * open the database.  But if we can't open the database,
533      * it won't help to say we failed, because we won't be
534      * able to verify anything else.  So, we treat -1 like 1.
535      */
536     if (tgetent(buf, s) == 0)
537 	return(0);
538     return(1);
539 }
540 
541 /*
542  * Get a pty, scan input lines.
543  */
544 void
545 doit(struct sockaddr *who)
546 {
547 	int err_; /* XXX */
548 	int ptynum;
549 
550 	/*
551 	 * Find an available pty to use.
552 	 */
553 #ifndef	convex
554 	pty = getpty(&ptynum);
555 	if (pty < 0)
556 		fatal(net, "All network ports in use");
557 #else
558 	for (;;) {
559 		char *lp;
560 
561 		if ((lp = getpty()) == NULL)
562 			fatal(net, "Out of ptys");
563 
564 		if ((pty = open(lp, 2)) >= 0) {
565 			strlcpy(line,lp,sizeof(line));
566 			line[5] = 't';
567 			break;
568 		}
569 	}
570 #endif
571 
572 	/* get name of connected client */
573 	if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
574 	    who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
575 		fatal(net, "Couldn't resolve your address into a host name.\r\n\
576 	Please contact your net administrator");
577 	remote_hostname[sizeof(remote_hostname) - 1] = '\0';
578 
579 	trimdomain(remote_hostname, UT_HOSTSIZE);
580 	if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
581 		err_ = getnameinfo(who, who->sa_len, remote_hostname,
582 				  sizeof(remote_hostname), NULL, 0,
583 				  NI_NUMERICHOST|NI_WITHSCOPEID);
584 		/* XXX: do 'err_' check */
585 
586 	(void) gethostname(host_name, sizeof(host_name) - 1);
587 	host_name[sizeof(host_name) - 1] = '\0';
588 	hostname = host_name;
589 
590 
591 	init_env();
592 	/*
593 	 * get terminal type.
594 	 */
595 	*user_name = 0;
596 	level = getterminaltype(user_name);
597 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
598 
599 	telnet(net, pty, remote_hostname);	/* begin server process */
600 
601 	/*NOTREACHED*/
602 }  /* end of doit */
603 
604 /*
605  * Main loop.  Select from pty and network, and
606  * hand data to telnet receiver finite state machine.
607  */
608 void
609 telnet(int f, int p, char *host)
610 {
611 	int on = 1;
612 #define	TABBUFSIZ	512
613 	char	defent[TABBUFSIZ];
614 	char	defstrs[TABBUFSIZ];
615 #undef	TABBUFSIZ
616 	char *HE;
617 	char *HN;
618 	char *IM;
619 	int nfd;
620 
621 	/*
622 	 * Initialize the slc mapping table.
623 	 */
624 	get_slc_defaults();
625 
626 	/*
627 	 * Do some tests where it is desireable to wait for a response.
628 	 * Rather than doing them slowly, one at a time, do them all
629 	 * at once.
630 	 */
631 	if (my_state_is_wont(TELOPT_SGA))
632 		send_will(TELOPT_SGA, 1);
633 	/*
634 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
635 	 * because 4.2 clients are unable to deal with TCP urgent data.
636 	 *
637 	 * To find out, we send out a "DO ECHO".  If the remote system
638 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
639 	 * that fact ("WILL ECHO" ==> that the client will echo what
640 	 * WE, the server, sends it; it does NOT mean that the client will
641 	 * echo the terminal input).
642 	 */
643 	send_do(TELOPT_ECHO, 1);
644 
645 #ifdef	LINEMODE
646 	if (his_state_is_wont(TELOPT_LINEMODE)) {
647 		/* Query the peer for linemode support by trying to negotiate
648 		 * the linemode option.
649 		 */
650 		linemode = 0;
651 		editmode = 0;
652 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
653 	}
654 #endif	/* LINEMODE */
655 
656 	/*
657 	 * Send along a couple of other options that we wish to negotiate.
658 	 */
659 	send_do(TELOPT_NAWS, 1);
660 	send_will(TELOPT_STATUS, 1);
661 	flowmode = 1;		/* default flow control state */
662 	restartany = -1;	/* uninitialized... */
663 	send_do(TELOPT_LFLOW, 1);
664 
665 	/*
666 	 * Spin, waiting for a response from the DO ECHO.  However,
667 	 * some REALLY DUMB telnets out there might not respond
668 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
669 	 * telnets so far seem to respond with WONT for a DO that
670 	 * they don't understand...) because by the time we get the
671 	 * response, it will already have processed the DO ECHO.
672 	 * Kludge upon kludge.
673 	 */
674 	while (his_will_wont_is_changing(TELOPT_NAWS))
675 		ttloop();
676 
677 	/*
678 	 * But...
679 	 * The client might have sent a WILL NAWS as part of its
680 	 * startup code; if so, we'll be here before we get the
681 	 * response to the DO ECHO.  We'll make the assumption
682 	 * that any implementation that understands about NAWS
683 	 * is a modern enough implementation that it will respond
684 	 * to our DO ECHO request; hence we'll do another spin
685 	 * waiting for the ECHO option to settle down, which is
686 	 * what we wanted to do in the first place...
687 	 */
688 	if (his_want_state_is_will(TELOPT_ECHO) &&
689 	    his_state_is_will(TELOPT_NAWS)) {
690 		while (his_will_wont_is_changing(TELOPT_ECHO))
691 			ttloop();
692 	}
693 	/*
694 	 * On the off chance that the telnet client is broken and does not
695 	 * respond to the DO ECHO we sent, (after all, we did send the
696 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
697 	 * until a response to the DO NAWS comes back) simulate the
698 	 * receipt of a will echo.  This will also send a WONT ECHO
699 	 * to the client, since we assume that the client failed to
700 	 * respond because it believes that it is already in DO ECHO
701 	 * mode, which we do not want.
702 	 */
703 	if (his_want_state_is_will(TELOPT_ECHO)) {
704 		DIAG(TD_OPTIONS, output_data("td: simulating recv\r\n"));
705 		willoption(TELOPT_ECHO);
706 	}
707 
708 	/*
709 	 * Finally, to clean things up, we turn on our echo.  This
710 	 * will break stupid 4.2 telnets out of local terminal echo.
711 	 */
712 
713 	if (my_state_is_wont(TELOPT_ECHO))
714 		send_will(TELOPT_ECHO, 1);
715 
716 	/*
717 	 * Turn on packet mode
718 	 */
719 	(void) ioctl(p, TIOCPKT, (char *)&on);
720 
721 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
722 	/*
723 	 * Continuing line mode support.  If client does not support
724 	 * real linemode, attempt to negotiate kludge linemode by sending
725 	 * the do timing mark sequence.
726 	 */
727 	if (lmodetype < REAL_LINEMODE)
728 		send_do(TELOPT_TM, 1);
729 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
730 
731 	/*
732 	 * Call telrcv() once to pick up anything received during
733 	 * terminal type negotiation, 4.2/4.3 determination, and
734 	 * linemode negotiation.
735 	 */
736 	telrcv();
737 
738 	(void) ioctl(f, FIONBIO, (char *)&on);
739 	(void) ioctl(p, FIONBIO, (char *)&on);
740 
741 #if	defined(SO_OOBINLINE)
742 	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
743 				(char *)&on, sizeof on);
744 #endif	/* defined(SO_OOBINLINE) */
745 
746 #ifdef	SIGTSTP
747 	(void) signal(SIGTSTP, SIG_IGN);
748 #endif
749 #ifdef	SIGTTOU
750 	/*
751 	 * Ignoring SIGTTOU keeps the kernel from blocking us
752 	 * in ttioct() in /sys/tty.c.
753 	 */
754 	(void) signal(SIGTTOU, SIG_IGN);
755 #endif
756 
757 	(void) signal(SIGCHLD, cleanup);
758 
759 #ifdef  TIOCNOTTY
760 	{
761 		int t;
762 		t = open(_PATH_TTY, O_RDWR);
763 		if (t >= 0) {
764 			(void) ioctl(t, TIOCNOTTY, (char *)0);
765 			(void) close(t);
766 		}
767 	}
768 #endif
769 
770 	/*
771 	 * Show banner that getty never gave.
772 	 *
773 	 * We put the banner in the pty input buffer.  This way, it
774 	 * gets carriage return null processing, etc., just like all
775 	 * other pty --> client data.
776 	 */
777 
778 	if (getent(defent, "default") == 1) {
779 		char *cp=defstrs;
780 
781 		HE = Getstr("he", &cp);
782 		HN = Getstr("hn", &cp);
783 		IM = Getstr("im", &cp);
784 		if (HN && *HN)
785 			(void) strlcpy(host_name, HN, sizeof(host_name));
786 		if (IM == 0)
787 			IM = strdup("");
788 	} else {
789 		IM = strdup(DEFAULT_IM);
790 		HE = 0;
791 	}
792 	edithost(HE, host_name);
793 	if (hostinfo && *IM)
794 		putf(IM, ptyibuf2);
795 
796 	if (pcc)
797 		(void) strncat(ptyibuf2, ptyip, pcc+1);
798 	ptyip = ptyibuf2;
799 	pcc = strlen(ptyip);
800 #ifdef	LINEMODE
801 	/*
802 	 * Last check to make sure all our states are correct.
803 	 */
804 	init_termbuf();
805 	localstat();
806 #endif	/* LINEMODE */
807 
808 	DIAG(TD_REPORT, output_data("td: Entering processing loop\r\n"));
809 
810 	/*
811 	 * Startup the login process on the slave side of the terminal
812 	 * now.  We delay this until here to insure option negotiation
813 	 * is complete.
814 	 */
815 	startslave(host, level, user_name);
816 
817 	nfd = ((f > p) ? f : p) + 1;
818 	for (;;) {
819 		fd_set ibits, obits, xbits;
820 		int c;
821 
822 		if (ncc < 0 && pcc < 0)
823 			break;
824 
825 		FD_ZERO(&ibits);
826 		FD_ZERO(&obits);
827 		FD_ZERO(&xbits);
828 		/*
829 		 * Never look for input if there's still
830 		 * stuff in the corresponding output buffer
831 		 */
832 		if (nfrontp - nbackp || pcc > 0) {
833 			FD_SET(f, &obits);
834 		} else {
835 			FD_SET(p, &ibits);
836 		}
837 		if (pfrontp - pbackp || ncc > 0) {
838 			FD_SET(p, &obits);
839 		} else {
840 			FD_SET(f, &ibits);
841 		}
842 		if (!SYNCHing) {
843 			FD_SET(f, &xbits);
844 		}
845 		if ((c = select(nfd, &ibits, &obits, &xbits,
846 						(struct timeval *)0)) < 1) {
847 			if (c == -1) {
848 				if (errno == EINTR) {
849 					continue;
850 				}
851 			}
852 			sleep(5);
853 			continue;
854 		}
855 
856 		/*
857 		 * Any urgent data?
858 		 */
859 		if (FD_ISSET(net, &xbits)) {
860 		    SYNCHing = 1;
861 		}
862 
863 		/*
864 		 * Something to read from the network...
865 		 */
866 		if (FD_ISSET(net, &ibits)) {
867 #if	!defined(SO_OOBINLINE)
868 			/*
869 			 * In 4.2 (and 4.3 beta) systems, the
870 			 * OOB indication and data handling in the kernel
871 			 * is such that if two separate TCP Urgent requests
872 			 * come in, one byte of TCP data will be overlaid.
873 			 * This is fatal for Telnet, but we try to live
874 			 * with it.
875 			 *
876 			 * In addition, in 4.2 (and...), a special protocol
877 			 * is needed to pick up the TCP Urgent data in
878 			 * the correct sequence.
879 			 *
880 			 * What we do is:  if we think we are in urgent
881 			 * mode, we look to see if we are "at the mark".
882 			 * If we are, we do an OOB receive.  If we run
883 			 * this twice, we will do the OOB receive twice,
884 			 * but the second will fail, since the second
885 			 * time we were "at the mark", but there wasn't
886 			 * any data there (the kernel doesn't reset
887 			 * "at the mark" until we do a normal read).
888 			 * Once we've read the OOB data, we go ahead
889 			 * and do normal reads.
890 			 *
891 			 * There is also another problem, which is that
892 			 * since the OOB byte we read doesn't put us
893 			 * out of OOB state, and since that byte is most
894 			 * likely the TELNET DM (data mark), we would
895 			 * stay in the TELNET SYNCH (SYNCHing) state.
896 			 * So, clocks to the rescue.  If we've "just"
897 			 * received a DM, then we test for the
898 			 * presence of OOB data when the receive OOB
899 			 * fails (and AFTER we did the normal mode read
900 			 * to clear "at the mark").
901 			 */
902 		    if (SYNCHing) {
903 			int atmark;
904 
905 			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
906 			if (atmark) {
907 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
908 			    if ((ncc == -1) && (errno == EINVAL)) {
909 				ncc = read(net, netibuf, sizeof (netibuf));
910 				if (sequenceIs(didnetreceive, gotDM)) {
911 				    SYNCHing = stilloob(net);
912 				}
913 			    }
914 			} else {
915 			    ncc = read(net, netibuf, sizeof (netibuf));
916 			}
917 		    } else {
918 			ncc = read(net, netibuf, sizeof (netibuf));
919 		    }
920 		    settimer(didnetreceive);
921 #else	/* !defined(SO_OOBINLINE)) */
922 		    ncc = read(net, netibuf, sizeof (netibuf));
923 #endif	/* !defined(SO_OOBINLINE)) */
924 		    if (ncc < 0 && errno == EWOULDBLOCK)
925 			ncc = 0;
926 		    else {
927 			if (ncc <= 0) {
928 			    break;
929 			}
930 			netip = netibuf;
931 		    }
932 		    DIAG((TD_REPORT | TD_NETDATA),
933 			output_data("td: netread %d chars\r\n", ncc));
934 		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
935 		}
936 
937 		/*
938 		 * Something to read from the pty...
939 		 */
940 		if (FD_ISSET(p, &ibits)) {
941 			pcc = read(p, ptyibuf, BUFSIZ);
942 			/*
943 			 * On some systems, if we try to read something
944 			 * off the master side before the slave side is
945 			 * opened, we get EIO.
946 			 */
947 			if (pcc < 0 && (errno == EWOULDBLOCK ||
948 #ifdef	EAGAIN
949 					errno == EAGAIN ||
950 #endif
951 					errno == EIO)) {
952 				pcc = 0;
953 			} else {
954 				if (pcc <= 0)
955 					break;
956 #ifdef	LINEMODE
957 				/*
958 				 * If ioctl from pty, pass it through net
959 				 */
960 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
961 					copy_termbuf(ptyibuf+1, pcc-1);
962 					localstat();
963 					pcc = 1;
964 				}
965 #endif	/* LINEMODE */
966 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
967 					netclear();	/* clear buffer back */
968 #ifndef	NO_URGENT
969 					/*
970 					 * There are client telnets on some
971 					 * operating systems get screwed up
972 					 * royally if we send them urgent
973 					 * mode data.
974 					 */
975 					output_data("%c%c", IAC, DM);
976 					neturg = nfrontp-1; /* off by one XXX */
977 					DIAG(TD_OPTIONS,
978 					    printoption("td: send IAC", DM));
979 
980 #endif
981 				}
982 				if (his_state_is_will(TELOPT_LFLOW) &&
983 				    (ptyibuf[0] &
984 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
985 					int newflow =
986 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
987 					if (newflow != flowmode) {
988 						flowmode = newflow;
989 						output_data("%c%c%c%c%c%c",
990 							IAC, SB, TELOPT_LFLOW,
991 							flowmode ? LFLOW_ON
992 								 : LFLOW_OFF,
993 							IAC, SE);
994 						DIAG(TD_OPTIONS, printsub('>',
995 						    (unsigned char *)nfrontp-4,
996 						    4););
997 					}
998 				}
999 				pcc--;
1000 				ptyip = ptyibuf+1;
1001 			}
1002 		}
1003 
1004 		while (pcc > 0) {
1005 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
1006 				break;
1007 			c = *ptyip++ & 0377, pcc--;
1008 			if (c == IAC)
1009 				output_data("%c", c);
1010 			output_data("%c", c);
1011 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
1012 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
1013 					output_data("%c", *ptyip++ & 0377);
1014 					pcc--;
1015 				} else
1016 					output_data("%c", '\0');
1017 			}
1018 		}
1019 
1020 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
1021 			netflush();
1022 		if (ncc > 0)
1023 			telrcv();
1024 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
1025 			ptyflush();
1026 	}
1027 	cleanup(0);
1028 }  /* end of telnet */
1029 
1030 #ifndef	TCSIG
1031 # ifdef	TIOCSIG
1032 #  define TCSIG TIOCSIG
1033 # endif
1034 #endif
1035 
1036 /*
1037  * Send interrupt to process on other side of pty.
1038  * If it is in raw mode, just write NULL;
1039  * otherwise, write intr char.
1040  */
1041 void
1042 interrupt(void)
1043 {
1044 	ptyflush();	/* half-hearted */
1045 
1046 #ifdef	TCSIG
1047 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
1048 #else	/* TCSIG */
1049 	init_termbuf();
1050 	*pfrontp++ = slctab[SLC_IP].sptr ?
1051 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
1052 #endif	/* TCSIG */
1053 }
1054 
1055 /*
1056  * Send quit to process on other side of pty.
1057  * If it is in raw mode, just write NULL;
1058  * otherwise, write quit char.
1059  */
1060 void
1061 sendbrk(void)
1062 {
1063 	ptyflush();	/* half-hearted */
1064 #ifdef	TCSIG
1065 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1066 #else	/* TCSIG */
1067 	init_termbuf();
1068 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
1069 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1070 #endif	/* TCSIG */
1071 }
1072 
1073 void
1074 sendsusp(void)
1075 {
1076 #ifdef	SIGTSTP
1077 	ptyflush();	/* half-hearted */
1078 # ifdef	TCSIG
1079 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1080 # else	/* TCSIG */
1081 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
1082 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1083 # endif	/* TCSIG */
1084 #endif	/* SIGTSTP */
1085 }
1086 
1087 /*
1088  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
1089  * just send back "[Yes]".
1090  */
1091 void
1092 recv_ayt(void)
1093 {
1094 #if	defined(SIGINFO) && defined(TCSIG)
1095 	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
1096 		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
1097 		return;
1098 	}
1099 #endif
1100 	output_data("\r\n[Yes]\r\n");
1101 }
1102 
1103 void
1104 doeof(void)
1105 {
1106 	init_termbuf();
1107 
1108 #if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
1109 	if (!tty_isediting()) {
1110 		extern char oldeofc;
1111 		*pfrontp++ = oldeofc;
1112 		return;
1113 	}
1114 #endif
1115 	*pfrontp++ = slctab[SLC_EOF].sptr ?
1116 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
1117 }
1118