xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 44363)
121182Sdist /*
238904Sborman  * Copyright (c) 1989 Regents of the University of California.
333687Sbostic  * All rights reserved.
433687Sbostic  *
542673Sbostic  * %sccs.include.redist.c%
621182Sdist  */
721182Sdist 
86295Sroot #ifndef lint
921182Sdist char copyright[] =
1038904Sborman "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1121182Sdist  All rights reserved.\n";
1233687Sbostic #endif /* not lint */
136295Sroot 
1421182Sdist #ifndef lint
15*44363Sborman static char sccsid[] = "@(#)telnetd.c	5.45 (Berkeley) 06/28/90";
1633687Sbostic #endif /* not lint */
1721182Sdist 
1838904Sborman #include "telnetd.h"
1938904Sborman 
206002Sroot /*
2138904Sborman  * I/O data buffers,
2238904Sborman  * pointers, and counters.
236002Sroot  */
2438904Sborman char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
2538904Sborman char	ptyibuf2[BUFSIZ];
269218Ssam 
2738904Sborman #ifdef	CRAY
2838904Sborman int	hostinfo = 1;			/* do we print login banner? */
2938904Sborman #endif
309218Ssam 
3138904Sborman #ifdef	CRAY
3238904Sborman extern int      newmap; /* nonzero if \n maps to ^M^J */
3340242Sborman int	lowpty = 0, highpty;	/* low, high pty numbers */
3438904Sborman #endif /* CRAY */
3512216Ssam 
3638904Sborman int debug = 0;
3738904Sborman char *progname;
389218Ssam 
39*44363Sborman #if	defined(NEED_GETTOS)
40*44363Sborman struct tosent {
41*44363Sborman 	char	*t_name;	/* name */
42*44363Sborman 	char	**t_aliases;	/* alias list */
43*44363Sborman 	char	*t_proto;	/* protocol */
44*44363Sborman 	int	t_tos;		/* Type Of Service bits */
45*44363Sborman };
46*44363Sborman 
47*44363Sborman struct tosent *
48*44363Sborman gettosbyname(name, proto)
49*44363Sborman char *name, *proto;
50*44363Sborman {
51*44363Sborman 	static struct tosent te;
52*44363Sborman 	static char *aliasp = 0;
53*44363Sborman 
54*44363Sborman 	te.t_name = name;
55*44363Sborman 	te.t_aliases = &aliasp;
56*44363Sborman 	te.t_proto = proto;
57*44363Sborman 	te.t_tos = 020;	/* Low Delay bit */
58*44363Sborman 	return(&te);
59*44363Sborman }
60*44363Sborman #endif
61*44363Sborman 
6238904Sborman main(argc, argv)
6338904Sborman 	char *argv[];
6438904Sborman {
6538904Sborman 	struct sockaddr_in from;
6638904Sborman 	int on = 1, fromlen;
67*44363Sborman #if	defined(HAS_IP_TOS) || defined(NEED_GETTOS)
6840242Sborman 	struct tosent *tp;
69*44363Sborman #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
706002Sroot 
7138904Sborman 	pfrontp = pbackp = ptyobuf;
7238904Sborman 	netip = netibuf;
7338904Sborman 	nfrontp = nbackp = netobuf;
746002Sroot 
7538904Sborman 	progname = *argv;
7640242Sborman 
7740242Sborman #ifdef CRAY
7840242Sborman 	/*
7940242Sborman 	 * Get number of pty's before trying to process options,
8040242Sborman 	 * which may include changing pty range.
8140242Sborman 	 */
8240242Sborman 	highpty = getnpty();
8340242Sborman #endif /* CRAY */
8440242Sborman 
8538904Sborman top:
8638904Sborman 	argc--, argv++;
8727649Sminshall 
8838904Sborman 	if (argc > 0 && strcmp(*argv, "-debug") == 0) {
8938904Sborman 		debug++;
9038904Sborman 		goto top;
9138904Sborman 	}
9227649Sminshall 
9338904Sborman #ifdef	LINEMODE
9438904Sborman 	if (argc > 0 && !strcmp(*argv, "-l")) {
9538904Sborman 		alwayslinemode = 1;
9638904Sborman 		goto top;
9738904Sborman 	}
9838904Sborman #endif	/* LINEMODE */
9927649Sminshall 
10038904Sborman #ifdef CRAY
10138904Sborman 	if (argc > 0 && !strcmp(*argv, "-h")) {
10238904Sborman 		hostinfo = 0;
10338904Sborman 		goto top;
10438904Sborman 	}
10527649Sminshall 
10638904Sborman 	if (argc > 0 && !strncmp(*argv, "-r", 2)) {
10738904Sborman 		char *strchr();
10838904Sborman 		char *c;
10927649Sminshall 
11040242Sborman 		/*
11140242Sborman 		 * Allow the specification of alterations to the pty search
11240242Sborman 		 * range.  It is legal to specify only one, and not change the
11340242Sborman 		 * other from its default.
11440242Sborman 		 */
11538904Sborman 		*argv += 2;
11638904Sborman 		if (**argv == '\0' && argc)
11738904Sborman 			argv++, argc--;
11838904Sborman 		c = strchr(*argv, '-');
11938904Sborman 		if (c) {
12038904Sborman 			*c++ = '\0';
12138904Sborman 			highpty = atoi(c);
12240242Sborman 		}
12340242Sborman 		if (**argv != '\0')
12440242Sborman 			lowpty = atoi(*argv);
12540242Sborman 		if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
126*44363Sborman 			usage();
127*44363Sborman 			/* NOT REACHED */
12838904Sborman 		}
12938904Sborman 		goto top;
13038904Sborman 	}
13138904Sborman # ifdef	NEWINIT
13238904Sborman 	if (argc > 0 && !strncmp(*argv, "-I", 2)) {
13338904Sborman 		extern char *gen_id;
13427649Sminshall 
13538904Sborman 		*argv += 2;
13638904Sborman 		if (**argv == '\0') {
137*44363Sborman 			if (argc < 2) {
138*44363Sborman 				usage();
139*44363Sborman 				/* NOT REACHED */
140*44363Sborman 			}
14138904Sborman 			argv++, argc--;
142*44363Sborman 			if (**argv == '\0') {
143*44363Sborman 				usage();
144*44363Sborman 				/* NOT REACHED */
145*44363Sborman 			}
14638904Sborman 		}
14738904Sborman 		gen_id = *argv;
14838904Sborman 		goto top;
14938904Sborman 	}
15038904Sborman # endif	/* NEWINIT */
15138904Sborman #endif	/* CRAY */
1526002Sroot 
153*44363Sborman #ifdef DIAGNOSTICS
154*44363Sborman 	/*
155*44363Sborman 	 * Check for desired diagnostics capabilities.
156*44363Sborman 	 */
157*44363Sborman 	if (argc > 0 && !strncmp(*argv, "-D", 2)) {
158*44363Sborman 		*argv += 2;
159*44363Sborman 		if (**argv == '\0') {
160*44363Sborman 			if (argc < 2) {
161*44363Sborman 				usage();
162*44363Sborman 				/* NOT REACHED */
163*44363Sborman 			}
164*44363Sborman 			argv++, argc--;
165*44363Sborman 			if (**argv == '\0') {
166*44363Sborman 				usage();
167*44363Sborman 				/* NOT REACHED */
168*44363Sborman 			}
169*44363Sborman 		}
170*44363Sborman 		if (!strcmp(*argv, "report")) {
171*44363Sborman 			diagnostic |= TD_REPORT|TD_OPTIONS;
172*44363Sborman 		} else if (!strcmp(*argv, "exercise")) {
173*44363Sborman 			diagnostic |= TD_EXERCISE;
174*44363Sborman 		} else if (!strcmp(*argv, "netdata")) {
175*44363Sborman 			diagnostic |= TD_NETDATA;
176*44363Sborman 		} else if (!strcmp(*argv, "ptydata")) {
177*44363Sborman 			diagnostic |= TD_PTYDATA;
178*44363Sborman 		} else if (!strcmp(*argv, "options")) {
179*44363Sborman 			diagnostic |= TD_OPTIONS;
180*44363Sborman 		} else {
181*44363Sborman 			usage();
182*44363Sborman 			/* NOT REACHED */
183*44363Sborman 		}
184*44363Sborman 		goto top;
185*44363Sborman 	}
186*44363Sborman #endif /* DIAGNOSTICS */
187*44363Sborman 
188*44363Sborman #ifdef BFTPDAEMON
189*44363Sborman 	/*
190*44363Sborman 	 * Check for bftp daemon
191*44363Sborman 	 */
192*44363Sborman 	if (argc > 0 && !strncmp(*argv, "-B", 2)) {
193*44363Sborman 		bftpd++;
194*44363Sborman 		goto top;
195*44363Sborman 	}
196*44363Sborman #endif /* BFTPDAEMON */
197*44363Sborman 
198*44363Sborman 	if (argc > 0 && **argv == '-') {
199*44363Sborman 		fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
200*44363Sborman 		usage();
201*44363Sborman 		/* NOT REACHED */
202*44363Sborman 	}
203*44363Sborman 
20438904Sborman 	if (debug) {
20527185Sminshall 	    int s, ns, foo;
20627185Sminshall 	    struct servent *sp;
20727185Sminshall 	    static struct sockaddr_in sin = { AF_INET };
20827185Sminshall 
209*44363Sborman 	    if (argc > 1) {
210*44363Sborman 		usage();
211*44363Sborman 		/* NOT REACHED */
212*44363Sborman 	    } else if (argc == 1) {
21338904Sborman 		    if (sp = getservbyname(*argv, "tcp")) {
21438904Sborman 			sin.sin_port = sp->s_port;
21538904Sborman 		    } else {
21638904Sborman 			sin.sin_port = atoi(*argv);
21738904Sborman 			if ((int)sin.sin_port <= 0) {
21838904Sborman 			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
219*44363Sborman 			    usage();
220*44363Sborman 			    /* NOT REACHED */
22138904Sborman 			}
22238904Sborman 			sin.sin_port = htons((u_short)sin.sin_port);
22338904Sborman 		   }
22437210Sminshall 	    } else {
22537210Sminshall 		sp = getservbyname("telnet", "tcp");
22637210Sminshall 		if (sp == 0) {
227*44363Sborman 		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
22838904Sborman 		    exit(1);
22937210Sminshall 		}
23037210Sminshall 		sin.sin_port = sp->s_port;
23127185Sminshall 	    }
23227185Sminshall 
23327185Sminshall 	    s = socket(AF_INET, SOCK_STREAM, 0);
23427185Sminshall 	    if (s < 0) {
23527185Sminshall 		    perror("telnetd: socket");;
23627185Sminshall 		    exit(1);
23727185Sminshall 	    }
23838904Sborman 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
23938904Sborman 	    if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
24027185Sminshall 		perror("bind");
24127185Sminshall 		exit(1);
24227185Sminshall 	    }
24327185Sminshall 	    if (listen(s, 1) < 0) {
24427185Sminshall 		perror("listen");
24527185Sminshall 		exit(1);
24627185Sminshall 	    }
24727185Sminshall 	    foo = sizeof sin;
24838904Sborman 	    ns = accept(s, (struct sockaddr *)&sin, &foo);
24927185Sminshall 	    if (ns < 0) {
25027185Sminshall 		perror("accept");
25127185Sminshall 		exit(1);
25227185Sminshall 	    }
25338904Sborman 	    (void) dup2(ns, 0);
25438904Sborman 	    (void) close(ns);
25538904Sborman 	    (void) close(s);
256*44363Sborman 	} else if (argc > 0) {
257*44363Sborman 		usage();
258*44363Sborman 		/* NOT REACHED */
25927185Sminshall 	}
26038904Sborman 
26124855Seric 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
26216371Skarels 	fromlen = sizeof (from);
26338904Sborman 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
26438904Sborman 		fprintf(stderr, "%s: ", progname);
26516371Skarels 		perror("getpeername");
26616371Skarels 		_exit(1);
2678346Ssam 	}
26817156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
26917187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
27010418Ssam 	}
27140242Sborman 
272*44363Sborman #if	defined(HAS_IP_TOS) || defined(NEED_GETTOS)
273*44363Sborman 	if ((tp = gettosbyname("telnet", "tcp")) &&
274*44363Sborman 	    (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
27540242Sborman 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
276*44363Sborman #endif	/* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
27738904Sborman 	net = 0;
27838904Sborman 	doit(&from);
27938904Sborman 	/* NOTREACHED */
28038904Sborman }  /* end of main */
2816002Sroot 
282*44363Sborman usage()
283*44363Sborman {
284*44363Sborman 	fprintf(stderr, "Usage: telnetd [-debug] [-h]");
285*44363Sborman #ifdef	NEWINIT
286*44363Sborman 	fprintf(stderr, " [-Iinitid]");
287*44363Sborman #endif	/* NEWINIT */
288*44363Sborman #ifdef DIAGNOSTICS
289*44363Sborman 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
290*44363Sborman #endif /* DIAGNOSTICS */
291*44363Sborman #ifdef LINEMODE
292*44363Sborman 	fprintf(stderr, " [-l]");
293*44363Sborman #endif
294*44363Sborman #ifdef	CRAY
295*44363Sborman 	fprintf(stderr, " [-r[lowpty]-[highpty]]");
296*44363Sborman #endif
297*44363Sborman #ifdef BFTPDAEMON
298*44363Sborman 	fprintf(stderr, " [-B]");
299*44363Sborman #endif /* BFTPDAEMON */
300*44363Sborman 	fprintf(stderr, " [port]\n");
301*44363Sborman 	exit(1);
302*44363Sborman }
303*44363Sborman 
30440242Sborman void	cleanup();
30527649Sminshall 
30627649Sminshall /*
30727983Sminshall  * getterminaltype
30827649Sminshall  *
30938904Sborman  *	Ask the other end to send along its terminal type and speed.
31027983Sminshall  * Output is the variable terminaltype filled in.
31127649Sminshall  */
31238904Sborman static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
31327983Sminshall void
31427983Sminshall getterminaltype()
31527649Sminshall {
31638904Sborman     void ttloop();
31727649Sminshall 
31838904Sborman     settimer(baseline);
31939503Sborman     send_do(TELOPT_TTYPE, 1);
32039503Sborman     send_do(TELOPT_TSPEED, 1);
321*44363Sborman     send_do(TELOPT_XDISPLOC, 1);
322*44363Sborman     send_do(TELOPT_ENVIRON, 1);
323*44363Sborman     while (his_will_wont_is_changing(TELOPT_TTYPE) ||
324*44363Sborman 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
325*44363Sborman 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
326*44363Sborman 	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
32727983Sminshall 	ttloop();
32827649Sminshall     }
329*44363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
33038904Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
33127983Sminshall 
33227983Sminshall 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
33327983Sminshall 	nfrontp += sizeof sbbuf;
33438904Sborman     }
335*44363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
336*44363Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
33738904Sborman 
338*44363Sborman 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
339*44363Sborman 	nfrontp += sizeof sbbuf;
340*44363Sborman     }
341*44363Sborman     if (his_state_is_will(TELOPT_ENVIRON)) {
342*44363Sborman 	static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
343*44363Sborman 
344*44363Sborman 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
345*44363Sborman 	nfrontp += sizeof sbbuf;
346*44363Sborman     }
347*44363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
348*44363Sborman 
34938904Sborman 	bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
35038904Sborman 	nfrontp += sizeof ttytype_sbbuf;
35138904Sborman     }
352*44363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
35338904Sborman 	while (sequenceIs(tspeedsubopt, baseline))
35427983Sminshall 	    ttloop();
35538904Sborman     }
356*44363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
357*44363Sborman 	while (sequenceIs(xdisplocsubopt, baseline))
358*44363Sborman 	    ttloop();
359*44363Sborman     }
360*44363Sborman     if (his_state_is_will(TELOPT_ENVIRON)) {
361*44363Sborman 	while (sequenceIs(environsubopt, baseline))
362*44363Sborman 	    ttloop();
363*44363Sborman     }
364*44363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
36538904Sborman 	char first[256], last[256];
36638904Sborman 
36738904Sborman 	while (sequenceIs(ttypesubopt, baseline))
36838904Sborman 	    ttloop();
36938904Sborman 
370*44363Sborman 	/*
371*44363Sborman 	 * If the other side has already disabled the option, then
372*44363Sborman 	 * we have to just go with what we (might) have already gotten.
373*44363Sborman 	 */
374*44363Sborman 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
37538904Sborman 	    (void) strncpy(first, terminaltype, sizeof(first));
37638904Sborman 	    for(;;) {
37738904Sborman 		/*
37838904Sborman 		 * Save the unknown name, and request the next name.
37938904Sborman 		 */
38038904Sborman 		(void) strncpy(last, terminaltype, sizeof(last));
38138904Sborman 		_gettermname();
382*44363Sborman 		if (terminaltypeok(terminaltype))
38338904Sborman 		    break;
384*44363Sborman 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
385*44363Sborman 		    his_state_is_wont(TELOPT_TTYPE)) {
38638904Sborman 		    /*
38738904Sborman 		     * We've hit the end.  If this is the same as
38838904Sborman 		     * the first name, just go with it.
38938904Sborman 		     */
39038904Sborman 		    if (strncmp(first, terminaltype, sizeof(first) == 0))
39138904Sborman 			break;
39238904Sborman 		    /*
393*44363Sborman 		     * Get the terminal name one more time, so that
39438904Sborman 		     * RFC1091 compliant telnets will cycle back to
39538904Sborman 		     * the start of the list.
39638904Sborman 		     */
397*44363Sborman 		     _gettermname();
39838904Sborman 		    if (strncmp(first, terminaltype, sizeof(first) != 0))
39938904Sborman 			(void) strncpy(terminaltype, first, sizeof(first));
40038904Sborman 		    break;
40138904Sborman 		}
40238904Sborman 	    }
40327983Sminshall 	}
40427983Sminshall     }
40538904Sborman }  /* end of getterminaltype */
40638904Sborman 
40738904Sborman _gettermname()
40838904Sborman {
409*44363Sborman     /*
410*44363Sborman      * If the client turned off the option,
411*44363Sborman      * we can't send another request, so we
412*44363Sborman      * just return.
413*44363Sborman      */
414*44363Sborman     if (his_state_is_wont(TELOPT_TTYPE))
415*44363Sborman 	return;
41638904Sborman     settimer(baseline);
41738904Sborman     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
41838904Sborman     nfrontp += sizeof ttytype_sbbuf;
41938904Sborman     while (sequenceIs(ttypesubopt, baseline))
42038904Sborman 	ttloop();
42127649Sminshall }
42227649Sminshall 
42338904Sborman terminaltypeok(s)
42438904Sborman char *s;
42538904Sborman {
42638904Sborman     char buf[1024];
42738904Sborman 
42838904Sborman     if (terminaltype == NULL)
42938904Sborman 	return(1);
43038904Sborman 
43138904Sborman     /*
43238904Sborman      * tgetent() will return 1 if the type is known, and
43338904Sborman      * 0 if it is not known.  If it returns -1, it couldn't
43438904Sborman      * open the database.  But if we can't open the database,
43538904Sborman      * it won't help to say we failed, because we won't be
43638904Sborman      * able to verify anything else.  So, we treat -1 like 1.
43738904Sborman      */
43838904Sborman     if (tgetent(buf, s) == 0)
43938904Sborman 	return(0);
44038904Sborman     return(1);
44138904Sborman }
44238904Sborman 
4436002Sroot /*
4446002Sroot  * Get a pty, scan input lines.
4456002Sroot  */
44638904Sborman doit(who)
44712683Ssam 	struct sockaddr_in *who;
4486002Sroot {
44920188Skarels 	char *host, *inet_ntoa();
45038904Sborman 	int t;
45112683Ssam 	struct hostent *hp;
4526002Sroot 
45338904Sborman 	/*
45438904Sborman 	 * Find an available pty to use.
45538904Sborman 	 */
45638904Sborman 	pty = getpty();
45738904Sborman 	if (pty < 0)
45838904Sborman 		fatal(net, "All network ports in use");
45920188Skarels 
46038904Sborman 	t = getptyslave();
46138904Sborman 
46238904Sborman 	/* get name of connected client */
46338904Sborman 	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
46412683Ssam 		who->sin_family);
46512683Ssam 	if (hp)
46612683Ssam 		host = hp->h_name;
46712683Ssam 	else
46817444Sralph 		host = inet_ntoa(who->sin_addr);
46927983Sminshall 
470*44363Sborman 	init_env();
47127983Sminshall 	/*
47238904Sborman 	 * get terminal type.
47327983Sminshall 	 */
47427983Sminshall 	getterminaltype();
475*44363Sborman 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
47627983Sminshall 
47727649Sminshall 	/*
47838904Sborman 	 * Start up the login process on the slave side of the terminal
47927649Sminshall 	 */
48038904Sborman 	startslave(t, host);
48138904Sborman 
48238904Sborman 	telnet(net, pty);  /* begin server processing */
4839244Ssam 	/*NOTREACHED*/
48438904Sborman }  /* end of doit */
4859244Ssam 
48638904Sborman #ifndef	MAXHOSTNAMELEN
48738904Sborman #define	MAXHOSTNAMELEN 64
48838904Sborman #endif	MAXHOSTNAMELEN
4896002Sroot /*
4906002Sroot  * Main loop.  Select from pty and network, and
4916002Sroot  * hand data to telnet receiver finite state machine.
4926002Sroot  */
4936002Sroot telnet(f, p)
49438904Sborman int f, p;
4956002Sroot {
4966002Sroot 	int on = 1;
49727898Skarels 	char hostname[MAXHOSTNAMELEN];
49840242Sborman #if	defined(CRAY2) && defined(UNICOS5)
49938904Sborman 	int termstat();
50038904Sborman 	int interrupt(), sendbrk();
50138904Sborman #endif
50233271Sminshall #define	TABBUFSIZ	512
50333271Sminshall 	char	defent[TABBUFSIZ];
50433271Sminshall 	char	defstrs[TABBUFSIZ];
50533271Sminshall #undef	TABBUFSIZ
50633271Sminshall 	char *HE;
50733271Sminshall 	char *HN;
50833271Sminshall 	char *IM;
50938904Sborman 	void netflush();
51038904Sborman 
51132400Sminshall 	/*
51238904Sborman 	 * Initialize the slc mapping table.
51332400Sminshall 	 */
51438904Sborman 	get_slc_defaults();
5156002Sroot 
5168379Ssam 	/*
51738904Sborman 	 * Do some tests where it is desireable to wait for a response.
51838904Sborman 	 * Rather than doing them slowly, one at a time, do them all
51938904Sborman 	 * at once.
5208379Ssam 	 */
521*44363Sborman 	if (my_state_is_wont(TELOPT_SGA))
52239503Sborman 		send_will(TELOPT_SGA, 1);
52312713Ssam 	/*
52427649Sminshall 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
52527649Sminshall 	 * because 4.2 clients are unable to deal with TCP urgent data.
52627649Sminshall 	 *
52727649Sminshall 	 * To find out, we send out a "DO ECHO".  If the remote system
52827649Sminshall 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
52927649Sminshall 	 * that fact ("WILL ECHO" ==> that the client will echo what
53027649Sminshall 	 * WE, the server, sends it; it does NOT mean that the client will
53127649Sminshall 	 * echo the terminal input).
53227649Sminshall 	 */
53339503Sborman 	send_do(TELOPT_ECHO, 1);
53427649Sminshall 
53538904Sborman #ifdef	LINEMODE
536*44363Sborman 	if (his_state_is_wont(TELOPT_LINEMODE)) {
53738904Sborman 		/* Query the peer for linemode support by trying to negotiate
53838904Sborman 		 * the linemode option.
53938904Sborman 		 */
540*44363Sborman 		linemode = 0;
54138904Sborman 		editmode = 0;
54239503Sborman 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
54338904Sborman 	}
54438904Sborman #endif	/* LINEMODE */
54538904Sborman 
54627649Sminshall 	/*
54738904Sborman 	 * Send along a couple of other options that we wish to negotiate.
54838904Sborman 	 */
54939503Sborman 	send_do(TELOPT_NAWS, 1);
55039503Sborman 	send_will(TELOPT_STATUS, 1);
55138904Sborman 	flowmode = 1;  /* default flow control state */
55239503Sborman 	send_do(TELOPT_LFLOW, 1);
55338904Sborman 
55438904Sborman 	/*
55538904Sborman 	 * Spin, waiting for a response from the DO ECHO.  However,
55638904Sborman 	 * some REALLY DUMB telnets out there might not respond
55738904Sborman 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
55838904Sborman 	 * telnets so far seem to respond with WONT for a DO that
55938904Sborman 	 * they don't understand...) because by the time we get the
56038904Sborman 	 * response, it will already have processed the DO ECHO.
56138904Sborman 	 * Kludge upon kludge.
56238904Sborman 	 */
563*44363Sborman 	while (his_will_wont_is_changing(TELOPT_NAWS))
56438904Sborman 		ttloop();
56538904Sborman 
56638904Sborman 	/*
567*44363Sborman 	 * But...
568*44363Sborman 	 * The client might have sent a WILL NAWS as part of its
569*44363Sborman 	 * startup code; if so, we'll be here before we get the
570*44363Sborman 	 * response to the DO ECHO.  We'll make the assumption
571*44363Sborman 	 * that any implementation that understands about NAWS
572*44363Sborman 	 * is a modern enough implementation that it will respond
573*44363Sborman 	 * to our DO ECHO request; hence we'll do another spin
574*44363Sborman 	 * waiting for the ECHO option to settle down, which is
575*44363Sborman 	 * what we wanted to do in the first place...
576*44363Sborman 	 */
577*44363Sborman 	if (his_want_state_is_will(TELOPT_ECHO) &&
578*44363Sborman 	    his_state_is_will(TELOPT_NAWS)) {
579*44363Sborman 		while (his_will_wont_is_changing(TELOPT_ECHO))
580*44363Sborman 			ttloop();
581*44363Sborman 	}
582*44363Sborman 	/*
58338995Sborman 	 * On the off chance that the telnet client is broken and does not
58438995Sborman 	 * respond to the DO ECHO we sent, (after all, we did send the
58538995Sborman 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
58638995Sborman 	 * until a response to the DO NAWS comes back) simulate the
58738995Sborman 	 * receipt of a will echo.  This will also send a WONT ECHO
58838995Sborman 	 * to the client, since we assume that the client failed to
58938995Sborman 	 * respond because it believes that it is already in DO ECHO
59038995Sborman 	 * mode, which we do not want.
59138995Sborman 	 */
592*44363Sborman 	if (his_want_state_is_will(TELOPT_ECHO)) {
593*44363Sborman #ifdef DIAGNOSTICS
594*44363Sborman 		if (diagnostic & TD_OPTIONS) {
595*44363Sborman 			sprintf(nfrontp, "td: simulating recv\r\n");
596*44363Sborman 			nfrontp += strlen(nfrontp);
597*44363Sborman 		}
598*44363Sborman #endif /* DIAGNOSTICS */
59939503Sborman 		willoption(TELOPT_ECHO);
60040242Sborman 	}
60138995Sborman 
60238995Sborman 	/*
60338995Sborman 	 * Finally, to clean things up, we turn on our echo.  This
60438995Sborman 	 * will break stupid 4.2 telnets out of local terminal echo.
60538995Sborman 	 */
60638995Sborman 
607*44363Sborman 	if (my_state_is_wont(TELOPT_ECHO))
60839503Sborman 		send_will(TELOPT_ECHO, 1);
60938995Sborman 
61038995Sborman 	/*
61138904Sborman 	 * Turn on packet mode, and default to line at at time mode.
61238904Sborman 	 */
61338904Sborman 	(void) ioctl(p, TIOCPKT, (char *)&on);
61438904Sborman #ifdef	LINEMODE
61538904Sborman 	tty_setlinemode(1);
61638904Sborman 
61738904Sborman # ifdef	KLUDGELINEMODE
61838904Sborman 	/*
61938904Sborman 	 * Continuing line mode support.  If client does not support
62038904Sborman 	 * real linemode, attempt to negotiate kludge linemode by sending
62138904Sborman 	 * the do timing mark sequence.
62238904Sborman 	 */
62338904Sborman 	if (lmodetype < REAL_LINEMODE)
62439503Sborman 		send_do(TELOPT_TM, 1);
62538904Sborman # endif	/* KLUDGELINEMODE */
62638904Sborman #endif	/* LINEMODE */
62738904Sborman 
62838904Sborman 	/*
62938904Sborman 	 * Call telrcv() once to pick up anything received during
63038904Sborman 	 * terminal type negotiation, 4.2/4.3 determination, and
63138904Sborman 	 * linemode negotiation.
63238904Sborman 	 */
63338904Sborman 	telrcv();
63438904Sborman 
63538904Sborman 	(void) ioctl(f, FIONBIO, (char *)&on);
63638904Sborman 	(void) ioctl(p, FIONBIO, (char *)&on);
63740242Sborman #if	defined(CRAY2) && defined(UNICOS5)
63838904Sborman 	init_termdriver(f, p, interrupt, sendbrk);
63938904Sborman #endif
64038904Sborman 
64138904Sborman #if	defined(SO_OOBINLINE)
64238904Sborman 	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
64338904Sborman #endif	/* defined(SO_OOBINLINE) */
64438904Sborman 
64538904Sborman #ifdef	SIGTSTP
64638904Sborman 	(void) signal(SIGTSTP, SIG_IGN);
64738904Sborman #endif
64838904Sborman #ifdef	SIGTTOU
64938904Sborman 	/*
65038904Sborman 	 * Ignoring SIGTTOU keeps the kernel from blocking us
65138904Sborman 	 * in ttioct() in /sys/tty.c.
65238904Sborman 	 */
65338904Sborman 	(void) signal(SIGTTOU, SIG_IGN);
65438904Sborman #endif
65538904Sborman 
65638904Sborman 	(void) signal(SIGCHLD, cleanup);
65738904Sborman 
65840242Sborman #if	defined(CRAY2) && defined(UNICOS5)
65938904Sborman 	/*
66038904Sborman 	 * Cray-2 will send a signal when pty modes are changed by slave
66138904Sborman 	 * side.  Set up signal handler now.
66238904Sborman 	 */
66338904Sborman 	if ((int)signal(SIGUSR1, termstat) < 0)
66438904Sborman 		perror("signal");
66538904Sborman 	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
66638904Sborman 		perror("ioctl:TCSIGME");
66738904Sborman 	/*
66838904Sborman 	 * Make processing loop check terminal characteristics early on.
66938904Sborman 	 */
67038904Sborman 	termstat();
67138904Sborman #endif
67238904Sborman 
673*44363Sborman #ifdef	NO_SETSID
67438904Sborman 	(void) setpgrp(0, 0);
675*44363Sborman #else
676*44363Sborman 	(void) setsid();
67740242Sborman #endif
678*44363Sborman #if	defined(TIOCSCTTY) && defined(CRAY)
679*44363Sborman 	ioctl(p, TIOCSCTTY, 0);
680*44363Sborman #endif
68138904Sborman 
68238904Sborman 	/*
68312713Ssam 	 * Show banner that getty never gave.
68427797Sminshall 	 *
68533271Sminshall 	 * We put the banner in the pty input buffer.  This way, it
68633271Sminshall 	 * gets carriage return null processing, etc., just like all
68733271Sminshall 	 * other pty --> client data.
68812713Ssam 	 */
68927797Sminshall 
69038904Sborman 	(void) gethostname(hostname, sizeof (hostname));
69138904Sborman 
69233271Sminshall 	if (getent(defent, "default") == 1) {
69333271Sminshall 		char *getstr();
69438904Sborman 		char *cp=defstrs;
69527649Sminshall 
69638904Sborman 		HE = getstr("he", &cp);
69738904Sborman 		HN = getstr("hn", &cp);
69838904Sborman 		IM = getstr("im", &cp);
69933271Sminshall 		if (HN && *HN)
70038904Sborman 			(void) strcpy(hostname, HN);
70138904Sborman 		if (IM == 0)
70238904Sborman 			IM = "";
70333271Sminshall 	} else {
70438904Sborman #ifdef	CRAY
70538904Sborman 		if (hostinfo == 0)
70638904Sborman 			IM = 0;
70738904Sborman 		else
70838904Sborman #endif
70938904Sborman 			IM = DEFAULT_IM;
71038904Sborman 		HE = 0;
71133271Sminshall 	}
71238904Sborman 	edithost(HE, hostname);
71338904Sborman 	if (IM && *IM)
71438904Sborman 		putf(IM, ptyibuf2);
71527797Sminshall 
71638904Sborman 	if (pcc)
71738904Sborman 		(void) strncat(ptyibuf2, ptyip, pcc+1);
71838904Sborman 	ptyip = ptyibuf2;
71938904Sborman 	pcc = strlen(ptyip);
72040242Sborman #ifdef	LINEMODE
72140242Sborman 	/*
72240242Sborman 	 * Last check to make sure all our states are correct.
72340242Sborman 	 */
72440242Sborman 	init_termbuf();
72540242Sborman 	localstat();
72640242Sborman #endif	/* LINEMODE */
72733271Sminshall 
728*44363Sborman #ifdef DIAGNOSTICS
729*44363Sborman 	if (diagnostic & TD_REPORT) {
730*44363Sborman 		sprintf(nfrontp, "td: Entering processing loop\r\n");
731*44363Sborman 		nfrontp += strlen(nfrontp);
732*44363Sborman 	}
733*44363Sborman #endif /* DIAGNOSTICS */
734*44363Sborman 
7356002Sroot 	for (;;) {
73627185Sminshall 		fd_set ibits, obits, xbits;
7376002Sroot 		register int c;
7386002Sroot 
73927185Sminshall 		if (ncc < 0 && pcc < 0)
74027185Sminshall 			break;
74127185Sminshall 
74240242Sborman #if	defined(CRAY2) && defined(UNICOS5)
74338904Sborman 		if (needtermstat)
74438904Sborman 			_termstat();
74540242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
74627185Sminshall 		FD_ZERO(&ibits);
74727185Sminshall 		FD_ZERO(&obits);
74827185Sminshall 		FD_ZERO(&xbits);
7496002Sroot 		/*
7506002Sroot 		 * Never look for input if there's still
7516002Sroot 		 * stuff in the corresponding output buffer
7526002Sroot 		 */
75327185Sminshall 		if (nfrontp - nbackp || pcc > 0) {
75427185Sminshall 			FD_SET(f, &obits);
75527185Sminshall 		} else {
75627185Sminshall 			FD_SET(p, &ibits);
75727185Sminshall 		}
75827185Sminshall 		if (pfrontp - pbackp || ncc > 0) {
75927185Sminshall 			FD_SET(p, &obits);
76027185Sminshall 		} else {
76127185Sminshall 			FD_SET(f, &ibits);
76227185Sminshall 		}
76327185Sminshall 		if (!SYNCHing) {
76427185Sminshall 			FD_SET(f, &xbits);
76527185Sminshall 		}
76627185Sminshall 		if ((c = select(16, &ibits, &obits, &xbits,
76727185Sminshall 						(struct timeval *)0)) < 1) {
76827185Sminshall 			if (c == -1) {
76927185Sminshall 				if (errno == EINTR) {
77027185Sminshall 					continue;
77127185Sminshall 				}
77227185Sminshall 			}
7736002Sroot 			sleep(5);
7746002Sroot 			continue;
7756002Sroot 		}
7766002Sroot 
7776002Sroot 		/*
77827185Sminshall 		 * Any urgent data?
77927185Sminshall 		 */
78027185Sminshall 		if (FD_ISSET(net, &xbits)) {
78127185Sminshall 		    SYNCHing = 1;
78227185Sminshall 		}
78327185Sminshall 
78427185Sminshall 		/*
7856002Sroot 		 * Something to read from the network...
7866002Sroot 		 */
78727185Sminshall 		if (FD_ISSET(net, &ibits)) {
78827649Sminshall #if	!defined(SO_OOBINLINE)
78927185Sminshall 			/*
79027898Skarels 			 * In 4.2 (and 4.3 beta) systems, the
79127185Sminshall 			 * OOB indication and data handling in the kernel
79227185Sminshall 			 * is such that if two separate TCP Urgent requests
79327185Sminshall 			 * come in, one byte of TCP data will be overlaid.
79427185Sminshall 			 * This is fatal for Telnet, but we try to live
79527185Sminshall 			 * with it.
79627185Sminshall 			 *
79727185Sminshall 			 * In addition, in 4.2 (and...), a special protocol
79827185Sminshall 			 * is needed to pick up the TCP Urgent data in
79927185Sminshall 			 * the correct sequence.
80027185Sminshall 			 *
80127185Sminshall 			 * What we do is:  if we think we are in urgent
80227185Sminshall 			 * mode, we look to see if we are "at the mark".
80327185Sminshall 			 * If we are, we do an OOB receive.  If we run
80427185Sminshall 			 * this twice, we will do the OOB receive twice,
80527185Sminshall 			 * but the second will fail, since the second
80627185Sminshall 			 * time we were "at the mark", but there wasn't
80727185Sminshall 			 * any data there (the kernel doesn't reset
80827185Sminshall 			 * "at the mark" until we do a normal read).
80927185Sminshall 			 * Once we've read the OOB data, we go ahead
81027185Sminshall 			 * and do normal reads.
81127185Sminshall 			 *
81227185Sminshall 			 * There is also another problem, which is that
81327185Sminshall 			 * since the OOB byte we read doesn't put us
81427185Sminshall 			 * out of OOB state, and since that byte is most
81527185Sminshall 			 * likely the TELNET DM (data mark), we would
81627185Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
81727185Sminshall 			 * So, clocks to the rescue.  If we've "just"
81827185Sminshall 			 * received a DM, then we test for the
81927185Sminshall 			 * presence of OOB data when the receive OOB
82027185Sminshall 			 * fails (and AFTER we did the normal mode read
82127185Sminshall 			 * to clear "at the mark").
82227185Sminshall 			 */
82327185Sminshall 		    if (SYNCHing) {
82427185Sminshall 			int atmark;
82527185Sminshall 
82638904Sborman 			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
82727185Sminshall 			if (atmark) {
82827185Sminshall 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
82927185Sminshall 			    if ((ncc == -1) && (errno == EINVAL)) {
83027185Sminshall 				ncc = read(net, netibuf, sizeof (netibuf));
83127983Sminshall 				if (sequenceIs(didnetreceive, gotDM)) {
83227185Sminshall 				    SYNCHing = stilloob(net);
83327185Sminshall 				}
83427185Sminshall 			    }
83527185Sminshall 			} else {
83627185Sminshall 			    ncc = read(net, netibuf, sizeof (netibuf));
8376002Sroot 			}
83827185Sminshall 		    } else {
83927185Sminshall 			ncc = read(net, netibuf, sizeof (netibuf));
84027185Sminshall 		    }
84127185Sminshall 		    settimer(didnetreceive);
84227649Sminshall #else	/* !defined(SO_OOBINLINE)) */
84327185Sminshall 		    ncc = read(net, netibuf, sizeof (netibuf));
84427649Sminshall #endif	/* !defined(SO_OOBINLINE)) */
84527185Sminshall 		    if (ncc < 0 && errno == EWOULDBLOCK)
84627185Sminshall 			ncc = 0;
84727185Sminshall 		    else {
84827185Sminshall 			if (ncc <= 0) {
84927185Sminshall 			    break;
85027185Sminshall 			}
85127185Sminshall 			netip = netibuf;
85227185Sminshall 		    }
853*44363Sborman #ifdef DIAGNOSTICS
854*44363Sborman 		    if (diagnostic & (TD_REPORT | TD_NETDATA)) {
855*44363Sborman 			    sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
856*44363Sborman 			    nfrontp += strlen(nfrontp);
857*44363Sborman 		    }
858*44363Sborman 		    if (diagnostic & TD_NETDATA) {
859*44363Sborman 			    printdata("nd", netip, ncc);
860*44363Sborman 		    }
861*44363Sborman #endif /* DIAGNOSTICS */
8626002Sroot 		}
8636002Sroot 
8646002Sroot 		/*
8656002Sroot 		 * Something to read from the pty...
8666002Sroot 		 */
86738904Sborman 		if (FD_ISSET(p, &ibits)) {
8686002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
8696002Sroot 			if (pcc < 0 && errno == EWOULDBLOCK)
8706002Sroot 				pcc = 0;
8716002Sroot 			else {
8726002Sroot 				if (pcc <= 0)
8736002Sroot 					break;
87440242Sborman #if	!defined(CRAY2) || !defined(UNICOS5)
87538904Sborman #ifdef	LINEMODE
87638904Sborman 				/*
87738904Sborman 				 * If ioctl from pty, pass it through net
87838904Sborman 				 */
87938904Sborman 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
88038904Sborman 					copy_termbuf(ptyibuf+1, pcc-1);
88138904Sborman 					localstat();
88238904Sborman 					pcc = 1;
88338904Sborman 				}
88438904Sborman #endif	LINEMODE
88537210Sminshall 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
88638904Sborman 					netclear();	/* clear buffer back */
88740242Sborman #ifdef	notdef
88840242Sborman 					/*
88940242Sborman 					 * We really should have this in, but
89040242Sborman 					 * there are client telnets on some
89140242Sborman 					 * operating systems get screwed up
89240242Sborman 					 * royally if we send them urgent
89340242Sborman 					 * mode data.  So, for now, we'll not
89440242Sborman 					 * do this...
89540242Sborman 					 */
89637210Sminshall 					*nfrontp++ = IAC;
89737210Sminshall 					*nfrontp++ = DM;
89837210Sminshall 					neturg = nfrontp-1; /* off by one XXX */
89940242Sborman #endif
90037210Sminshall 				}
901*44363Sborman 				if (his_state_is_will(TELOPT_LFLOW) &&
90237210Sminshall 				    (ptyibuf[0] &
90338904Sborman 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
90438904Sborman 					(void) sprintf(nfrontp, "%c%c%c%c%c%c",
90537210Sminshall 					    IAC, SB, TELOPT_LFLOW,
90637210Sminshall 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
90737210Sminshall 					    IAC, SE);
90837210Sminshall 					nfrontp += 6;
90937210Sminshall 				}
91033267Sminshall 				pcc--;
91133267Sminshall 				ptyip = ptyibuf+1;
91240242Sborman #else	/* defined(CRAY2) && defined(UNICOS5) */
91338904Sborman 				if (!uselinemode) {
91439531Sborman 					unpcc = pcc;
91539531Sborman 					unptyip = ptyibuf;
91639531Sborman 					pcc = term_output(&unptyip, ptyibuf2,
91739531Sborman 								&unpcc, BUFSIZ);
91838904Sborman 					ptyip = ptyibuf2;
91938904Sborman 				} else
92038904Sborman 					ptyip = ptyibuf;
92140242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
92238904Sborman 			}
9236002Sroot 		}
9246002Sroot 
9256002Sroot 		while (pcc > 0) {
9266002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
9276002Sroot 				break;
9286002Sroot 			c = *ptyip++ & 0377, pcc--;
9296002Sroot 			if (c == IAC)
9306002Sroot 				*nfrontp++ = c;
93140242Sborman #if	defined(CRAY2) && defined(UNICOS5)
93238904Sborman 			else if (c == '\n' &&
933*44363Sborman 				     my_state_is_wont(TELOPT_BINARY) && newmap)
93438904Sborman 				*nfrontp++ = '\r';
93540242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
9366002Sroot 			*nfrontp++ = c;
937*44363Sborman 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
93827020Sminshall 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
93927020Sminshall 					*nfrontp++ = *ptyip++ & 0377;
94027020Sminshall 					pcc--;
94127020Sminshall 				} else
94227020Sminshall 					*nfrontp++ = '\0';
94327020Sminshall 			}
9446002Sroot 		}
94540242Sborman #if	defined(CRAY2) && defined(UNICOS5)
94639531Sborman 		/*
94739531Sborman 		 * If chars were left over from the terminal driver,
94839531Sborman 		 * note their existence.
94939531Sborman 		 */
95039531Sborman 		 if (!uselinemode && unpcc) {
95139531Sborman 			pcc = unpcc;
95239531Sborman 			unpcc = 0;
95339531Sborman 			ptyip = unptyip;
95439531Sborman 		}
95540242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
95639531Sborman 
95727185Sminshall 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
9586002Sroot 			netflush();
9596002Sroot 		if (ncc > 0)
9606002Sroot 			telrcv();
96127185Sminshall 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
9626002Sroot 			ptyflush();
9636002Sroot 	}
9646002Sroot 	cleanup();
96538904Sborman }  /* end of telnet */
9666002Sroot 
96738904Sborman #ifndef	TCSIG
96838904Sborman # ifdef	TIOCSIG
96938904Sborman #  define TCSIG TIOCSIG
97038904Sborman # endif
97138904Sborman #endif
9726002Sroot 
97337212Sminshall /*
9746002Sroot  * Send interrupt to process on other side of pty.
9756002Sroot  * If it is in raw mode, just write NULL;
9766002Sroot  * otherwise, write intr char.
9776002Sroot  */
9786002Sroot interrupt()
9796002Sroot {
98038904Sborman 	ptyflush();	/* half-hearted */
9816002Sroot 
98238904Sborman #ifdef	TCSIG
98338904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
98438904Sborman #else	/* TCSIG */
98538904Sborman 	init_termbuf();
98640242Sborman 	*pfrontp++ = slctab[SLC_IP].sptr ?
98740242Sborman 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
98838904Sborman #endif	/* TCSIG */
9896002Sroot }
9906002Sroot 
99127229Sminshall /*
99227229Sminshall  * Send quit to process on other side of pty.
99327229Sminshall  * If it is in raw mode, just write NULL;
99427229Sminshall  * otherwise, write quit char.
99527229Sminshall  */
99627229Sminshall sendbrk()
99727229Sminshall {
99827229Sminshall 	ptyflush();	/* half-hearted */
99938904Sborman #ifdef	TCSIG
100038904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
100138904Sborman #else	/* TCSIG */
100238904Sborman 	init_termbuf();
100340242Sborman 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
100440242Sborman 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
100538904Sborman #endif	/* TCSIG */
100627229Sminshall }
100727229Sminshall 
100838904Sborman sendsusp()
10096002Sroot {
101038904Sborman #ifdef	SIGTSTP
101138904Sborman 	ptyflush();	/* half-hearted */
101238904Sborman # ifdef	TCSIG
101338904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
101438904Sborman # else	/* TCSIG */
101540242Sborman 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
101640242Sborman 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
101738904Sborman # endif	/* TCSIG */
101838904Sborman #endif	/* SIGTSTP */
10196002Sroot }
10206002Sroot 
102138904Sborman doeof()
10226002Sroot {
102340242Sborman #if	defined(USE_TERMIO) && defined(SYSV_TERMIO)
102440242Sborman 	extern char oldeofc;
102540242Sborman #endif
102638904Sborman 	init_termbuf();
10276002Sroot 
102840242Sborman #if	defined(USE_TERMIO) && defined(SYSV_TERMIO)
102940242Sborman 	if (!tty_isediting()) {
103040242Sborman 		*pfrontp++ = oldeofc;
103140242Sborman 		return;
103240242Sborman 	}
103340242Sborman #endif
103440242Sborman 	*pfrontp++ = slctab[SLC_EOF].sptr ?
103540242Sborman 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
10366002Sroot }
1037