xref: /netbsd/libexec/telnetd/telnetd.c (revision c4a72b64)
1 /*	$NetBSD: telnetd.c,v 1.35 2002/09/20 19:11:17 mycroft Exp $	*/
2 
3 /*
4  * Copyright (C) 1997 and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1989, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 #include <sys/cdefs.h>
66 #ifndef lint
67 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
68 	The Regents of the University of California.  All rights reserved.\n");
69 #if 0
70 static char sccsid[] = "@(#)telnetd.c	8.4 (Berkeley) 5/30/95";
71 #else
72 __RCSID("$NetBSD: telnetd.c,v 1.35 2002/09/20 19:11:17 mycroft Exp $");
73 #endif
74 #endif /* not lint */
75 
76 #include "telnetd.h"
77 #include "pathnames.h"
78 
79 #include <arpa/inet.h>
80 
81 #include <err.h>
82 #include <termcap.h>
83 
84 #include <limits.h>
85 
86 #define P __P
87 
88 #if	defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
89 /*
90  * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
91  * use it to tell us to turn off all the socket security code,
92  * since that is only used in UNICOS 7.0 and later.
93  */
94 # undef _SC_CRAY_SECURE_SYS
95 #endif
96 
97 #if	defined(_SC_CRAY_SECURE_SYS)
98 #include <sys/sysv.h>
99 #include <sys/secdev.h>
100 # ifdef SO_SEC_MULTI		/* 8.0 code */
101 #include <sys/secparm.h>
102 #include <sys/usrv.h>
103 # endif /* SO_SEC_MULTI */
104 int	secflag;
105 char	tty_dev[16];
106 struct	secdev dv;
107 struct	sysv sysv;
108 # ifdef SO_SEC_MULTI		/* 8.0 code */
109 struct	socksec ss;
110 # else /* SO_SEC_MULTI */	/* 7.0 code */
111 struct	socket_security ss;
112 # endif /* SO_SEC_MULTI */
113 #endif	/* _SC_CRAY_SECURE_SYS */
114 
115 #if	defined(KRB5)
116 #define	Authenticator	k5_Authenticator
117 #include <krb5.h>
118 #undef	Authenticator
119 #include <com_err.h>
120 #endif
121 
122 #if	defined(AUTHENTICATION)
123 int	auth_level = 0;
124 #endif
125 
126 #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
127 #include <libtelnet/misc.h>
128 #endif
129 
130 #if	defined(SECURELOGIN)
131 int	require_secure_login = 0;
132 #endif
133 
134 #if	!defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
135 extern	int utmp_len;
136 #endif
137 extern int require_hwpreauth;
138 #ifdef KRB5
139 extern krb5_context telnet_context;
140 #endif
141 int	registerd_host_only = 0;
142 
143 #ifdef	STREAMSPTY
144 # include <stropts.h>
145 # include <termio.h>
146 /* make sure we don't get the bsd version */
147 # include "/usr/include/sys/tty.h"
148 # include <sys/ptyvar.h>
149 
150 /*
151  * Because of the way ptyibuf is used with streams messages, we need
152  * ptyibuf+1 to be on a full-word boundary.  The following weirdness
153  * is simply to make that happen.
154  */
155 long	ptyibufbuf[BUFSIZ/sizeof(long)+1];
156 char	*ptyibuf = ((char *)&ptyibufbuf[1])-1;
157 char	*ptyip = ((char *)&ptyibufbuf[1])-1;
158 char	ptyibuf2[BUFSIZ*4];
159 unsigned char ctlbuf[BUFSIZ];
160 struct	strbuf strbufc, strbufd;
161 
162 int readstream();
163 
164 #else	/* ! STREAMPTY */
165 
166 /*
167  * I/O data buffers,
168  * pointers, and counters.
169  */
170 char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
171 char	ptyibuf2[BUFSIZ];
172 
173 #endif /* ! STREAMPTY */
174 
175 int	hostinfo = 1;			/* do we print login banner? */
176 
177 #ifdef	CRAY
178 extern int      newmap; /* nonzero if \n maps to ^M^J */
179 int	lowpty = 0, highpty;	/* low, high pty numbers */
180 #endif /* CRAY */
181 
182 int debug = 0;
183 int keepalive = 1;
184 char *gettyname = "default";
185 char *progname;
186 
187 int main __P((int, char *[]));
188 void usage __P((void));
189 int getterminaltype __P((char *));
190 int getent __P((char *, char *));
191 void doit __P((struct sockaddr *));
192 void _gettermname __P((void));
193 int terminaltypeok __P((char *));
194 char *getstr __P((const char *, char **));
195 
196 /*
197  * The string to pass to getopt().  We do it this way so
198  * that only the actual options that we support will be
199  * passed off to getopt().
200  */
201 char valid_opts[] = {
202 	'd', ':', 'g', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
203 	'4', '6',
204 #ifdef	AUTHENTICATION
205 	'a', ':', 'X', ':',
206 #endif
207 #ifdef BFTPDAEMON
208 	'B',
209 #endif
210 #ifdef	ENCRYPTION
211 	'e', ':',
212 #endif
213 #ifdef DIAGNOSTICS
214 	'D', ':',
215 #endif
216 #ifdef	LINEMODE
217 	'l',
218 #endif
219 #ifdef CRAY
220 	'r', ':',
221 #endif
222 #ifdef	SECURELOGIN
223 	's',
224 #endif
225 #ifdef	KRB5
226 	'R', ':', 'H',
227 #endif
228 	'\0'
229 };
230 
231 int family = AF_INET;
232 
233 int
234 main(argc, argv)
235 	int argc;
236 	char *argv[];
237 {
238 	struct sockaddr_storage from;
239 	int on = 1, fromlen;
240 	register int ch;
241 #if	defined(IPPROTO_IP) && defined(IP_TOS)
242 	int tos = -1;
243 #endif
244 
245 	pfrontp = pbackp = ptyobuf;
246 	netip = netibuf;
247 	nfrontp = nbackp = netobuf;
248 #ifdef	ENCRYPTION
249 	nclearto = 0;
250 #endif	/* ENCRYPTION */
251 
252 	progname = *argv;
253 
254 #ifdef CRAY
255 	/*
256 	 * Get number of pty's before trying to process options,
257 	 * which may include changing pty range.
258 	 */
259 	highpty = getnpty();
260 #endif /* CRAY */
261 
262 	while ((ch = getopt(argc, argv, valid_opts)) != -1) {
263 		switch (ch) {
264 
265 #ifdef	AUTHENTICATION
266 		case 'a':
267 			/*
268 			 * Check for required authentication level
269 			 */
270 			if (strcmp(optarg, "debug") == 0) {
271 				auth_debug_mode = 1;
272 			} else if (strcasecmp(optarg, "none") == 0) {
273 				auth_level = 0;
274 			} else if (strcasecmp(optarg, "other") == 0) {
275 				auth_level = AUTH_OTHER;
276 			} else if (strcasecmp(optarg, "user") == 0) {
277 				auth_level = AUTH_USER;
278 			} else if (strcasecmp(optarg, "valid") == 0) {
279 				auth_level = AUTH_VALID;
280 			} else if (strcasecmp(optarg, "off") == 0) {
281 				/*
282 				 * This hack turns off authentication
283 				 */
284 				auth_level = -1;
285 			} else {
286 				fprintf(stderr,
287 			    "telnetd: unknown authorization level for -a\n");
288 			}
289 			break;
290 #endif	/* AUTHENTICATION */
291 
292 #ifdef BFTPDAEMON
293 		case 'B':
294 			bftpd++;
295 			break;
296 #endif /* BFTPDAEMON */
297 
298 		case 'd':
299 			if (strcmp(optarg, "ebug") == 0) {
300 				debug++;
301 				break;
302 			}
303 			usage();
304 			/* NOTREACHED */
305 			break;
306 
307 #ifdef DIAGNOSTICS
308 		case 'D':
309 			/*
310 			 * Check for desired diagnostics capabilities.
311 			 */
312 			if (!strcmp(optarg, "report")) {
313 				diagnostic |= TD_REPORT|TD_OPTIONS;
314 			} else if (!strcmp(optarg, "exercise")) {
315 				diagnostic |= TD_EXERCISE;
316 			} else if (!strcmp(optarg, "netdata")) {
317 				diagnostic |= TD_NETDATA;
318 			} else if (!strcmp(optarg, "ptydata")) {
319 				diagnostic |= TD_PTYDATA;
320 			} else if (!strcmp(optarg, "options")) {
321 				diagnostic |= TD_OPTIONS;
322 			} else {
323 				usage();
324 				/* NOT REACHED */
325 			}
326 			break;
327 #endif /* DIAGNOSTICS */
328 
329 #ifdef	ENCRYPTION
330 		case 'e':
331 			if (strcmp(optarg, "debug") == 0) {
332 				encrypt_debug_mode = 1;
333 				break;
334 			}
335 			usage();
336 			/* NOTREACHED */
337 			break;
338 #endif	/* ENCRYPTION */
339 
340 		case 'g':
341 			gettyname = optarg;
342 			break;
343 
344 		case 'h':
345 			hostinfo = 0;
346 			break;
347 
348 #ifdef	KRB5
349 		case 'H':
350 		    {
351 			require_hwpreauth = 1;
352 			break;
353 		    }
354 #endif	/* KRB5 */
355 
356 
357 #ifdef	LINEMODE
358 		case 'l':
359 			alwayslinemode = 1;
360 			break;
361 #endif	/* LINEMODE */
362 
363 		case 'k':
364 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
365 			lmodetype = NO_AUTOKLUDGE;
366 #else
367 			/* ignore -k option if built without kludge linemode */
368 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
369 			break;
370 
371 		case 'n':
372 			keepalive = 0;
373 			break;
374 
375 #ifdef CRAY
376 		case 'r':
377 		    {
378 			char *strchr();
379 			char *c;
380 
381 			/*
382 			 * Allow the specification of alterations
383 			 * to the pty search range.  It is legal to
384 			 * specify only one, and not change the
385 			 * other from its default.
386 			 */
387 			c = strchr(optarg, '-');
388 			if (c) {
389 				*c++ = '\0';
390 				highpty = atoi(c);
391 			}
392 			if (*optarg != '\0')
393 				lowpty = atoi(optarg);
394 			if ((lowpty > highpty) || (lowpty < 0) ||
395 							(highpty > 32767)) {
396 				usage();
397 				/* NOT REACHED */
398 			}
399 			break;
400 		    }
401 #endif	/* CRAY */
402 
403 #ifdef	KRB5
404 		case 'R':
405 		    {
406 			krb5_error_code retval;
407 
408 			if (telnet_context == 0) {
409 				retval = krb5_init_context(&telnet_context);
410 				if (retval) {
411 					com_err("telnetd", retval,
412 					    "while initializing krb5");
413 					exit(1);
414 				}
415 			}
416 			krb5_set_default_realm(telnet_context, optarg);
417 			break;
418 		    }
419 #endif	/* KRB5 */
420 
421 #ifdef	SECURELOGIN
422 		case 's':
423 			/* Secure login required */
424 			require_secure_login = 1;
425 			break;
426 #endif	/* SECURELOGIN */
427 		case 'S':
428 #ifdef	HAS_GETTOS
429 			if ((tos = parsetos(optarg, "tcp")) < 0)
430 				fprintf(stderr, "%s%s%s\n",
431 					"telnetd: Bad TOS argument '", optarg,
432 					"'; will try to use default TOS");
433 #else
434 			fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
435 						"-S flag not supported\n");
436 #endif
437 			break;
438 
439 		case 'u':
440 #if	!defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
441 			utmp_len = atoi(optarg);
442 #else
443 			fprintf(stderr, "telnetd: -u option unneeded\n");
444 #endif
445 			break;
446 
447 		case 'U':
448 			registerd_host_only = 1;
449 			break;
450 
451 #ifdef	AUTHENTICATION
452 		case 'X':
453 			/*
454 			 * Check for invalid authentication types
455 			 */
456 			auth_disable_name(optarg);
457 			break;
458 #endif	/* AUTHENTICATION */
459 
460 		case '4':
461 			family = AF_INET;
462 			break;
463 
464 		case '6':
465 			family = AF_INET6;
466 			break;
467 
468 		default:
469 			fprintf(stderr, "telnetd: %c: unknown option\n", ch);
470 			/* FALLTHROUGH */
471 		case '?':
472 			usage();
473 			/* NOTREACHED */
474 		}
475 	}
476 
477 	argc -= optind;
478 	argv += optind;
479 
480 	if (debug) {
481 	    int s, ns, foo, error;
482 	    char *service = "telnet";
483 	    struct addrinfo hints, *res;
484 
485 	    if (argc > 1) {
486 		usage();
487 		/* NOT REACHED */
488 	    } else if (argc == 1)
489 		service = *argv;
490 
491 	    memset(&hints, 0, sizeof(hints));
492 	    hints.ai_flags = AI_PASSIVE;
493 	    hints.ai_family = family;
494 	    hints.ai_socktype = SOCK_STREAM;
495 	    hints.ai_protocol = 0;
496 	    error = getaddrinfo(NULL, service, &hints, &res);
497 
498 	    if (error) {
499 		fprintf(stderr, "tcp/%s: %s\n", service, gai_strerror(error));
500 		exit(1);
501 	    }
502 
503 	    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
504 	    if (s < 0) {
505 		perror("telnetd: socket");
506 		exit(1);
507 	    }
508 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
509 				(char *)&on, sizeof(on));
510 	    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
511 		perror("bind");
512 		exit(1);
513 	    }
514 	    if (listen(s, 1) < 0) {
515 		perror("listen");
516 		exit(1);
517 	    }
518 	    foo = res->ai_addrlen;
519 	    ns = accept(s, res->ai_addr, &foo);
520 	    if (ns < 0) {
521 		perror("accept");
522 		exit(1);
523 	    }
524 	    (void) dup2(ns, 0);
525 	    (void) close(ns);
526 	    (void) close(s);
527 #ifdef convex
528 	} else if (argc == 1) {
529 		; /* VOID*/		/* Just ignore the host/port name */
530 #endif
531 	} else if (argc > 0) {
532 		usage();
533 		/* NOT REACHED */
534 	}
535 
536 #if	defined(_SC_CRAY_SECURE_SYS)
537 	secflag = sysconf(_SC_CRAY_SECURE_SYS);
538 
539 	/*
540 	 *	Get socket's security label
541 	 */
542 	if (secflag)  {
543 		int szss = sizeof(ss);
544 #ifdef SO_SEC_MULTI			/* 8.0 code */
545 		int sock_multi;
546 		int szi = sizeof(int);
547 #endif /* SO_SEC_MULTI */
548 
549 		memset((char *)&dv, 0, sizeof(dv));
550 
551 		if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
552 			perror("getsysv");
553 			exit(1);
554 		}
555 
556 		/*
557 		 *	Get socket security label and set device values
558 		 *	   {security label to be set on ttyp device}
559 		 */
560 #ifdef SO_SEC_MULTI			/* 8.0 code */
561 		if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
562 			       (char *)&ss, &szss) < 0) ||
563 		    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
564 				(char *)&sock_multi, &szi) < 0)) {
565 			perror("getsockopt");
566 			exit(1);
567 		} else {
568 			dv.dv_actlvl = ss.ss_actlabel.lt_level;
569 			dv.dv_actcmp = ss.ss_actlabel.lt_compart;
570 			if (!sock_multi) {
571 				dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
572 				dv.dv_valcmp = dv.dv_actcmp;
573 			} else {
574 				dv.dv_minlvl = ss.ss_minlabel.lt_level;
575 				dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
576 				dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
577 			}
578 			dv.dv_devflg = 0;
579 		}
580 #else /* SO_SEC_MULTI */		/* 7.0 code */
581 		if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
582 				(char *)&ss, &szss) >= 0) {
583 			dv.dv_actlvl = ss.ss_slevel;
584 			dv.dv_actcmp = ss.ss_compart;
585 			dv.dv_minlvl = ss.ss_minlvl;
586 			dv.dv_maxlvl = ss.ss_maxlvl;
587 			dv.dv_valcmp = ss.ss_maxcmp;
588 		}
589 #endif /* SO_SEC_MULTI */
590 	}
591 #endif	/* _SC_CRAY_SECURE_SYS */
592 
593 	openlog("telnetd", LOG_PID, LOG_DAEMON);
594 	fromlen = sizeof (from);
595 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
596 		fprintf(stderr, "%s: ", progname);
597 		perror("getpeername");
598 		_exit(1);
599 	}
600 	if (keepalive &&
601 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
602 			(char *)&on, sizeof (on)) < 0) {
603 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
604 	}
605 
606 #if	defined(IPPROTO_IP) && defined(IP_TOS)
607 	if (((struct sockaddr *)&from)->sa_family == AF_INET) {
608 # if	defined(HAS_GETTOS)
609 		struct tosent *tp;
610 		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
611 			tos = tp->t_tos;
612 # endif
613 		if (tos < 0)
614 			tos = 020;	/* Low Delay bit */
615 		if (tos
616 		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
617 				  (char *)&tos, sizeof(tos)) < 0)
618 		   && (errno != ENOPROTOOPT) )
619 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
620 	}
621 #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
622 
623 	net = 0;
624 	doit((struct sockaddr *)&from);
625 	/* NOTREACHED */
626 #ifdef __GNUC__
627 	exit(0);
628 #endif
629 }  /* end of main */
630 
631 	void
632 usage()
633 {
634 	fprintf(stderr, "Usage: telnetd");
635 #ifdef	AUTHENTICATION
636 	fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
637 #endif
638 #ifdef BFTPDAEMON
639 	fprintf(stderr, " [-B]");
640 #endif
641 	fprintf(stderr, " [-debug]");
642 #ifdef DIAGNOSTICS
643 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
644 #endif
645 #ifdef	ENCRYPTION
646 	fprintf(stderr, " [-edebug]");
647 #endif
648 	fprintf(stderr, " [-h]");
649 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
650 	fprintf(stderr, " [-k]");
651 #endif
652 #ifdef LINEMODE
653 	fprintf(stderr, " [-l]");
654 #endif
655 	fprintf(stderr, " [-n]");
656 #ifdef	CRAY
657 	fprintf(stderr, " [-r[lowpty]-[highpty]]");
658 #endif
659 	fprintf(stderr, "\n\t");
660 #ifdef	SECURELOGIN
661 	fprintf(stderr, " [-s]");
662 #endif
663 #ifdef	HAS_GETTOS
664 	fprintf(stderr, " [-S tos]");
665 #endif
666 #ifdef	AUTHENTICATION
667 	fprintf(stderr, " [-X auth-type]");
668 #endif
669 	fprintf(stderr, " [-u utmp_hostname_length] [-U]");
670 	fprintf(stderr, " [port]\n");
671 	exit(1);
672 }
673 
674 /*
675  * getterminaltype
676  *
677  *	Ask the other end to send along its terminal type and speed.
678  * Output is the variable terminaltype filled in.
679  */
680 static unsigned char ttytype_sbbuf[] = {
681 	IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
682 };
683 
684     int
685 getterminaltype(name)
686     char *name;
687 {
688     int retval = -1;
689 
690     settimer(baseline);
691 #if	defined(AUTHENTICATION)
692     /*
693      * Handle the Authentication option before we do anything else.
694      */
695     send_do(TELOPT_AUTHENTICATION, 1);
696     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
697 	ttloop();
698     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
699 	retval = auth_wait(name);
700     }
701 #endif
702 
703 #ifdef	ENCRYPTION
704     send_will(TELOPT_ENCRYPT, 1);
705 #endif	/* ENCRYPTION */
706     send_do(TELOPT_TTYPE, 1);
707     send_do(TELOPT_TSPEED, 1);
708     send_do(TELOPT_XDISPLOC, 1);
709     send_do(TELOPT_NEW_ENVIRON, 1);
710     send_do(TELOPT_OLD_ENVIRON, 1);
711     while (
712 #ifdef	ENCRYPTION
713 	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
714 #endif	/* ENCRYPTION */
715 	   his_will_wont_is_changing(TELOPT_TTYPE) ||
716 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
717 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
718 	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
719 	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
720 	ttloop();
721     }
722     if (his_state_is_will(TELOPT_TSPEED)) {
723 	static unsigned char sb[] =
724 			{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
725 
726 	output_datalen((const char *)sb, sizeof sb);
727 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
728     }
729 #ifdef	ENCRYPTION
730     /*
731      * Wait for the negotiation of what type of encryption we can
732      * send with.  If autoencrypt is not set, this will just return.
733      */
734     if (his_state_is_will(TELOPT_ENCRYPT)) {
735 	encrypt_wait();
736     }
737 #endif	/* ENCRYPTION */
738     if (his_state_is_will(TELOPT_XDISPLOC)) {
739 	static unsigned char sb[] =
740 			{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
741 
742 	output_datalen((const char *)sb, sizeof sb);
743 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
744     }
745     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
746 	static unsigned char sb[] =
747 			{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
748 
749 	output_datalen((const char *)sb, sizeof sb);
750 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
751     }
752     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
753 	static unsigned char sb[] =
754 			{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
755 
756 	output_datalen((const char *)sb, sizeof sb);
757 	DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
758     }
759     if (his_state_is_will(TELOPT_TTYPE)) {
760 
761 	output_datalen((const char *)ttytype_sbbuf, sizeof ttytype_sbbuf);
762 	DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
763 					sizeof ttytype_sbbuf - 2););
764     }
765     if (his_state_is_will(TELOPT_TSPEED)) {
766 	while (sequenceIs(tspeedsubopt, baseline))
767 	    ttloop();
768     }
769     if (his_state_is_will(TELOPT_XDISPLOC)) {
770 	while (sequenceIs(xdisplocsubopt, baseline))
771 	    ttloop();
772     }
773     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
774 	while (sequenceIs(environsubopt, baseline))
775 	    ttloop();
776     }
777     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
778 	while (sequenceIs(oenvironsubopt, baseline))
779 	    ttloop();
780     }
781     if (his_state_is_will(TELOPT_TTYPE)) {
782 	char first[256], last[256];
783 
784 	while (sequenceIs(ttypesubopt, baseline))
785 	    ttloop();
786 
787 	/*
788 	 * If the other side has already disabled the option, then
789 	 * we have to just go with what we (might) have already gotten.
790 	 */
791 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
792 	    (void) strncpy(first, terminaltype, sizeof(first) - 1);
793 	    first[sizeof(first) - 1] = '\0';
794 	    for(;;) {
795 		/*
796 		 * Save the unknown name, and request the next name.
797 		 */
798 		(void) strncpy(last, terminaltype, sizeof(last) - 1);
799 		last[sizeof(last) - 1] = '\0';
800 		_gettermname();
801 		if (terminaltypeok(terminaltype))
802 		    break;
803 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
804 		    his_state_is_wont(TELOPT_TTYPE)) {
805 		    /*
806 		     * We've hit the end.  If this is the same as
807 		     * the first name, just go with it.
808 		     */
809 		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
810 			break;
811 		    /*
812 		     * Get the terminal name one more time, so that
813 		     * RFC1091 compliant telnets will cycle back to
814 		     * the start of the list.
815 		     */
816 		     _gettermname();
817 		    if (strncmp(first, terminaltype, sizeof(first)) != 0) {
818 			(void) strncpy(terminaltype, first, sizeof(first) - 1);
819 			terminaltype[sizeof(terminaltype) - 1] = '\0';
820 		    }
821 		    break;
822 		}
823 	    }
824 	}
825     }
826     return(retval);
827 }  /* end of getterminaltype */
828 
829     void
830 _gettermname()
831 {
832     /*
833      * If the client turned off the option,
834      * we can't send another request, so we
835      * just return.
836      */
837     if (his_state_is_wont(TELOPT_TTYPE))
838 	return;
839     settimer(baseline);
840     output_datalen((const char *)ttytype_sbbuf, sizeof ttytype_sbbuf);
841     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
842 					sizeof ttytype_sbbuf - 2););
843     while (sequenceIs(ttypesubopt, baseline))
844 	ttloop();
845 }
846 
847     int
848 terminaltypeok(s)
849     char *s;
850 {
851     char buf[1024];
852 
853     if (terminaltype == NULL)
854 	return(1);
855 
856     /*
857      * tgetent() will return 1 if the type is known, and
858      * 0 if it is not known.  If it returns -1, it couldn't
859      * open the database.  But if we can't open the database,
860      * it won't help to say we failed, because we won't be
861      * able to verify anything else.  So, we treat -1 like 1.
862      */
863     if (tgetent(buf, s) == 0)
864 	return(0);
865     return(1);
866 }
867 
868 #ifndef	MAXHOSTNAMELEN
869 #define	MAXHOSTNAMELEN 64
870 #endif	/* MAXHOSTNAMELEN */
871 
872 char *hostname;
873 char host_name[MAXHOSTNAMELEN + 1];
874 char remote_host_name[MAXHOSTNAMELEN + 1];
875 
876 #ifndef	convex
877 extern void telnet P((int, int));
878 #else
879 extern void telnet P((int, int, char *));
880 #endif
881 
882 /*
883  * Get a pty, scan input lines.
884  */
885 void
886 doit(who)
887 	struct sockaddr *who;
888 {
889 	char *host;
890 	int error;
891 	int level;
892 	int ptynum;
893 	char user_name[256];
894 
895 	/*
896 	 * Find an available pty to use.
897 	 */
898 #ifndef	convex
899 	pty = getpty(&ptynum);
900 	if (pty < 0)
901 		fatal(net, "All network ports in use");
902 #else
903 	for (;;) {
904 		char *lp;
905 
906 		if ((lp = getpty()) == NULL)
907 			fatal(net, "Out of ptys");
908 
909 		if ((pty = open(lp, 2)) >= 0) {
910 			(void)strlcpy(line, lp, sizeof(NULL16STR));
911 			line[5] = 't';
912 			break;
913 		}
914 	}
915 #endif
916 
917 #if	defined(_SC_CRAY_SECURE_SYS)
918 	/*
919 	 *	set ttyp line security label
920 	 */
921 	if (secflag) {
922 		char slave_dev[16];
923 
924 		sprintf(tty_dev, "/dev/pty/%03d", ptynum);
925 		if (setdevs(tty_dev, &dv) < 0)
926 		 	fatal(net, "cannot set pty security");
927 		sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
928 		if (setdevs(slave_dev, &dv) < 0)
929 		 	fatal(net, "cannot set tty security");
930 	}
931 #endif	/* _SC_CRAY_SECURE_SYS */
932 
933 	/* get name of connected client */
934 	error = getnameinfo(who, who->sa_len, remote_host_name,
935 	    sizeof(remote_host_name), NULL, 0, 0);
936 
937 #if	!defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
938 	if (!error && strlen(remote_host_name) > utmp_len)
939 		error = getnameinfo(who, who->sa_len, remote_host_name,
940 		    sizeof(remote_host_name), NULL, 0, NI_NUMERICHOST);
941 #endif
942 
943 	if (error) {
944 		fatal(net, "Couldn't resolve your address into a host name.\r\n\
945 	 Please contact your net administrator");
946 #ifdef __GNUC__
947 		host = NULL;	/* XXX gcc */
948 #endif
949 	}
950 
951 	remote_host_name[sizeof(remote_host_name)-1] = 0;
952 	host = remote_host_name;
953 
954 	(void)gethostname(host_name, sizeof (host_name));
955 	host_name[sizeof(host_name) - 1] = '\0';
956 	hostname = host_name;
957 
958 #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
959 	auth_encrypt_init(hostname, host, "TELNETD", 1);
960 #endif
961 
962 	init_env();
963 	/*
964 	 * get terminal type.
965 	 */
966 	*user_name = 0;
967 	level = getterminaltype(user_name);
968 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
969 
970 	/*
971 	 * Start up the login process on the slave side of the terminal
972 	 */
973 #ifndef	convex
974 	startslave(host, level, user_name);
975 
976 #if	defined(_SC_CRAY_SECURE_SYS)
977 	if (secflag) {
978 		if (setulvl(dv.dv_actlvl) < 0)
979 			fatal(net,"cannot setulvl()");
980 		if (setucmp(dv.dv_actcmp) < 0)
981 			fatal(net, "cannot setucmp()");
982 	}
983 #endif	/* _SC_CRAY_SECURE_SYS */
984 
985 	telnet(net, pty);  /* begin server processing */
986 #else
987 	telnet(net, pty, host);
988 #endif
989 	/*NOTREACHED*/
990 }  /* end of doit */
991 
992 
993 /*
994  * Main loop.  Select from pty and network, and
995  * hand data to telnet receiver finite state machine.
996  */
997 	void
998 #ifndef	convex
999 telnet(f, p)
1000 #else
1001 telnet(f, p, host)
1002 #endif
1003 	int f, p;
1004 #ifdef convex
1005 	char *host;
1006 #endif
1007 {
1008 	int on = 1;
1009 #define	TABBUFSIZ	512
1010 	char	defent[TABBUFSIZ];
1011 	char	defstrs[TABBUFSIZ];
1012 #undef	TABBUFSIZ
1013 	char *HE, *HN, *IM, *IF, *ptyibuf2ptr;
1014 	struct pollfd set[2];
1015 
1016 	/*
1017 	 * Initialize the slc mapping table.
1018 	 */
1019 	get_slc_defaults();
1020 
1021 	/*
1022 	 * Do some tests where it is desireable to wait for a response.
1023 	 * Rather than doing them slowly, one at a time, do them all
1024 	 * at once.
1025 	 */
1026 	if (my_state_is_wont(TELOPT_SGA))
1027 		send_will(TELOPT_SGA, 1);
1028 	/*
1029 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
1030 	 * because 4.2 clients are unable to deal with TCP urgent data.
1031 	 *
1032 	 * To find out, we send out a "DO ECHO".  If the remote system
1033 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
1034 	 * that fact ("WILL ECHO" ==> that the client will echo what
1035 	 * WE, the server, sends it; it does NOT mean that the client will
1036 	 * echo the terminal input).
1037 	 */
1038 	send_do(TELOPT_ECHO, 1);
1039 
1040 #ifdef	LINEMODE
1041 	if (his_state_is_wont(TELOPT_LINEMODE)) {
1042 		/* Query the peer for linemode support by trying to negotiate
1043 		 * the linemode option.
1044 		 */
1045 		linemode = 0;
1046 		editmode = 0;
1047 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
1048 	}
1049 #endif	/* LINEMODE */
1050 
1051 	/*
1052 	 * Send along a couple of other options that we wish to negotiate.
1053 	 */
1054 	send_do(TELOPT_NAWS, 1);
1055 	send_will(TELOPT_STATUS, 1);
1056 	flowmode = 1;		/* default flow control state */
1057 	restartany = -1;	/* uninitialized... */
1058 	send_do(TELOPT_LFLOW, 1);
1059 
1060 	/*
1061 	 * Spin, waiting for a response from the DO ECHO.  However,
1062 	 * some REALLY DUMB telnets out there might not respond
1063 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
1064 	 * telnets so far seem to respond with WONT for a DO that
1065 	 * they don't understand...) because by the time we get the
1066 	 * response, it will already have processed the DO ECHO.
1067 	 * Kludge upon kludge.
1068 	 */
1069 	while (his_will_wont_is_changing(TELOPT_NAWS))
1070 		ttloop();
1071 
1072 	/*
1073 	 * But...
1074 	 * The client might have sent a WILL NAWS as part of its
1075 	 * startup code; if so, we'll be here before we get the
1076 	 * response to the DO ECHO.  We'll make the assumption
1077 	 * that any implementation that understands about NAWS
1078 	 * is a modern enough implementation that it will respond
1079 	 * to our DO ECHO request; hence we'll do another spin
1080 	 * waiting for the ECHO option to settle down, which is
1081 	 * what we wanted to do in the first place...
1082 	 */
1083 	if (his_want_state_is_will(TELOPT_ECHO) &&
1084 	    his_state_is_will(TELOPT_NAWS)) {
1085 		while (his_will_wont_is_changing(TELOPT_ECHO))
1086 			ttloop();
1087 	}
1088 	/*
1089 	 * On the off chance that the telnet client is broken and does not
1090 	 * respond to the DO ECHO we sent, (after all, we did send the
1091 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
1092 	 * until a response to the DO NAWS comes back) simulate the
1093 	 * receipt of a will echo.  This will also send a WONT ECHO
1094 	 * to the client, since we assume that the client failed to
1095 	 * respond because it believes that it is already in DO ECHO
1096 	 * mode, which we do not want.
1097 	 */
1098 	if (his_want_state_is_will(TELOPT_ECHO)) {
1099 		DIAG(TD_OPTIONS,
1100 			{output_data("td: simulating recv\r\n");});
1101 		willoption(TELOPT_ECHO);
1102 	}
1103 
1104 	/*
1105 	 * Finally, to clean things up, we turn on our echo.  This
1106 	 * will break stupid 4.2 telnets out of local terminal echo.
1107 	 */
1108 
1109 	if (my_state_is_wont(TELOPT_ECHO))
1110 		send_will(TELOPT_ECHO, 1);
1111 
1112 #ifndef	STREAMSPTY
1113 	/*
1114 	 * Turn on packet mode
1115 	 */
1116 	(void) ioctl(p, TIOCPKT, (char *)&on);
1117 #endif
1118 
1119 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
1120 	/*
1121 	 * Continuing line mode support.  If client does not support
1122 	 * real linemode, attempt to negotiate kludge linemode by sending
1123 	 * the do timing mark sequence.
1124 	 */
1125 	if (lmodetype < REAL_LINEMODE)
1126 		send_do(TELOPT_TM, 1);
1127 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1128 
1129 	/*
1130 	 * Call telrcv() once to pick up anything received during
1131 	 * terminal type negotiation, 4.2/4.3 determination, and
1132 	 * linemode negotiation.
1133 	 */
1134 	telrcv();
1135 
1136 	(void) ioctl(f, FIONBIO, (char *)&on);
1137 	(void) ioctl(p, FIONBIO, (char *)&on);
1138 
1139 #if	defined(SO_OOBINLINE)
1140 	(void) setsockopt(f, SOL_SOCKET, SO_OOBINLINE,
1141 				(char *)&on, sizeof on);
1142 #endif	/* defined(SO_OOBINLINE) */
1143 
1144 #ifdef	SIGTSTP
1145 	(void) signal(SIGTSTP, SIG_IGN);
1146 #endif
1147 #ifdef	SIGTTOU
1148 	/*
1149 	 * Ignoring SIGTTOU keeps the kernel from blocking us
1150 	 * in ttioct() in /sys/tty.c.
1151 	 */
1152 	(void) signal(SIGTTOU, SIG_IGN);
1153 #endif
1154 
1155 	(void) signal(SIGCHLD, cleanup);
1156 
1157 
1158 #ifdef  TIOCNOTTY
1159 	{
1160 		register int t;
1161 		t = open(_PATH_TTY, O_RDWR);
1162 		if (t >= 0) {
1163 			(void) ioctl(t, TIOCNOTTY, (char *)0);
1164 			(void) close(t);
1165 		}
1166 	}
1167 #endif
1168 
1169 
1170 	/*
1171 	 * Show banner that getty never gave.
1172 	 *
1173 	 * We put the banner in the pty input buffer.  This way, it
1174 	 * gets carriage return null processing, etc., just like all
1175 	 * other pty --> client data.
1176 	 */
1177 
1178 	if (getenv("USER"))
1179 		hostinfo = 0;
1180 
1181 	if (getent(defent, gettyname) == 1) {
1182 		char *cp=defstrs;
1183 
1184 		HE = getstr("he", &cp);
1185 		HN = getstr("hn", &cp);
1186 		IM = getstr("im", &cp);
1187 		IF = getstr("if", &cp);
1188 		if (HN && *HN)
1189 			(void)strlcpy(host_name, HN, sizeof(host_name));
1190 		if (IM == 0)
1191 			IM = "";
1192 	} else {
1193 		IM = DEFAULT_IM;
1194 		HE = 0;
1195 	}
1196 	edithost(HE, host_name);
1197 	ptyibuf2ptr = ptyibuf2;
1198 	if (hostinfo) {
1199 		if (IF)	{
1200 			char buf[_POSIX2_LINE_MAX];
1201 			FILE *fd;
1202 
1203 			if ((fd = fopen(IF, "r")) != NULL) {
1204 				while (fgets(buf, sizeof(buf) - 1, fd) != NULL)
1205 					ptyibuf2ptr = putf(buf, ptyibuf2ptr);
1206 				fclose(fd);
1207 			}
1208 		}
1209 		if (*IM)
1210 			ptyibuf2ptr = putf(IM, ptyibuf2ptr);
1211 	}
1212 
1213 	if (pcc)
1214 		strncpy(ptyibuf2ptr, ptyip, pcc+1);
1215 	ptyip = ptyibuf2;
1216 	pcc = strlen(ptyip);
1217 #ifdef	LINEMODE
1218 	/*
1219 	 * Last check to make sure all our states are correct.
1220 	 */
1221 	init_termbuf();
1222 	localstat();
1223 #endif	/* LINEMODE */
1224 
1225 	DIAG(TD_REPORT,
1226 		{output_data("td: Entering processing loop\r\n");});
1227 
1228 #ifdef	convex
1229 	startslave(host);
1230 #endif
1231 
1232 	set[0].fd = f;
1233 	set[1].fd = p;
1234 	for (;;) {
1235 		register int c;
1236 
1237 		if (ncc < 0 && pcc < 0)
1238 			break;
1239 
1240 		/*
1241 		 * Never look for input if there's still
1242 		 * stuff in the corresponding output buffer
1243 		 */
1244 		set[0].events = 0;
1245 		set[1].events = 0;
1246 		if (nfrontp - nbackp || pcc > 0)
1247 			set[0].events |= POLLOUT;
1248 		else
1249 			set[1].events |= POLLIN;
1250 		if (pfrontp - pbackp || ncc > 0)
1251 			set[1].events |= POLLOUT;
1252 		else
1253 			set[0].events |= POLLIN;
1254 		if (!SYNCHing)
1255 			set[0].events |= POLLPRI;
1256 
1257 		if ((c = poll(set, 2, INFTIM)) < 1) {
1258 			if (c == -1) {
1259 				if (errno == EINTR) {
1260 					continue;
1261 				}
1262 			}
1263 			sleep(5);
1264 			continue;
1265 		}
1266 
1267 		/*
1268 		 * Any urgent data?
1269 		 */
1270 		if (set[0].revents & POLLPRI) {
1271 		    SYNCHing = 1;
1272 		}
1273 
1274 		/*
1275 		 * Something to read from the network...
1276 		 */
1277 		if (set[0].revents && POLLIN) {
1278 #if	!defined(SO_OOBINLINE)
1279 			/*
1280 			 * In 4.2 (and 4.3 beta) systems, the
1281 			 * OOB indication and data handling in the kernel
1282 			 * is such that if two separate TCP Urgent requests
1283 			 * come in, one byte of TCP data will be overlaid.
1284 			 * This is fatal for Telnet, but we try to live
1285 			 * with it.
1286 			 *
1287 			 * In addition, in 4.2 (and...), a special protocol
1288 			 * is needed to pick up the TCP Urgent data in
1289 			 * the correct sequence.
1290 			 *
1291 			 * What we do is:  if we think we are in urgent
1292 			 * mode, we look to see if we are "at the mark".
1293 			 * If we are, we do an OOB receive.  If we run
1294 			 * this twice, we will do the OOB receive twice,
1295 			 * but the second will fail, since the second
1296 			 * time we were "at the mark", but there wasn't
1297 			 * any data there (the kernel doesn't reset
1298 			 * "at the mark" until we do a normal read).
1299 			 * Once we've read the OOB data, we go ahead
1300 			 * and do normal reads.
1301 			 *
1302 			 * There is also another problem, which is that
1303 			 * since the OOB byte we read doesn't put us
1304 			 * out of OOB state, and since that byte is most
1305 			 * likely the TELNET DM (data mark), we would
1306 			 * stay in the TELNET SYNCH (SYNCHing) state.
1307 			 * So, clocks to the rescue.  If we've "just"
1308 			 * received a DM, then we test for the
1309 			 * presence of OOB data when the receive OOB
1310 			 * fails (and AFTER we did the normal mode read
1311 			 * to clear "at the mark").
1312 			 */
1313 		    if (SYNCHing) {
1314 			int atmark;
1315 
1316 			(void) ioctl(f, SIOCATMARK, (char *)&atmark);
1317 			if (atmark) {
1318 			    ncc = recv(f, netibuf, sizeof (netibuf), MSG_OOB);
1319 			    if ((ncc == -1) && (errno == EINVAL)) {
1320 				ncc = read(f, netibuf, sizeof (netibuf));
1321 				if (sequenceIs(didnetreceive, gotDM)) {
1322 				    SYNCHing = stilloob(f);
1323 				}
1324 			    }
1325 			} else {
1326 			    ncc = read(f, netibuf, sizeof (netibuf));
1327 			}
1328 		    } else {
1329 			ncc = read(f, netibuf, sizeof (netibuf));
1330 		    }
1331 		    settimer(didnetreceive);
1332 #else	/* !defined(SO_OOBINLINE)) */
1333 		    ncc = read(f, netibuf, sizeof (netibuf));
1334 #endif	/* !defined(SO_OOBINLINE)) */
1335 		    if (ncc < 0 && errno == EWOULDBLOCK)
1336 			ncc = 0;
1337 		    else {
1338 			if (ncc <= 0) {
1339 			    break;
1340 			}
1341 			netip = netibuf;
1342 		    }
1343 		    DIAG((TD_REPORT | TD_NETDATA),
1344 			    {output_data("td: netread %d chars\r\n", ncc);});
1345 		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
1346 		}
1347 
1348 		/*
1349 		 * Something to read from the pty...
1350 		 */
1351 		if (set[1].revents & POLLIN) {
1352 #ifndef	STREAMSPTY
1353 			pcc = read(p, ptyibuf, BUFSIZ);
1354 #else
1355 			pcc = readstream(p, ptyibuf, BUFSIZ);
1356 #endif
1357 			/*
1358 			 * On some systems, if we try to read something
1359 			 * off the master side before the slave side is
1360 			 * opened, we get EIO.
1361 			 */
1362 			if (pcc < 0 && (errno == EWOULDBLOCK ||
1363 #ifdef	EAGAIN
1364 					errno == EAGAIN ||
1365 #endif
1366 					errno == EIO)) {
1367 				pcc = 0;
1368 			} else {
1369 				if (pcc <= 0)
1370 					break;
1371 #ifdef	LINEMODE
1372 				/*
1373 				 * If ioctl from pty, pass it through net
1374 				 */
1375 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
1376 					copy_termbuf(ptyibuf+1, pcc-1);
1377 					localstat();
1378 					pcc = 1;
1379 				}
1380 #endif	/* LINEMODE */
1381 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
1382 					netclear();	/* clear buffer back */
1383 #ifndef	NO_URGENT
1384 					/*
1385 					 * There are client telnets on some
1386 					 * operating systems get screwed up
1387 					 * royally if we send them urgent
1388 					 * mode data.
1389 					 */
1390 					output_data("%c%c", IAC, DM);
1391 					neturg = nfrontp - 1; /* off by one XXX */
1392 					DIAG(TD_OPTIONS,
1393 					    printoption("td: send IAC", DM));
1394 
1395 #endif
1396 				}
1397 				if (his_state_is_will(TELOPT_LFLOW) &&
1398 				    (ptyibuf[0] &
1399 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
1400 					int newflow =
1401 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
1402 					if (newflow != flowmode) {
1403 						flowmode = newflow;
1404 						(void) output_data(
1405 							"%c%c%c%c%c%c",
1406 							IAC, SB, TELOPT_LFLOW,
1407 							flowmode ? LFLOW_ON
1408 								 : LFLOW_OFF,
1409 							IAC, SE);
1410 						DIAG(TD_OPTIONS, printsub('>',
1411 						    (unsigned char *)nfrontp - 4,
1412 						    4););
1413 					}
1414 				}
1415 				pcc--;
1416 				ptyip = ptyibuf+1;
1417 			}
1418 		}
1419 
1420 		while (pcc > 0) {
1421 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
1422 				break;
1423 			c = *ptyip++ & 0377, pcc--;
1424 			if (c == IAC)
1425 				output_data("%c", c);
1426 			output_data("%c", c);
1427 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
1428 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
1429 					output_data("%c", *ptyip++ & 0377);
1430 					pcc--;
1431 				} else
1432 					output_datalen("\0", 1);
1433 			}
1434 		}
1435 
1436 		if (set[0].revents & POLLOUT && (nfrontp - nbackp) > 0)
1437 			netflush();
1438 		if (ncc > 0)
1439 			telrcv();
1440 		if (set[1].revents & POLLOUT && (pfrontp - pbackp) > 0)
1441 			ptyflush();
1442 	}
1443 	cleanup(0);
1444 }  /* end of telnet */
1445 
1446 #ifndef	TCSIG
1447 # ifdef	TIOCSIG
1448 #  define TCSIG TIOCSIG
1449 # endif
1450 #endif
1451 
1452 #ifdef	STREAMSPTY
1453 
1454 int flowison = -1;  /* current state of flow: -1 is unknown */
1455 
1456 int readstream(p, ibuf, bufsize)
1457 	int p;
1458 	char *ibuf;
1459 	int bufsize;
1460 {
1461 	int flags = 0;
1462 	int ret = 0;
1463 	struct termios *tsp;
1464 	struct termio *tp;
1465 	struct iocblk *ip;
1466 	char vstop, vstart;
1467 	int ixon;
1468 	int newflow;
1469 
1470 	strbufc.maxlen = BUFSIZ;
1471 	strbufc.buf = (char *)ctlbuf;
1472 	strbufd.maxlen = bufsize-1;
1473 	strbufd.len = 0;
1474 	strbufd.buf = ibuf+1;
1475 	ibuf[0] = 0;
1476 
1477 	ret = getmsg(p, &strbufc, &strbufd, &flags);
1478 	if (ret < 0)  /* error of some sort -- probably EAGAIN */
1479 		return(-1);
1480 
1481 	if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
1482 		/* data message */
1483 		if (strbufd.len > 0) {			/* real data */
1484 			return(strbufd.len + 1);	/* count header char */
1485 		} else {
1486 			/* nothing there */
1487 			errno = EAGAIN;
1488 			return(-1);
1489 		}
1490 	}
1491 
1492 	/*
1493 	 * It's a control message.  Return 1, to look at the flag we set
1494 	 */
1495 
1496 	switch (ctlbuf[0]) {
1497 	case M_FLUSH:
1498 		if (ibuf[1] & FLUSHW)
1499 			ibuf[0] = TIOCPKT_FLUSHWRITE;
1500 		return(1);
1501 
1502 	case M_IOCTL:
1503 		ip = (struct iocblk *) (ibuf+1);
1504 
1505 		switch (ip->ioc_cmd) {
1506 		case TCSETS:
1507 		case TCSETSW:
1508 		case TCSETSF:
1509 			tsp = (struct termios *)
1510 					(ibuf+1 + sizeof(struct iocblk));
1511 			vstop = tsp->c_cc[VSTOP];
1512 			vstart = tsp->c_cc[VSTART];
1513 			ixon = tsp->c_iflag & IXON;
1514 			break;
1515 		case TCSETA:
1516 		case TCSETAW:
1517 		case TCSETAF:
1518 			tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
1519 			vstop = tp->c_cc[VSTOP];
1520 			vstart = tp->c_cc[VSTART];
1521 			ixon = tp->c_iflag & IXON;
1522 			break;
1523 		default:
1524 			errno = EAGAIN;
1525 			return(-1);
1526 		}
1527 
1528 		newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
1529 		if (newflow != flowison) {  /* it's a change */
1530 			flowison = newflow;
1531 			ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
1532 			return(1);
1533 		}
1534 	}
1535 
1536 	/* nothing worth doing anything about */
1537 	errno = EAGAIN;
1538 	return(-1);
1539 }
1540 #endif /* STREAMSPTY */
1541 
1542 /*
1543  * Send interrupt to process on other side of pty.
1544  * If it is in raw mode, just write NULL;
1545  * otherwise, write intr char.
1546  */
1547 	void
1548 interrupt()
1549 {
1550 	ptyflush();	/* half-hearted */
1551 
1552 #if defined(STREAMSPTY) && defined(TIOCSIGNAL)
1553 	/* Streams PTY style ioctl to post a signal */
1554 	{
1555 		int sig = SIGINT;
1556 		(void) ioctl(pty, TIOCSIGNAL, &sig);
1557 		(void) ioctl(pty, I_FLUSH, FLUSHR);
1558 	}
1559 #else
1560 #ifdef	TCSIG
1561 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
1562 #else	/* TCSIG */
1563 	init_termbuf();
1564 	*pfrontp++ = slctab[SLC_IP].sptr ?
1565 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
1566 #endif	/* TCSIG */
1567 #endif
1568 }
1569 
1570 /*
1571  * Send quit to process on other side of pty.
1572  * If it is in raw mode, just write NULL;
1573  * otherwise, write quit char.
1574  */
1575 	void
1576 sendbrk()
1577 {
1578 	ptyflush();	/* half-hearted */
1579 #ifdef	TCSIG
1580 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1581 #else	/* TCSIG */
1582 	init_termbuf();
1583 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
1584 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1585 #endif	/* TCSIG */
1586 }
1587 
1588 	void
1589 sendsusp()
1590 {
1591 #ifdef	SIGTSTP
1592 	ptyflush();	/* half-hearted */
1593 # ifdef	TCSIG
1594 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1595 # else	/* TCSIG */
1596 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
1597 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1598 # endif	/* TCSIG */
1599 #endif	/* SIGTSTP */
1600 }
1601 
1602 /*
1603  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
1604  * just send back "[Yes]".
1605  */
1606 	void
1607 recv_ayt()
1608 {
1609 #if	defined(SIGINFO) && defined(TCSIG)
1610 	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
1611 		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
1612 		return;
1613 	}
1614 #endif
1615 	(void) output_data("\r\n[Yes]\r\n");
1616 }
1617 
1618 	void
1619 doeof()
1620 {
1621 	init_termbuf();
1622 
1623 #if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
1624 	if (!tty_isediting()) {
1625 		extern char oldeofc;
1626 		*pfrontp++ = oldeofc;
1627 		return;
1628 	}
1629 #endif
1630 	*pfrontp++ = slctab[SLC_EOF].sptr ?
1631 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
1632 }
1633