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