xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 68346)
121182Sdist /*
261451Sbostic  * Copyright (c) 1989, 1993
361451Sbostic  *	The Regents of the University of California.  All rights reserved.
433687Sbostic  *
542673Sbostic  * %sccs.include.redist.c%
621182Sdist  */
721182Sdist 
86295Sroot #ifndef lint
961451Sbostic static char copyright[] =
1061451Sbostic "@(#) Copyright (c) 1989, 1993\n\
1161451Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1233687Sbostic #endif /* not lint */
136295Sroot 
1421182Sdist #ifndef lint
15*68346Sdab static char sccsid[] = "@(#)telnetd.c	8.3 (Berkeley) 02/16/95";
1633687Sbostic #endif /* not lint */
1721182Sdist 
1838904Sborman #include "telnetd.h"
1945234Sborman #include "pathnames.h"
2038904Sborman 
2160151Sdab #if	defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
2260151Sdab /*
2360151Sdab  * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
2460151Sdab  * use it to tell us to turn off all the socket security code,
2560151Sdab  * since that is only used in UNICOS 7.0 and later.
2660151Sdab  */
2760151Sdab # undef _SC_CRAY_SECURE_SYS
2860151Sdab #endif
2960151Sdab 
3057212Sdab #if	defined(_SC_CRAY_SECURE_SYS)
3157212Sdab #include <sys/sysv.h>
3257212Sdab #include <sys/secdev.h>
3360151Sdab # ifdef SO_SEC_MULTI		/* 8.0 code */
3460151Sdab #include <sys/secparm.h>
3560151Sdab #include <sys/usrv.h>
3660151Sdab # endif /* SO_SEC_MULTI */
3757212Sdab int	secflag;
3857212Sdab char	tty_dev[16];
3957212Sdab struct	secdev dv;
4057212Sdab struct	sysv sysv;
4160151Sdab # ifdef SO_SEC_MULTI		/* 8.0 code */
4260151Sdab struct	socksec ss;
4360151Sdab # else /* SO_SEC_MULTI */	/* 7.0 code */
4457212Sdab struct	socket_security ss;
4560151Sdab # endif /* SO_SEC_MULTI */
4657212Sdab #endif	/* _SC_CRAY_SECURE_SYS */
4757212Sdab 
4857212Sdab #if	defined(AUTHENTICATION)
4946809Sdab #include <libtelnet/auth.h>
5046809Sdab int	auth_level = 0;
5146809Sdab #endif
5246809Sdab #if	defined(SecurID)
5346809Sdab int	require_SecurID = 0;
5446809Sdab #endif
5546809Sdab 
5657212Sdab extern	int utmp_len;
5757212Sdab int	registerd_host_only = 0;
5857212Sdab 
5957212Sdab #ifdef	STREAMSPTY
6057212Sdab # include <stropts.h>
6157212Sdab # include <termio.h>
6257212Sdab /* make sure we don't get the bsd version */
6357212Sdab # include "/usr/include/sys/tty.h"
6457212Sdab # include <sys/ptyvar.h>
6557212Sdab 
666002Sroot /*
6757212Sdab  * Because of the way ptyibuf is used with streams messages, we need
6857212Sdab  * ptyibuf+1 to be on a full-word boundary.  The following wierdness
6957212Sdab  * is simply to make that happen.
7057212Sdab  */
7165158Sdab long	ptyibufbuf[BUFSIZ/sizeof(long)+1];
7265158Sdab char	*ptyibuf = ((char *)&ptyibufbuf[1])-1;
7365158Sdab char	*ptyip = ((char *)&ptyibufbuf[1])-1;
7457212Sdab char	ptyibuf2[BUFSIZ];
7557212Sdab unsigned char ctlbuf[BUFSIZ];
7657212Sdab struct	strbuf strbufc, strbufd;
7757212Sdab 
7857212Sdab int readstream();
7957212Sdab 
8057212Sdab #else	/* ! STREAMPTY */
8157212Sdab 
8257212Sdab /*
8338904Sborman  * I/O data buffers,
8438904Sborman  * pointers, and counters.
856002Sroot  */
8638904Sborman char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
8738904Sborman char	ptyibuf2[BUFSIZ];
889218Ssam 
8957212Sdab #endif /* ! STREAMPTY */
9057212Sdab 
9138904Sborman int	hostinfo = 1;			/* do we print login banner? */
929218Ssam 
9338904Sborman #ifdef	CRAY
9438904Sborman extern int      newmap; /* nonzero if \n maps to ^M^J */
9540242Sborman int	lowpty = 0, highpty;	/* low, high pty numbers */
9638904Sborman #endif /* CRAY */
9712216Ssam 
9838904Sborman int debug = 0;
9946809Sdab int keepalive = 1;
10038904Sborman char *progname;
1019218Ssam 
10246809Sdab extern void usage P((void));
10344363Sborman 
10460151Sdab /*
10560151Sdab  * The string to pass to getopt().  We do it this way so
10660151Sdab  * that only the actual options that we support will be
10760151Sdab  * passed off to getopt().
10860151Sdab  */
10960151Sdab char valid_opts[] = {
11060151Sdab 	'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
11160151Sdab #ifdef	AUTHENTICATION
11260151Sdab 	'a', ':', 'X', ':',
11360151Sdab #endif
11460151Sdab #ifdef BFTPDAEMON
11560151Sdab 	'B',
11660151Sdab #endif
11760151Sdab #ifdef DIAGNOSTICS
11860151Sdab 	'D', ':',
11960151Sdab #endif
12060151Sdab #ifdef	ENCRYPTION
12160151Sdab 	'e', ':',
12260151Sdab #endif
12360151Sdab #if	defined(CRAY) && defined(NEWINIT)
12460151Sdab 	'I', ':',
12560151Sdab #endif
12660151Sdab #ifdef	LINEMODE
12760151Sdab 	'l',
12860151Sdab #endif
12960151Sdab #ifdef CRAY
13060151Sdab 	'r', ':',
13160151Sdab #endif
13260151Sdab #ifdef	SecurID
13360151Sdab 	's',
13460151Sdab #endif
13560151Sdab 	'\0'
13660151Sdab };
13760151Sdab 
13838904Sborman main(argc, argv)
13938904Sborman 	char *argv[];
14038904Sborman {
14138904Sborman 	struct sockaddr_in from;
14238904Sborman 	int on = 1, fromlen;
14346809Sdab 	register int ch;
14446809Sdab 	extern char *optarg;
14546809Sdab 	extern int optind;
14646809Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
14746809Sdab 	int tos = -1;
14846809Sdab #endif
1496002Sroot 
15038904Sborman 	pfrontp = pbackp = ptyobuf;
15138904Sborman 	netip = netibuf;
15238904Sborman 	nfrontp = nbackp = netobuf;
15360151Sdab #ifdef	ENCRYPTION
15446809Sdab 	nclearto = 0;
15560151Sdab #endif	/* ENCRYPTION */
1566002Sroot 
15738904Sborman 	progname = *argv;
15840242Sborman 
15940242Sborman #ifdef CRAY
16040242Sborman 	/*
16140242Sborman 	 * Get number of pty's before trying to process options,
16240242Sborman 	 * which may include changing pty range.
16340242Sborman 	 */
16440242Sborman 	highpty = getnpty();
16540242Sborman #endif /* CRAY */
16640242Sborman 
16760151Sdab 	while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
16846809Sdab 		switch(ch) {
16927649Sminshall 
17057212Sdab #ifdef	AUTHENTICATION
17146809Sdab 		case 'a':
17246809Sdab 			/*
17346809Sdab 			 * Check for required authentication level
17446809Sdab 			 */
17546809Sdab 			if (strcmp(optarg, "debug") == 0) {
17646809Sdab 				extern int auth_debug_mode;
17746809Sdab 				auth_debug_mode = 1;
17846809Sdab 			} else if (strcasecmp(optarg, "none") == 0) {
17946809Sdab 				auth_level = 0;
18046809Sdab 			} else if (strcasecmp(optarg, "other") == 0) {
18146809Sdab 				auth_level = AUTH_OTHER;
18246809Sdab 			} else if (strcasecmp(optarg, "user") == 0) {
18346809Sdab 				auth_level = AUTH_USER;
18446809Sdab 			} else if (strcasecmp(optarg, "valid") == 0) {
18546809Sdab 				auth_level = AUTH_VALID;
18646809Sdab 			} else if (strcasecmp(optarg, "off") == 0) {
18746809Sdab 				/*
18846809Sdab 				 * This hack turns off authentication
18946809Sdab 				 */
19046809Sdab 				auth_level = -1;
19146809Sdab 			} else {
19246809Sdab 				fprintf(stderr,
19346809Sdab 			    "telnetd: unknown authorization level for -a\n");
19446809Sdab 			}
19546809Sdab 			break;
19657212Sdab #endif	/* AUTHENTICATION */
19727649Sminshall 
19846809Sdab #ifdef BFTPDAEMON
19946809Sdab 		case 'B':
20046809Sdab 			bftpd++;
20146809Sdab 			break;
20246809Sdab #endif /* BFTPDAEMON */
20346809Sdab 
20446809Sdab 		case 'd':
20546809Sdab 			if (strcmp(optarg, "ebug") == 0) {
20646809Sdab 				debug++;
20746809Sdab 				break;
20846809Sdab 			}
20946809Sdab 			usage();
21046809Sdab 			/* NOTREACHED */
21146809Sdab 			break;
21246809Sdab 
21346809Sdab #ifdef DIAGNOSTICS
21446809Sdab 		case 'D':
21546809Sdab 			/*
21646809Sdab 			 * Check for desired diagnostics capabilities.
21746809Sdab 			 */
21846809Sdab 			if (!strcmp(optarg, "report")) {
21946809Sdab 				diagnostic |= TD_REPORT|TD_OPTIONS;
22046809Sdab 			} else if (!strcmp(optarg, "exercise")) {
22146809Sdab 				diagnostic |= TD_EXERCISE;
22246809Sdab 			} else if (!strcmp(optarg, "netdata")) {
22346809Sdab 				diagnostic |= TD_NETDATA;
22446809Sdab 			} else if (!strcmp(optarg, "ptydata")) {
22546809Sdab 				diagnostic |= TD_PTYDATA;
22646809Sdab 			} else if (!strcmp(optarg, "options")) {
22746809Sdab 				diagnostic |= TD_OPTIONS;
22846809Sdab 			} else {
22946809Sdab 				usage();
23046809Sdab 				/* NOT REACHED */
23146809Sdab 			}
23246809Sdab 			break;
23346809Sdab #endif /* DIAGNOSTICS */
23446809Sdab 
23557212Sdab #ifdef	ENCRYPTION
23646809Sdab 		case 'e':
23746809Sdab 			if (strcmp(optarg, "debug") == 0) {
23846809Sdab 				extern int encrypt_debug_mode;
23946809Sdab 				encrypt_debug_mode = 1;
24046809Sdab 				break;
24146809Sdab 			}
24246809Sdab 			usage();
24346809Sdab 			/* NOTREACHED */
24446809Sdab 			break;
24557212Sdab #endif	/* ENCRYPTION */
24646809Sdab 
24746809Sdab 		case 'h':
24846809Sdab 			hostinfo = 0;
24946809Sdab 			break;
25046809Sdab 
25146809Sdab #if	defined(CRAY) && defined(NEWINIT)
25246809Sdab 		case 'I':
25346809Sdab 		    {
25446809Sdab 			extern char *gen_id;
25546809Sdab 			gen_id = optarg;
25646809Sdab 			break;
25746809Sdab 		    }
25846809Sdab #endif	/* defined(CRAY) && defined(NEWINIT) */
25946809Sdab 
26038904Sborman #ifdef	LINEMODE
26146809Sdab 		case 'l':
26246809Sdab 			alwayslinemode = 1;
26346809Sdab 			break;
26438904Sborman #endif	/* LINEMODE */
26527649Sminshall 
26657212Sdab 		case 'k':
26757212Sdab #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
26857212Sdab 			lmodetype = NO_AUTOKLUDGE;
26957212Sdab #else
27057212Sdab 			/* ignore -k option if built without kludge linemode */
27157212Sdab #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
27257212Sdab 			break;
27357212Sdab 
27446809Sdab 		case 'n':
27546809Sdab 			keepalive = 0;
27646809Sdab 			break;
27727649Sminshall 
27845234Sborman #ifdef CRAY
27946809Sdab 		case 'r':
28046809Sdab 		    {
28146809Sdab 			char *strchr();
28246809Sdab 			char *c;
28327649Sminshall 
28446809Sdab 			/*
28546809Sdab 			 * Allow the specification of alterations
28646809Sdab 			 * to the pty search range.  It is legal to
28746809Sdab 			 * specify only one, and not change the
28846809Sdab 			 * other from its default.
28946809Sdab 			 */
29046809Sdab 			c = strchr(optarg, '-');
29146809Sdab 			if (c) {
29246809Sdab 				*c++ = '\0';
29346809Sdab 				highpty = atoi(c);
29444363Sborman 			}
29546809Sdab 			if (*optarg != '\0')
29646809Sdab 				lowpty = atoi(optarg);
29746809Sdab 			if ((lowpty > highpty) || (lowpty < 0) ||
29846809Sdab 							(highpty > 32767)) {
29944363Sborman 				usage();
30044363Sborman 				/* NOT REACHED */
30144363Sborman 			}
30246809Sdab 			break;
30346809Sdab 		    }
30438904Sborman #endif	/* CRAY */
3056002Sroot 
30646809Sdab #ifdef	SecurID
30746809Sdab 		case 's':
30846809Sdab 			/* SecurID required */
30946809Sdab 			require_SecurID = 1;
31046809Sdab 			break;
31146809Sdab #endif	/* SecurID */
31246809Sdab 		case 'S':
31346809Sdab #ifdef	HAS_GETTOS
31446809Sdab 			if ((tos = parsetos(optarg, "tcp")) < 0)
31546809Sdab 				fprintf(stderr, "%s%s%s\n",
31646809Sdab 					"telnetd: Bad TOS argument '", optarg,
31746809Sdab 					"'; will try to use default TOS");
31846809Sdab #else
31946809Sdab 			fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
32046809Sdab 						"-S flag not supported\n");
32146809Sdab #endif
32246809Sdab 			break;
32346809Sdab 
32457212Sdab 		case 'u':
32557212Sdab 			utmp_len = atoi(optarg);
32657212Sdab 			break;
32757212Sdab 
32857212Sdab 		case 'U':
32957212Sdab 			registerd_host_only = 1;
33057212Sdab 			break;
33157212Sdab 
33257212Sdab #ifdef	AUTHENTICATION
33346809Sdab 		case 'X':
33446809Sdab 			/*
33546809Sdab 			 * Check for invalid authentication types
33646809Sdab 			 */
33746809Sdab 			auth_disable_name(optarg);
33846809Sdab 			break;
33957212Sdab #endif	/* AUTHENTICATION */
34046809Sdab 
34146809Sdab 		default:
34260151Sdab 			fprintf(stderr, "telnetd: %c: unknown option\n", ch);
34346809Sdab 			/* FALLTHROUGH */
34446809Sdab 		case '?':
34544363Sborman 			usage();
34646809Sdab 			/* NOTREACHED */
34744363Sborman 		}
34844363Sborman 	}
34944363Sborman 
35046809Sdab 	argc -= optind;
35146809Sdab 	argv += optind;
35244363Sborman 
35338904Sborman 	if (debug) {
35427185Sminshall 	    int s, ns, foo;
35527185Sminshall 	    struct servent *sp;
35627185Sminshall 	    static struct sockaddr_in sin = { AF_INET };
35727185Sminshall 
35844363Sborman 	    if (argc > 1) {
35944363Sborman 		usage();
36044363Sborman 		/* NOT REACHED */
36144363Sborman 	    } else if (argc == 1) {
36238904Sborman 		    if (sp = getservbyname(*argv, "tcp")) {
36338904Sborman 			sin.sin_port = sp->s_port;
36438904Sborman 		    } else {
36538904Sborman 			sin.sin_port = atoi(*argv);
36638904Sborman 			if ((int)sin.sin_port <= 0) {
36738904Sborman 			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
36844363Sborman 			    usage();
36944363Sborman 			    /* NOT REACHED */
37038904Sborman 			}
37138904Sborman 			sin.sin_port = htons((u_short)sin.sin_port);
37238904Sborman 		   }
37337210Sminshall 	    } else {
37437210Sminshall 		sp = getservbyname("telnet", "tcp");
37537210Sminshall 		if (sp == 0) {
37644363Sborman 		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
37738904Sborman 		    exit(1);
37837210Sminshall 		}
37937210Sminshall 		sin.sin_port = sp->s_port;
38027185Sminshall 	    }
38127185Sminshall 
38227185Sminshall 	    s = socket(AF_INET, SOCK_STREAM, 0);
38327185Sminshall 	    if (s < 0) {
38427185Sminshall 		    perror("telnetd: socket");;
38527185Sminshall 		    exit(1);
38627185Sminshall 	    }
38757212Sdab 	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
38857212Sdab 				(char *)&on, sizeof(on));
38938904Sborman 	    if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
39027185Sminshall 		perror("bind");
39127185Sminshall 		exit(1);
39227185Sminshall 	    }
39327185Sminshall 	    if (listen(s, 1) < 0) {
39427185Sminshall 		perror("listen");
39527185Sminshall 		exit(1);
39627185Sminshall 	    }
39727185Sminshall 	    foo = sizeof sin;
39838904Sborman 	    ns = accept(s, (struct sockaddr *)&sin, &foo);
39927185Sminshall 	    if (ns < 0) {
40027185Sminshall 		perror("accept");
40127185Sminshall 		exit(1);
40227185Sminshall 	    }
40338904Sborman 	    (void) dup2(ns, 0);
40438904Sborman 	    (void) close(ns);
40538904Sborman 	    (void) close(s);
40646809Sdab #ifdef convex
40746809Sdab 	} else if (argc == 1) {
40846809Sdab 		; /* VOID*/		/* Just ignore the host/port name */
40946809Sdab #endif
41044363Sborman 	} else if (argc > 0) {
41144363Sborman 		usage();
41244363Sborman 		/* NOT REACHED */
41327185Sminshall 	}
41438904Sborman 
41557212Sdab #if	defined(_SC_CRAY_SECURE_SYS)
41657212Sdab 	secflag = sysconf(_SC_CRAY_SECURE_SYS);
41757212Sdab 
41857212Sdab 	/*
41960151Sdab 	 *	Get socket's security label
42057212Sdab 	 */
42157212Sdab 	if (secflag)  {
42260151Sdab 		int szss = sizeof(ss);
42360151Sdab #ifdef SO_SEC_MULTI			/* 8.0 code */
42460151Sdab 		int sock_multi;
42560151Sdab 		int szi = sizeof(int);
42660151Sdab #endif /* SO_SEC_MULTI */
42757212Sdab 
42857212Sdab 		bzero((char *)&dv, sizeof(dv));
42957212Sdab 
43057212Sdab 		if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
43157212Sdab 			perror("getsysv");
43257212Sdab 			exit(1);
43357212Sdab 		}
43457212Sdab 
43557212Sdab 		/*
43660151Sdab 		 *	Get socket security label and set device values
43760151Sdab 		 *	   {security label to be set on ttyp device}
43857212Sdab 		 */
43960151Sdab #ifdef SO_SEC_MULTI			/* 8.0 code */
44060151Sdab 		if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
44160151Sdab 			       (char *)&ss, &szss) < 0) ||
44260151Sdab 		    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
44360151Sdab 				(char *)&sock_multi, &szi) < 0)) {
44460151Sdab 			perror("getsockopt");
44560151Sdab 			exit(1);
44660151Sdab 		} else {
44760151Sdab 			dv.dv_actlvl = ss.ss_actlabel.lt_level;
44860151Sdab 			dv.dv_actcmp = ss.ss_actlabel.lt_compart;
44960151Sdab 			if (!sock_multi) {
45060151Sdab 				dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
45160151Sdab 				dv.dv_valcmp = dv.dv_actcmp;
45260151Sdab 			} else {
45360151Sdab 				dv.dv_minlvl = ss.ss_minlabel.lt_level;
45460151Sdab 				dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
45560151Sdab 				dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
45660151Sdab 			}
45760151Sdab 			dv.dv_devflg = 0;
45860151Sdab 		}
45960151Sdab #else /* SO_SEC_MULTI */		/* 7.0 code */
46057212Sdab 		if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
46160151Sdab 				(char *)&ss, &szss) >= 0) {
46257212Sdab 			dv.dv_actlvl = ss.ss_slevel;
46357212Sdab 			dv.dv_actcmp = ss.ss_compart;
46457212Sdab 			dv.dv_minlvl = ss.ss_minlvl;
46557212Sdab 			dv.dv_maxlvl = ss.ss_maxlvl;
46657212Sdab 			dv.dv_valcmp = ss.ss_maxcmp;
46757212Sdab 		}
46860151Sdab #endif /* SO_SEC_MULTI */
46957212Sdab 	}
47057212Sdab #endif	/* _SC_CRAY_SECURE_SYS */
47157212Sdab 
47224855Seric 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
47316371Skarels 	fromlen = sizeof (from);
47438904Sborman 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
47538904Sborman 		fprintf(stderr, "%s: ", progname);
47616371Skarels 		perror("getpeername");
47716371Skarels 		_exit(1);
4788346Ssam 	}
47946809Sdab 	if (keepalive &&
48057212Sdab 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
48157212Sdab 			(char *)&on, sizeof (on)) < 0) {
48217187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
48310418Ssam 	}
48440242Sborman 
48546809Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
48646809Sdab 	{
48746809Sdab # if	defined(HAS_GETTOS)
48846809Sdab 		struct tosent *tp;
48946809Sdab 		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
49046809Sdab 			tos = tp->t_tos;
49146809Sdab # endif
49246809Sdab 		if (tos < 0)
49346809Sdab 			tos = 020;	/* Low Delay bit */
49446809Sdab 		if (tos
49557212Sdab 		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
49657212Sdab 				  (char *)&tos, sizeof(tos)) < 0)
49746809Sdab 		   && (errno != ENOPROTOOPT) )
49846809Sdab 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
49946809Sdab 	}
50046809Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
50138904Sborman 	net = 0;
50238904Sborman 	doit(&from);
50338904Sborman 	/* NOTREACHED */
50438904Sborman }  /* end of main */
5056002Sroot 
50646809Sdab 	void
50744363Sborman usage()
50844363Sborman {
50946809Sdab 	fprintf(stderr, "Usage: telnetd");
51057212Sdab #ifdef	AUTHENTICATION
51160151Sdab 	fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
51246809Sdab #endif
51346809Sdab #ifdef BFTPDAEMON
51446809Sdab 	fprintf(stderr, " [-B]");
51546809Sdab #endif
51646809Sdab 	fprintf(stderr, " [-debug]");
51746809Sdab #ifdef DIAGNOSTICS
51846809Sdab 	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
51946809Sdab #endif
52057212Sdab #ifdef	AUTHENTICATION
52146809Sdab 	fprintf(stderr, " [-edebug]");
52246809Sdab #endif
52346809Sdab 	fprintf(stderr, " [-h]");
52446809Sdab #if	defined(CRAY) && defined(NEWINIT)
52544363Sborman 	fprintf(stderr, " [-Iinitid]");
52646809Sdab #endif
52760151Sdab #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
52860151Sdab 	fprintf(stderr, " [-k]");
52960151Sdab #endif
53044363Sborman #ifdef LINEMODE
53144363Sborman 	fprintf(stderr, " [-l]");
53244363Sborman #endif
53346809Sdab 	fprintf(stderr, " [-n]");
53444363Sborman #ifdef	CRAY
53544363Sborman 	fprintf(stderr, " [-r[lowpty]-[highpty]]");
53644363Sborman #endif
53760151Sdab 	fprintf(stderr, "\n\t");
53846809Sdab #ifdef	SecurID
53946809Sdab 	fprintf(stderr, " [-s]");
54046809Sdab #endif
54160151Sdab #ifdef	HAS_GETTOS
54260151Sdab 	fprintf(stderr, " [-S tos]");
54360151Sdab #endif
54457212Sdab #ifdef	AUTHENTICATION
54546809Sdab 	fprintf(stderr, " [-X auth-type]");
54646809Sdab #endif
54757212Sdab 	fprintf(stderr, " [-u utmp_hostname_length] [-U]");
54844363Sborman 	fprintf(stderr, " [port]\n");
54944363Sborman 	exit(1);
55044363Sborman }
55144363Sborman 
55227649Sminshall /*
55327983Sminshall  * getterminaltype
55427649Sminshall  *
55538904Sborman  *	Ask the other end to send along its terminal type and speed.
55627983Sminshall  * Output is the variable terminaltype filled in.
55727649Sminshall  */
55865158Sdab static unsigned char ttytype_sbbuf[] = {
55965158Sdab 	IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
56065158Sdab };
56146809Sdab 
56246809Sdab     int
56346809Sdab getterminaltype(name)
56446809Sdab     char *name;
56527649Sminshall {
56646809Sdab     int retval = -1;
56746809Sdab     void _gettermname();
56827649Sminshall 
56938904Sborman     settimer(baseline);
57057212Sdab #if	defined(AUTHENTICATION)
57146809Sdab     /*
57246809Sdab      * Handle the Authentication option before we do anything else.
57346809Sdab      */
57446809Sdab     send_do(TELOPT_AUTHENTICATION, 1);
57546809Sdab     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
57646809Sdab 	ttloop();
57746809Sdab     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
57846809Sdab 	retval = auth_wait(name);
57946809Sdab     }
58046809Sdab #endif
58146809Sdab 
58260151Sdab #ifdef	ENCRYPTION
58346809Sdab     send_will(TELOPT_ENCRYPT, 1);
58460151Sdab #endif	/* ENCRYPTION */
58539503Sborman     send_do(TELOPT_TTYPE, 1);
58639503Sborman     send_do(TELOPT_TSPEED, 1);
58744363Sborman     send_do(TELOPT_XDISPLOC, 1);
58865158Sdab     send_do(TELOPT_NEW_ENVIRON, 1);
58965158Sdab     send_do(TELOPT_OLD_ENVIRON, 1);
59046809Sdab     while (
59160151Sdab #ifdef	ENCRYPTION
59246809Sdab 	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
59360151Sdab #endif	/* ENCRYPTION */
59446809Sdab 	   his_will_wont_is_changing(TELOPT_TTYPE) ||
59544363Sborman 	   his_will_wont_is_changing(TELOPT_TSPEED) ||
59644363Sborman 	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
59765158Sdab 	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
59865158Sdab 	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
59927983Sminshall 	ttloop();
60027649Sminshall     }
60160151Sdab #ifdef	ENCRYPTION
60246809Sdab     /*
60346809Sdab      * Wait for the negotiation of what type of encryption we can
60446809Sdab      * send with.  If autoencrypt is not set, this will just return.
60546809Sdab      */
60646809Sdab     if (his_state_is_will(TELOPT_ENCRYPT)) {
60746809Sdab 	encrypt_wait();
60846809Sdab     }
60960151Sdab #endif	/* ENCRYPTION */
61044363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
61165158Sdab 	static unsigned char sb[] =
61265158Sdab 			{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
61327983Sminshall 
61465158Sdab 	bcopy(sb, nfrontp, sizeof sb);
61565158Sdab 	nfrontp += sizeof sb;
61638904Sborman     }
61744363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
61865158Sdab 	static unsigned char sb[] =
61965158Sdab 			{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
62038904Sborman 
62165158Sdab 	bcopy(sb, nfrontp, sizeof sb);
62265158Sdab 	nfrontp += sizeof sb;
62344363Sborman     }
62465158Sdab     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
62565158Sdab 	static unsigned char sb[] =
62665158Sdab 			{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
62744363Sborman 
62865158Sdab 	bcopy(sb, nfrontp, sizeof sb);
62965158Sdab 	nfrontp += sizeof sb;
63044363Sborman     }
63165158Sdab     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
63265158Sdab 	static unsigned char sb[] =
63365158Sdab 			{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
63465158Sdab 
63565158Sdab 	bcopy(sb, nfrontp, sizeof sb);
63665158Sdab 	nfrontp += sizeof sb;
63765158Sdab     }
63844363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
63944363Sborman 
64038904Sborman 	bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
64138904Sborman 	nfrontp += sizeof ttytype_sbbuf;
64238904Sborman     }
64344363Sborman     if (his_state_is_will(TELOPT_TSPEED)) {
64438904Sborman 	while (sequenceIs(tspeedsubopt, baseline))
64527983Sminshall 	    ttloop();
64638904Sborman     }
64744363Sborman     if (his_state_is_will(TELOPT_XDISPLOC)) {
64844363Sborman 	while (sequenceIs(xdisplocsubopt, baseline))
64944363Sborman 	    ttloop();
65044363Sborman     }
65165158Sdab     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
65244363Sborman 	while (sequenceIs(environsubopt, baseline))
65344363Sborman 	    ttloop();
65444363Sborman     }
65565158Sdab     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
65665158Sdab 	while (sequenceIs(oenvironsubopt, baseline))
65765158Sdab 	    ttloop();
65865158Sdab     }
65944363Sborman     if (his_state_is_will(TELOPT_TTYPE)) {
66038904Sborman 	char first[256], last[256];
66138904Sborman 
66238904Sborman 	while (sequenceIs(ttypesubopt, baseline))
66338904Sborman 	    ttloop();
66438904Sborman 
66544363Sborman 	/*
66644363Sborman 	 * If the other side has already disabled the option, then
66744363Sborman 	 * we have to just go with what we (might) have already gotten.
66844363Sborman 	 */
66944363Sborman 	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
67038904Sborman 	    (void) strncpy(first, terminaltype, sizeof(first));
67138904Sborman 	    for(;;) {
67238904Sborman 		/*
67338904Sborman 		 * Save the unknown name, and request the next name.
67438904Sborman 		 */
67538904Sborman 		(void) strncpy(last, terminaltype, sizeof(last));
67638904Sborman 		_gettermname();
67744363Sborman 		if (terminaltypeok(terminaltype))
67838904Sborman 		    break;
67944363Sborman 		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
68044363Sborman 		    his_state_is_wont(TELOPT_TTYPE)) {
68138904Sborman 		    /*
68238904Sborman 		     * We've hit the end.  If this is the same as
68338904Sborman 		     * the first name, just go with it.
68438904Sborman 		     */
68545234Sborman 		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
68638904Sborman 			break;
68738904Sborman 		    /*
68844363Sborman 		     * Get the terminal name one more time, so that
68938904Sborman 		     * RFC1091 compliant telnets will cycle back to
69038904Sborman 		     * the start of the list.
69138904Sborman 		     */
69244363Sborman 		     _gettermname();
69345234Sborman 		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
69438904Sborman 			(void) strncpy(terminaltype, first, sizeof(first));
69538904Sborman 		    break;
69638904Sborman 		}
69738904Sborman 	    }
69827983Sminshall 	}
69927983Sminshall     }
70046809Sdab     return(retval);
70138904Sborman }  /* end of getterminaltype */
70238904Sborman 
70346809Sdab     void
70438904Sborman _gettermname()
70538904Sborman {
70644363Sborman     /*
70744363Sborman      * If the client turned off the option,
70844363Sborman      * we can't send another request, so we
70944363Sborman      * just return.
71044363Sborman      */
71144363Sborman     if (his_state_is_wont(TELOPT_TTYPE))
71244363Sborman 	return;
71338904Sborman     settimer(baseline);
71438904Sborman     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
71538904Sborman     nfrontp += sizeof ttytype_sbbuf;
71638904Sborman     while (sequenceIs(ttypesubopt, baseline))
71738904Sborman 	ttloop();
71827649Sminshall }
71927649Sminshall 
72046809Sdab     int
72138904Sborman terminaltypeok(s)
72246809Sdab     char *s;
72338904Sborman {
72438904Sborman     char buf[1024];
72538904Sborman 
72638904Sborman     if (terminaltype == NULL)
72738904Sborman 	return(1);
72838904Sborman 
72938904Sborman     /*
73038904Sborman      * tgetent() will return 1 if the type is known, and
73138904Sborman      * 0 if it is not known.  If it returns -1, it couldn't
73238904Sborman      * open the database.  But if we can't open the database,
73338904Sborman      * it won't help to say we failed, because we won't be
73438904Sborman      * able to verify anything else.  So, we treat -1 like 1.
73538904Sborman      */
73638904Sborman     if (tgetent(buf, s) == 0)
73738904Sborman 	return(0);
73838904Sborman     return(1);
73938904Sborman }
74038904Sborman 
74146809Sdab #ifndef	MAXHOSTNAMELEN
74246809Sdab #define	MAXHOSTNAMELEN 64
74346809Sdab #endif	/* MAXHOSTNAMELEN */
74446809Sdab 
74546809Sdab char *hostname;
74646809Sdab char host_name[MAXHOSTNAMELEN];
74746809Sdab char remote_host_name[MAXHOSTNAMELEN];
74846809Sdab 
74946809Sdab #ifndef	convex
75046809Sdab extern void telnet P((int, int));
75146809Sdab #else
75246809Sdab extern void telnet P((int, int, char *));
75346809Sdab #endif
75446809Sdab 
7556002Sroot /*
7566002Sroot  * Get a pty, scan input lines.
7576002Sroot  */
75838904Sborman doit(who)
75912683Ssam 	struct sockaddr_in *who;
7606002Sroot {
76120188Skarels 	char *host, *inet_ntoa();
76238904Sborman 	int t;
76312683Ssam 	struct hostent *hp;
76446809Sdab 	int level;
76560151Sdab 	int ptynum;
76646809Sdab 	char user_name[256];
7676002Sroot 
76838904Sborman 	/*
76938904Sborman 	 * Find an available pty to use.
77038904Sborman 	 */
77145234Sborman #ifndef	convex
77260151Sdab 	pty = getpty(&ptynum);
77338904Sborman 	if (pty < 0)
77438904Sborman 		fatal(net, "All network ports in use");
77545234Sborman #else
77645234Sborman 	for (;;) {
77745234Sborman 		char *lp;
77845234Sborman 		extern char *line, *getpty();
77920188Skarels 
78045234Sborman 		if ((lp = getpty()) == NULL)
78145234Sborman 			fatal(net, "Out of ptys");
78245234Sborman 
78345234Sborman 		if ((pty = open(lp, 2)) >= 0) {
78445234Sborman 			strcpy(line,lp);
78545234Sborman 			line[5] = 't';
78645234Sborman 			break;
78745234Sborman 		}
78845234Sborman 	}
78944545Smarc #endif
79038904Sborman 
79157212Sdab #if	defined(_SC_CRAY_SECURE_SYS)
79257212Sdab 	/*
79357212Sdab 	 *	set ttyp line security label
79457212Sdab 	 */
79557212Sdab 	if (secflag) {
79660151Sdab 		char slave_dev[16];
79760151Sdab 
79860151Sdab 		sprintf(tty_dev, "/dev/pty/%03d", ptynum);
79960151Sdab 		if (setdevs(tty_dev, &dv) < 0)
80060151Sdab 		 	fatal(net, "cannot set pty security");
80160151Sdab 		sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
80260151Sdab 		if (setdevs(slave_dev, &dv) < 0)
80360151Sdab 		 	fatal(net, "cannot set tty security");
80457212Sdab 	}
80557212Sdab #endif	/* _SC_CRAY_SECURE_SYS */
80657212Sdab 
80738904Sborman 	/* get name of connected client */
80838904Sborman 	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
80912683Ssam 		who->sin_family);
81057212Sdab 
81157641Sdab 	if (hp == NULL && registerd_host_only) {
81257641Sdab 		fatal(net, "Couldn't resolve your address into a host name.\r\n\
81357641Sdab          Please contact your net administrator");
81457641Sdab 	} else if (hp &&
81557212Sdab 	    (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
81612683Ssam 		host = hp->h_name;
81757212Sdab 	} else {
81817444Sralph 		host = inet_ntoa(who->sin_addr);
81957212Sdab 	}
82046809Sdab 	/*
82146809Sdab 	 * We must make a copy because Kerberos is probably going
82246809Sdab 	 * to also do a gethost* and overwrite the static data...
82346809Sdab 	 */
82446809Sdab 	strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
82546809Sdab 	remote_host_name[sizeof(remote_host_name)-1] = 0;
82646809Sdab 	host = remote_host_name;
82727983Sminshall 
82846809Sdab 	(void) gethostname(host_name, sizeof (host_name));
82946809Sdab 	hostname = host_name;
83046809Sdab 
83157212Sdab #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
83246809Sdab 	auth_encrypt_init(hostname, host, "TELNETD", 1);
83346809Sdab #endif
83446809Sdab 
83544363Sborman 	init_env();
83627983Sminshall 	/*
83738904Sborman 	 * get terminal type.
83827983Sminshall 	 */
83946809Sdab 	*user_name = 0;
84046809Sdab 	level = getterminaltype(user_name);
84144363Sborman 	setenv("TERM", terminaltype ? terminaltype : "network", 1);
84227983Sminshall 
84327649Sminshall 	/*
84438904Sborman 	 * Start up the login process on the slave side of the terminal
84527649Sminshall 	 */
84645234Sborman #ifndef	convex
84746809Sdab 	startslave(host, level, user_name);
84838904Sborman 
84960151Sdab #if	defined(_SC_CRAY_SECURE_SYS)
85060151Sdab 	if (secflag) {
85160151Sdab 		if (setulvl(dv.dv_actlvl) < 0)
85260151Sdab 			fatal(net,"cannot setulvl()");
85360151Sdab 		if (setucmp(dv.dv_actcmp) < 0)
85460151Sdab 			fatal(net, "cannot setucmp()");
85560151Sdab 	}
85660151Sdab #endif	/* _SC_CRAY_SECURE_SYS */
85760151Sdab 
85838904Sborman 	telnet(net, pty);  /* begin server processing */
85945234Sborman #else
86045234Sborman 	telnet(net, pty, host);
86145234Sborman #endif
8629244Ssam 	/*NOTREACHED*/
86338904Sborman }  /* end of doit */
8649244Ssam 
86546809Sdab #if	defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
86646809Sdab 	int
86746809Sdab Xterm_output(ibufp, obuf, icountp, ocount)
86846809Sdab 	char **ibufp, *obuf;
86946809Sdab 	int *icountp, ocount;
87046809Sdab {
87146809Sdab 	int ret;
87246809Sdab 	ret = term_output(*ibufp, obuf, *icountp, ocount);
87346809Sdab 	*ibufp += *icountp;
87446809Sdab 	*icountp = 0;
87546809Sdab 	return(ret);
87646809Sdab }
87746809Sdab #define	term_output	Xterm_output
87846809Sdab #endif	/* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
87946809Sdab 
8806002Sroot /*
8816002Sroot  * Main loop.  Select from pty and network, and
8826002Sroot  * hand data to telnet receiver finite state machine.
8836002Sroot  */
88446809Sdab 	void
88545234Sborman #ifndef	convex
8866002Sroot telnet(f, p)
88745234Sborman #else
88845234Sborman telnet(f, p, host)
88945234Sborman #endif
89046809Sdab 	int f, p;
89145234Sborman #ifdef convex
89246809Sdab 	char *host;
89345234Sborman #endif
8946002Sroot {
8956002Sroot 	int on = 1;
89633271Sminshall #define	TABBUFSIZ	512
89733271Sminshall 	char	defent[TABBUFSIZ];
89833271Sminshall 	char	defstrs[TABBUFSIZ];
89933271Sminshall #undef	TABBUFSIZ
90033271Sminshall 	char *HE;
90133271Sminshall 	char *HN;
90233271Sminshall 	char *IM;
90338904Sborman 	void netflush();
904*68346Sdab 	int nfd;
90546809Sdab 
90632400Sminshall 	/*
90738904Sborman 	 * Initialize the slc mapping table.
90832400Sminshall 	 */
90938904Sborman 	get_slc_defaults();
9106002Sroot 
9118379Ssam 	/*
91238904Sborman 	 * Do some tests where it is desireable to wait for a response.
91338904Sborman 	 * Rather than doing them slowly, one at a time, do them all
91438904Sborman 	 * at once.
9158379Ssam 	 */
91644363Sborman 	if (my_state_is_wont(TELOPT_SGA))
91739503Sborman 		send_will(TELOPT_SGA, 1);
91812713Ssam 	/*
91927649Sminshall 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
92027649Sminshall 	 * because 4.2 clients are unable to deal with TCP urgent data.
92127649Sminshall 	 *
92227649Sminshall 	 * To find out, we send out a "DO ECHO".  If the remote system
92327649Sminshall 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
92427649Sminshall 	 * that fact ("WILL ECHO" ==> that the client will echo what
92527649Sminshall 	 * WE, the server, sends it; it does NOT mean that the client will
92627649Sminshall 	 * echo the terminal input).
92727649Sminshall 	 */
92839503Sborman 	send_do(TELOPT_ECHO, 1);
92927649Sminshall 
93038904Sborman #ifdef	LINEMODE
93144363Sborman 	if (his_state_is_wont(TELOPT_LINEMODE)) {
93238904Sborman 		/* Query the peer for linemode support by trying to negotiate
93338904Sborman 		 * the linemode option.
93438904Sborman 		 */
93544363Sborman 		linemode = 0;
93638904Sborman 		editmode = 0;
93739503Sborman 		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
93838904Sborman 	}
93938904Sborman #endif	/* LINEMODE */
94038904Sborman 
94127649Sminshall 	/*
94238904Sborman 	 * Send along a couple of other options that we wish to negotiate.
94338904Sborman 	 */
94439503Sborman 	send_do(TELOPT_NAWS, 1);
94539503Sborman 	send_will(TELOPT_STATUS, 1);
94657597Sdab 	flowmode = 1;		/* default flow control state */
94757597Sdab 	restartany = -1;	/* uninitialized... */
94839503Sborman 	send_do(TELOPT_LFLOW, 1);
94938904Sborman 
95038904Sborman 	/*
95138904Sborman 	 * Spin, waiting for a response from the DO ECHO.  However,
95238904Sborman 	 * some REALLY DUMB telnets out there might not respond
95338904Sborman 	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
95438904Sborman 	 * telnets so far seem to respond with WONT for a DO that
95538904Sborman 	 * they don't understand...) because by the time we get the
95638904Sborman 	 * response, it will already have processed the DO ECHO.
95738904Sborman 	 * Kludge upon kludge.
95838904Sborman 	 */
95944363Sborman 	while (his_will_wont_is_changing(TELOPT_NAWS))
96038904Sborman 		ttloop();
96138904Sborman 
96238904Sborman 	/*
96344363Sborman 	 * But...
96444363Sborman 	 * The client might have sent a WILL NAWS as part of its
96544363Sborman 	 * startup code; if so, we'll be here before we get the
96644363Sborman 	 * response to the DO ECHO.  We'll make the assumption
96744363Sborman 	 * that any implementation that understands about NAWS
96844363Sborman 	 * is a modern enough implementation that it will respond
96944363Sborman 	 * to our DO ECHO request; hence we'll do another spin
97044363Sborman 	 * waiting for the ECHO option to settle down, which is
97144363Sborman 	 * what we wanted to do in the first place...
97244363Sborman 	 */
97344363Sborman 	if (his_want_state_is_will(TELOPT_ECHO) &&
97444363Sborman 	    his_state_is_will(TELOPT_NAWS)) {
97544363Sborman 		while (his_will_wont_is_changing(TELOPT_ECHO))
97644363Sborman 			ttloop();
97744363Sborman 	}
97844363Sborman 	/*
97938995Sborman 	 * On the off chance that the telnet client is broken and does not
98038995Sborman 	 * respond to the DO ECHO we sent, (after all, we did send the
98138995Sborman 	 * DO NAWS negotiation after the DO ECHO, and we won't get here
98238995Sborman 	 * until a response to the DO NAWS comes back) simulate the
98338995Sborman 	 * receipt of a will echo.  This will also send a WONT ECHO
98438995Sborman 	 * to the client, since we assume that the client failed to
98538995Sborman 	 * respond because it believes that it is already in DO ECHO
98638995Sborman 	 * mode, which we do not want.
98738995Sborman 	 */
98844363Sborman 	if (his_want_state_is_will(TELOPT_ECHO)) {
98946809Sdab 		DIAG(TD_OPTIONS,
99046809Sdab 			{sprintf(nfrontp, "td: simulating recv\r\n");
99146809Sdab 			 nfrontp += strlen(nfrontp);});
99239503Sborman 		willoption(TELOPT_ECHO);
99340242Sborman 	}
99438995Sborman 
99538995Sborman 	/*
99638995Sborman 	 * Finally, to clean things up, we turn on our echo.  This
99738995Sborman 	 * will break stupid 4.2 telnets out of local terminal echo.
99838995Sborman 	 */
99938995Sborman 
100044363Sborman 	if (my_state_is_wont(TELOPT_ECHO))
100139503Sborman 		send_will(TELOPT_ECHO, 1);
100238995Sborman 
100357212Sdab #ifndef	STREAMSPTY
100438995Sborman 	/*
100545234Sborman 	 * Turn on packet mode
100638904Sborman 	 */
100738904Sborman 	(void) ioctl(p, TIOCPKT, (char *)&on);
100857212Sdab #endif
100957212Sdab 
101046809Sdab #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
101138904Sborman 	/*
101238904Sborman 	 * Continuing line mode support.  If client does not support
101338904Sborman 	 * real linemode, attempt to negotiate kludge linemode by sending
101438904Sborman 	 * the do timing mark sequence.
101538904Sborman 	 */
101638904Sborman 	if (lmodetype < REAL_LINEMODE)
101739503Sborman 		send_do(TELOPT_TM, 1);
101846809Sdab #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
101938904Sborman 
102038904Sborman 	/*
102138904Sborman 	 * Call telrcv() once to pick up anything received during
102238904Sborman 	 * terminal type negotiation, 4.2/4.3 determination, and
102338904Sborman 	 * linemode negotiation.
102438904Sborman 	 */
102538904Sborman 	telrcv();
102638904Sborman 
102738904Sborman 	(void) ioctl(f, FIONBIO, (char *)&on);
102838904Sborman 	(void) ioctl(p, FIONBIO, (char *)&on);
102940242Sborman #if	defined(CRAY2) && defined(UNICOS5)
103038904Sborman 	init_termdriver(f, p, interrupt, sendbrk);
103138904Sborman #endif
103238904Sborman 
103338904Sborman #if	defined(SO_OOBINLINE)
103457212Sdab 	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
103557212Sdab 				(char *)&on, sizeof on);
103638904Sborman #endif	/* defined(SO_OOBINLINE) */
103738904Sborman 
103838904Sborman #ifdef	SIGTSTP
103938904Sborman 	(void) signal(SIGTSTP, SIG_IGN);
104038904Sborman #endif
104138904Sborman #ifdef	SIGTTOU
104238904Sborman 	/*
104338904Sborman 	 * Ignoring SIGTTOU keeps the kernel from blocking us
104438904Sborman 	 * in ttioct() in /sys/tty.c.
104538904Sborman 	 */
104638904Sborman 	(void) signal(SIGTTOU, SIG_IGN);
104738904Sborman #endif
104838904Sborman 
104938904Sborman 	(void) signal(SIGCHLD, cleanup);
105038904Sborman 
105140242Sborman #if	defined(CRAY2) && defined(UNICOS5)
105238904Sborman 	/*
105338904Sborman 	 * Cray-2 will send a signal when pty modes are changed by slave
105438904Sborman 	 * side.  Set up signal handler now.
105538904Sborman 	 */
105638904Sborman 	if ((int)signal(SIGUSR1, termstat) < 0)
105738904Sborman 		perror("signal");
105838904Sborman 	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
105938904Sborman 		perror("ioctl:TCSIGME");
106038904Sborman 	/*
106138904Sborman 	 * Make processing loop check terminal characteristics early on.
106238904Sborman 	 */
106338904Sborman 	termstat();
106438904Sborman #endif
106538904Sborman 
106645234Sborman #ifdef  TIOCNOTTY
106745234Sborman 	{
106845234Sborman 		register int t;
106945234Sborman 		t = open(_PATH_TTY, O_RDWR);
107045234Sborman 		if (t >= 0) {
107145234Sborman 			(void) ioctl(t, TIOCNOTTY, (char *)0);
107245234Sborman 			(void) close(t);
107345234Sborman 		}
107445234Sborman 	}
107540242Sborman #endif
107645234Sborman 
107746809Sdab #if	defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
107845234Sborman 	(void) setsid();
107944363Sborman 	ioctl(p, TIOCSCTTY, 0);
108044363Sborman #endif
108138904Sborman 
108238904Sborman 	/*
108312713Ssam 	 * Show banner that getty never gave.
108427797Sminshall 	 *
108533271Sminshall 	 * We put the banner in the pty input buffer.  This way, it
108633271Sminshall 	 * gets carriage return null processing, etc., just like all
108733271Sminshall 	 * other pty --> client data.
108812713Ssam 	 */
108927797Sminshall 
109045234Sborman #if	!defined(CRAY) || !defined(NEWINIT)
109145234Sborman 	if (getenv("USER"))
109245234Sborman 		hostinfo = 0;
109345234Sborman #endif
109438904Sborman 
109533271Sminshall 	if (getent(defent, "default") == 1) {
109633271Sminshall 		char *getstr();
109738904Sborman 		char *cp=defstrs;
109827649Sminshall 
109938904Sborman 		HE = getstr("he", &cp);
110038904Sborman 		HN = getstr("hn", &cp);
110138904Sborman 		IM = getstr("im", &cp);
110233271Sminshall 		if (HN && *HN)
110346809Sdab 			(void) strcpy(host_name, HN);
110438904Sborman 		if (IM == 0)
110538904Sborman 			IM = "";
110633271Sminshall 	} else {
110745234Sborman 		IM = DEFAULT_IM;
110838904Sborman 		HE = 0;
110933271Sminshall 	}
111046809Sdab 	edithost(HE, host_name);
111145234Sborman 	if (hostinfo && *IM)
111238904Sborman 		putf(IM, ptyibuf2);
111327797Sminshall 
111438904Sborman 	if (pcc)
111538904Sborman 		(void) strncat(ptyibuf2, ptyip, pcc+1);
111638904Sborman 	ptyip = ptyibuf2;
111738904Sborman 	pcc = strlen(ptyip);
111840242Sborman #ifdef	LINEMODE
111940242Sborman 	/*
112040242Sborman 	 * Last check to make sure all our states are correct.
112140242Sborman 	 */
112240242Sborman 	init_termbuf();
112340242Sborman 	localstat();
112440242Sborman #endif	/* LINEMODE */
112533271Sminshall 
112646809Sdab 	DIAG(TD_REPORT,
112746809Sdab 		{sprintf(nfrontp, "td: Entering processing loop\r\n");
112846809Sdab 		 nfrontp += strlen(nfrontp);});
112944363Sborman 
113045234Sborman #ifdef	convex
113145234Sborman 	startslave(host);
113245234Sborman #endif
113345234Sborman 
1134*68346Sdab 	nfd = ((f > p) ? f : p) + 1;
11356002Sroot 	for (;;) {
113627185Sminshall 		fd_set ibits, obits, xbits;
11376002Sroot 		register int c;
11386002Sroot 
113927185Sminshall 		if (ncc < 0 && pcc < 0)
114027185Sminshall 			break;
114127185Sminshall 
114240242Sborman #if	defined(CRAY2) && defined(UNICOS5)
114338904Sborman 		if (needtermstat)
114438904Sborman 			_termstat();
114540242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
114627185Sminshall 		FD_ZERO(&ibits);
114727185Sminshall 		FD_ZERO(&obits);
114827185Sminshall 		FD_ZERO(&xbits);
11496002Sroot 		/*
11506002Sroot 		 * Never look for input if there's still
11516002Sroot 		 * stuff in the corresponding output buffer
11526002Sroot 		 */
115327185Sminshall 		if (nfrontp - nbackp || pcc > 0) {
115427185Sminshall 			FD_SET(f, &obits);
115527185Sminshall 		} else {
115627185Sminshall 			FD_SET(p, &ibits);
115727185Sminshall 		}
115827185Sminshall 		if (pfrontp - pbackp || ncc > 0) {
115927185Sminshall 			FD_SET(p, &obits);
116027185Sminshall 		} else {
116127185Sminshall 			FD_SET(f, &ibits);
116227185Sminshall 		}
116327185Sminshall 		if (!SYNCHing) {
116427185Sminshall 			FD_SET(f, &xbits);
116527185Sminshall 		}
1166*68346Sdab 		if ((c = select(nfd, &ibits, &obits, &xbits,
116727185Sminshall 						(struct timeval *)0)) < 1) {
116827185Sminshall 			if (c == -1) {
116927185Sminshall 				if (errno == EINTR) {
117027185Sminshall 					continue;
117127185Sminshall 				}
117227185Sminshall 			}
11736002Sroot 			sleep(5);
11746002Sroot 			continue;
11756002Sroot 		}
11766002Sroot 
11776002Sroot 		/*
117827185Sminshall 		 * Any urgent data?
117927185Sminshall 		 */
118027185Sminshall 		if (FD_ISSET(net, &xbits)) {
118127185Sminshall 		    SYNCHing = 1;
118227185Sminshall 		}
118327185Sminshall 
118427185Sminshall 		/*
11856002Sroot 		 * Something to read from the network...
11866002Sroot 		 */
118727185Sminshall 		if (FD_ISSET(net, &ibits)) {
118827649Sminshall #if	!defined(SO_OOBINLINE)
118927185Sminshall 			/*
119027898Skarels 			 * In 4.2 (and 4.3 beta) systems, the
119127185Sminshall 			 * OOB indication and data handling in the kernel
119227185Sminshall 			 * is such that if two separate TCP Urgent requests
119327185Sminshall 			 * come in, one byte of TCP data will be overlaid.
119427185Sminshall 			 * This is fatal for Telnet, but we try to live
119527185Sminshall 			 * with it.
119627185Sminshall 			 *
119727185Sminshall 			 * In addition, in 4.2 (and...), a special protocol
119827185Sminshall 			 * is needed to pick up the TCP Urgent data in
119927185Sminshall 			 * the correct sequence.
120027185Sminshall 			 *
120127185Sminshall 			 * What we do is:  if we think we are in urgent
120227185Sminshall 			 * mode, we look to see if we are "at the mark".
120327185Sminshall 			 * If we are, we do an OOB receive.  If we run
120427185Sminshall 			 * this twice, we will do the OOB receive twice,
120527185Sminshall 			 * but the second will fail, since the second
120627185Sminshall 			 * time we were "at the mark", but there wasn't
120727185Sminshall 			 * any data there (the kernel doesn't reset
120827185Sminshall 			 * "at the mark" until we do a normal read).
120927185Sminshall 			 * Once we've read the OOB data, we go ahead
121027185Sminshall 			 * and do normal reads.
121127185Sminshall 			 *
121227185Sminshall 			 * There is also another problem, which is that
121327185Sminshall 			 * since the OOB byte we read doesn't put us
121427185Sminshall 			 * out of OOB state, and since that byte is most
121527185Sminshall 			 * likely the TELNET DM (data mark), we would
121627185Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
121727185Sminshall 			 * So, clocks to the rescue.  If we've "just"
121827185Sminshall 			 * received a DM, then we test for the
121927185Sminshall 			 * presence of OOB data when the receive OOB
122027185Sminshall 			 * fails (and AFTER we did the normal mode read
122127185Sminshall 			 * to clear "at the mark").
122227185Sminshall 			 */
122327185Sminshall 		    if (SYNCHing) {
122427185Sminshall 			int atmark;
122527185Sminshall 
122638904Sborman 			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
122727185Sminshall 			if (atmark) {
122827185Sminshall 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
122927185Sminshall 			    if ((ncc == -1) && (errno == EINVAL)) {
123027185Sminshall 				ncc = read(net, netibuf, sizeof (netibuf));
123127983Sminshall 				if (sequenceIs(didnetreceive, gotDM)) {
123227185Sminshall 				    SYNCHing = stilloob(net);
123327185Sminshall 				}
123427185Sminshall 			    }
123527185Sminshall 			} else {
123627185Sminshall 			    ncc = read(net, netibuf, sizeof (netibuf));
12376002Sroot 			}
123827185Sminshall 		    } else {
123927185Sminshall 			ncc = read(net, netibuf, sizeof (netibuf));
124027185Sminshall 		    }
124127185Sminshall 		    settimer(didnetreceive);
124227649Sminshall #else	/* !defined(SO_OOBINLINE)) */
124327185Sminshall 		    ncc = read(net, netibuf, sizeof (netibuf));
124427649Sminshall #endif	/* !defined(SO_OOBINLINE)) */
124527185Sminshall 		    if (ncc < 0 && errno == EWOULDBLOCK)
124627185Sminshall 			ncc = 0;
124727185Sminshall 		    else {
124827185Sminshall 			if (ncc <= 0) {
124927185Sminshall 			    break;
125027185Sminshall 			}
125127185Sminshall 			netip = netibuf;
125227185Sminshall 		    }
125346809Sdab 		    DIAG((TD_REPORT | TD_NETDATA),
125446809Sdab 			    {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
125546809Sdab 			     nfrontp += strlen(nfrontp);});
125646809Sdab 		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
12576002Sroot 		}
12586002Sroot 
12596002Sroot 		/*
12606002Sroot 		 * Something to read from the pty...
12616002Sroot 		 */
126238904Sborman 		if (FD_ISSET(p, &ibits)) {
126357212Sdab #ifndef	STREAMSPTY
12646002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
126557212Sdab #else
126657212Sdab 			pcc = readstream(p, ptyibuf, BUFSIZ);
126757212Sdab #endif
126846809Sdab 			/*
126946809Sdab 			 * On some systems, if we try to read something
127046809Sdab 			 * off the master side before the slave side is
127146809Sdab 			 * opened, we get EIO.
127246809Sdab 			 */
127357212Sdab 			if (pcc < 0 && (errno == EWOULDBLOCK ||
127457212Sdab #ifdef	EAGAIN
127557212Sdab 					errno == EAGAIN ||
127657212Sdab #endif
127757212Sdab 					errno == EIO)) {
12786002Sroot 				pcc = 0;
127946809Sdab 			} else {
12806002Sroot 				if (pcc <= 0)
12816002Sroot 					break;
128240242Sborman #if	!defined(CRAY2) || !defined(UNICOS5)
128338904Sborman #ifdef	LINEMODE
128438904Sborman 				/*
128538904Sborman 				 * If ioctl from pty, pass it through net
128638904Sborman 				 */
128738904Sborman 				if (ptyibuf[0] & TIOCPKT_IOCTL) {
128838904Sborman 					copy_termbuf(ptyibuf+1, pcc-1);
128938904Sborman 					localstat();
129038904Sborman 					pcc = 1;
129138904Sborman 				}
129246809Sdab #endif	/* LINEMODE */
129337210Sminshall 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
129438904Sborman 					netclear();	/* clear buffer back */
129545234Sborman #ifndef	NO_URGENT
129640242Sborman 					/*
129745234Sborman 					 * There are client telnets on some
129840242Sborman 					 * operating systems get screwed up
129940242Sborman 					 * royally if we send them urgent
130045234Sborman 					 * mode data.
130140242Sborman 					 */
130237210Sminshall 					*nfrontp++ = IAC;
130337210Sminshall 					*nfrontp++ = DM;
130437210Sminshall 					neturg = nfrontp-1; /* off by one XXX */
130540242Sborman #endif
130637210Sminshall 				}
130744363Sborman 				if (his_state_is_will(TELOPT_LFLOW) &&
130837210Sminshall 				    (ptyibuf[0] &
130938904Sborman 				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
131057597Sdab 					int newflow =
131157597Sdab 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
131257597Sdab 					if (newflow != flowmode) {
131357597Sdab 						flowmode = newflow;
131457597Sdab 						(void) sprintf(nfrontp,
131557597Sdab 							"%c%c%c%c%c%c",
131657597Sdab 							IAC, SB, TELOPT_LFLOW,
131757597Sdab 							flowmode ? LFLOW_ON
131857597Sdab 								 : LFLOW_OFF,
131957597Sdab 							IAC, SE);
132057597Sdab 						nfrontp += 6;
132157597Sdab 					}
132237210Sminshall 				}
132333267Sminshall 				pcc--;
132433267Sminshall 				ptyip = ptyibuf+1;
132540242Sborman #else	/* defined(CRAY2) && defined(UNICOS5) */
132638904Sborman 				if (!uselinemode) {
132739531Sborman 					unpcc = pcc;
132839531Sborman 					unptyip = ptyibuf;
132939531Sborman 					pcc = term_output(&unptyip, ptyibuf2,
133039531Sborman 								&unpcc, BUFSIZ);
133138904Sborman 					ptyip = ptyibuf2;
133238904Sborman 				} else
133338904Sborman 					ptyip = ptyibuf;
133440242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
133538904Sborman 			}
13366002Sroot 		}
13376002Sroot 
13386002Sroot 		while (pcc > 0) {
13396002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
13406002Sroot 				break;
13416002Sroot 			c = *ptyip++ & 0377, pcc--;
13426002Sroot 			if (c == IAC)
13436002Sroot 				*nfrontp++ = c;
134440242Sborman #if	defined(CRAY2) && defined(UNICOS5)
134538904Sborman 			else if (c == '\n' &&
134644363Sborman 				     my_state_is_wont(TELOPT_BINARY) && newmap)
134738904Sborman 				*nfrontp++ = '\r';
134840242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
13496002Sroot 			*nfrontp++ = c;
135044363Sborman 			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
135127020Sminshall 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
135227020Sminshall 					*nfrontp++ = *ptyip++ & 0377;
135327020Sminshall 					pcc--;
135427020Sminshall 				} else
135527020Sminshall 					*nfrontp++ = '\0';
135627020Sminshall 			}
13576002Sroot 		}
135840242Sborman #if	defined(CRAY2) && defined(UNICOS5)
135939531Sborman 		/*
136039531Sborman 		 * If chars were left over from the terminal driver,
136139531Sborman 		 * note their existence.
136239531Sborman 		 */
136346809Sdab 		if (!uselinemode && unpcc) {
136439531Sborman 			pcc = unpcc;
136539531Sborman 			unpcc = 0;
136639531Sborman 			ptyip = unptyip;
136739531Sborman 		}
136840242Sborman #endif	/* defined(CRAY2) && defined(UNICOS5) */
136939531Sborman 
137027185Sminshall 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
13716002Sroot 			netflush();
13726002Sroot 		if (ncc > 0)
13736002Sroot 			telrcv();
137427185Sminshall 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
13756002Sroot 			ptyflush();
13766002Sroot 	}
137746809Sdab 	cleanup(0);
137838904Sborman }  /* end of telnet */
13796002Sroot 
138038904Sborman #ifndef	TCSIG
138138904Sborman # ifdef	TIOCSIG
138238904Sborman #  define TCSIG TIOCSIG
138338904Sborman # endif
138438904Sborman #endif
13856002Sroot 
138657212Sdab #ifdef	STREAMSPTY
138757212Sdab 
138857212Sdab int flowison = -1;  /* current state of flow: -1 is unknown */
138957212Sdab 
139057212Sdab int readstream(p, ibuf, bufsize)
139157212Sdab 	int p;
139257212Sdab 	char *ibuf;
139357212Sdab 	int bufsize;
139457212Sdab {
139557212Sdab 	int flags = 0;
139657212Sdab 	int ret = 0;
139757212Sdab 	struct termios *tsp;
139857212Sdab 	struct termio *tp;
139957212Sdab 	struct iocblk *ip;
140057212Sdab 	char vstop, vstart;
140157212Sdab 	int ixon;
140257212Sdab 	int newflow;
140357212Sdab 
140457212Sdab 	strbufc.maxlen = BUFSIZ;
140565158Sdab 	strbufc.buf = (char *)ctlbuf;
140657212Sdab 	strbufd.maxlen = bufsize-1;
140757212Sdab 	strbufd.len = 0;
140857212Sdab 	strbufd.buf = ibuf+1;
140957212Sdab 	ibuf[0] = 0;
141057212Sdab 
141157212Sdab 	ret = getmsg(p, &strbufc, &strbufd, &flags);
141257212Sdab 	if (ret < 0)  /* error of some sort -- probably EAGAIN */
141357212Sdab 		return(-1);
141457212Sdab 
141557212Sdab 	if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
141657212Sdab 		/* data message */
141757212Sdab 		if (strbufd.len > 0) {			/* real data */
141857212Sdab 			return(strbufd.len + 1);	/* count header char */
141957212Sdab 		} else {
142057212Sdab 			/* nothing there */
142157212Sdab 			errno = EAGAIN;
142257212Sdab 			return(-1);
142357212Sdab 		}
142457212Sdab 	}
142557212Sdab 
142657212Sdab 	/*
142757212Sdab 	 * It's a control message.  Return 1, to look at the flag we set
142857212Sdab 	 */
142957212Sdab 
143057212Sdab 	switch (ctlbuf[0]) {
143157212Sdab 	case M_FLUSH:
143257212Sdab 		if (ibuf[1] & FLUSHW)
143357212Sdab 			ibuf[0] = TIOCPKT_FLUSHWRITE;
143457212Sdab 		return(1);
143557212Sdab 
143657212Sdab 	case M_IOCTL:
143757212Sdab 		ip = (struct iocblk *) (ibuf+1);
143857212Sdab 
143957212Sdab 		switch (ip->ioc_cmd) {
144057212Sdab 		case TCSETS:
144157212Sdab 		case TCSETSW:
144257212Sdab 		case TCSETSF:
144357212Sdab 			tsp = (struct termios *)
144457212Sdab 					(ibuf+1 + sizeof(struct iocblk));
144557212Sdab 			vstop = tsp->c_cc[VSTOP];
144657212Sdab 			vstart = tsp->c_cc[VSTART];
144757212Sdab 			ixon = tsp->c_iflag & IXON;
144857212Sdab 			break;
144957212Sdab 		case TCSETA:
145057212Sdab 		case TCSETAW:
145157212Sdab 		case TCSETAF:
145257212Sdab 			tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
145357212Sdab 			vstop = tp->c_cc[VSTOP];
145457212Sdab 			vstart = tp->c_cc[VSTART];
145557212Sdab 			ixon = tp->c_iflag & IXON;
145657212Sdab 			break;
145757212Sdab 		default:
145857212Sdab 			errno = EAGAIN;
145957212Sdab 			return(-1);
146057212Sdab 		}
146157212Sdab 
146257212Sdab 		newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
146357212Sdab 		if (newflow != flowison) {  /* it's a change */
146457212Sdab 			flowison = newflow;
146557212Sdab 			ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
146657212Sdab 			return(1);
146757212Sdab 		}
146857212Sdab 	}
146957212Sdab 
147057212Sdab 	/* nothing worth doing anything about */
147157212Sdab 	errno = EAGAIN;
147257212Sdab 	return(-1);
147357212Sdab }
147457212Sdab #endif /* STREAMSPTY */
147557212Sdab 
147637212Sminshall /*
14776002Sroot  * Send interrupt to process on other side of pty.
14786002Sroot  * If it is in raw mode, just write NULL;
14796002Sroot  * otherwise, write intr char.
14806002Sroot  */
148146809Sdab 	void
14826002Sroot interrupt()
14836002Sroot {
148438904Sborman 	ptyflush();	/* half-hearted */
14856002Sroot 
1486*68346Sdab #if defined(STREAMSPTY) && defined(TIOCSIGNAL)
1487*68346Sdab 	/* Streams PTY style ioctl to post a signal */
1488*68346Sdab 	{
1489*68346Sdab 		int sig = SIGINT;
1490*68346Sdab 		(void) ioctl(pty, TIOCSIGNAL, &sig);
1491*68346Sdab 		(void) ioctl(pty, I_FLUSH, FLUSHR);
1492*68346Sdab 	}
1493*68346Sdab #else
149438904Sborman #ifdef	TCSIG
149538904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGINT);
149638904Sborman #else	/* TCSIG */
149738904Sborman 	init_termbuf();
149840242Sborman 	*pfrontp++ = slctab[SLC_IP].sptr ?
149940242Sborman 			(unsigned char)*slctab[SLC_IP].sptr : '\177';
150038904Sborman #endif	/* TCSIG */
1501*68346Sdab #endif
15026002Sroot }
15036002Sroot 
150427229Sminshall /*
150527229Sminshall  * Send quit to process on other side of pty.
150627229Sminshall  * If it is in raw mode, just write NULL;
150727229Sminshall  * otherwise, write quit char.
150827229Sminshall  */
150946809Sdab 	void
151027229Sminshall sendbrk()
151127229Sminshall {
151227229Sminshall 	ptyflush();	/* half-hearted */
151338904Sborman #ifdef	TCSIG
151438904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
151538904Sborman #else	/* TCSIG */
151638904Sborman 	init_termbuf();
151740242Sborman 	*pfrontp++ = slctab[SLC_ABORT].sptr ?
151840242Sborman 			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
151938904Sborman #endif	/* TCSIG */
152027229Sminshall }
152127229Sminshall 
152246809Sdab 	void
152338904Sborman sendsusp()
15246002Sroot {
152538904Sborman #ifdef	SIGTSTP
152638904Sborman 	ptyflush();	/* half-hearted */
152738904Sborman # ifdef	TCSIG
152838904Sborman 	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
152938904Sborman # else	/* TCSIG */
153040242Sborman 	*pfrontp++ = slctab[SLC_SUSP].sptr ?
153140242Sborman 			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
153238904Sborman # endif	/* TCSIG */
153338904Sborman #endif	/* SIGTSTP */
15346002Sroot }
15356002Sroot 
153645234Sborman /*
153745234Sborman  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
153845234Sborman  * just send back "[Yes]".
153945234Sborman  */
154046809Sdab 	void
154145234Sborman recv_ayt()
154245234Sborman {
154345234Sborman #if	defined(SIGINFO) && defined(TCSIG)
154445234Sborman 	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
154545234Sborman 		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
154645234Sborman 		return;
154745234Sborman 	}
154845234Sborman #endif
154945234Sborman 	(void) strcpy(nfrontp, "\r\n[Yes]\r\n");
155045234Sborman 	nfrontp += 9;
155145234Sborman }
155245234Sborman 
155346809Sdab 	void
155438904Sborman doeof()
15556002Sroot {
155638904Sborman 	init_termbuf();
15576002Sroot 
155845234Sborman #if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
155940242Sborman 	if (!tty_isediting()) {
156046809Sdab 		extern char oldeofc;
156140242Sborman 		*pfrontp++ = oldeofc;
156240242Sborman 		return;
156340242Sborman 	}
156440242Sborman #endif
156540242Sborman 	*pfrontp++ = slctab[SLC_EOF].sptr ?
156640242Sborman 			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
15676002Sroot }
1568