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