xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 13799)
16295Sroot #ifndef lint
2*13799Ssam static char sccsid[] = "@(#)telnetd.c	4.25 (Berkeley) 83/07/06";
36295Sroot #endif
46295Sroot 
56002Sroot /*
66002Sroot  * Stripped-down telnet server.
76002Sroot  */
89218Ssam #include <sys/types.h>
99218Ssam #include <sys/socket.h>
1013608Ssam #include <sys/wait.h>
119218Ssam 
129218Ssam #include <netinet/in.h>
139218Ssam 
1412216Ssam #include <arpa/telnet.h>
1512216Ssam 
166002Sroot #include <stdio.h>
176002Sroot #include <signal.h>
186002Sroot #include <errno.h>
196002Sroot #include <sgtty.h>
208346Ssam #include <netdb.h>
219218Ssam 
2213798Ssam #define	BELL	'\07'
2313798Ssam #define BANNER	"\r\n\r\n4.2 BSD UNIX (%s)\r\n\r\r\n\r%s"
246002Sroot 
256002Sroot char	hisopts[256];
266002Sroot char	myopts[256];
276002Sroot 
286002Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
296002Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
306002Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
316002Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
326002Sroot 
336002Sroot /*
346002Sroot  * I/O data buffers, pointers, and counters.
356002Sroot  */
366002Sroot char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
376002Sroot char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
386002Sroot char	netibuf[BUFSIZ], *netip = netibuf;
396388Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
406002Sroot int	pcc, ncc;
416002Sroot 
426002Sroot int	pty, net;
436002Sroot int	inter;
4410418Ssam int	reapchild();
45*13799Ssam extern	char **environ;
466002Sroot extern	int errno;
476002Sroot char	line[] = "/dev/ptyp0";
486002Sroot 
498346Ssam struct	sockaddr_in sin = { AF_INET };
506002Sroot 
516002Sroot main(argc, argv)
526002Sroot 	char *argv[];
536002Sroot {
5410418Ssam 	int s, pid, options;
558346Ssam 	struct servent *sp;
566002Sroot 
578346Ssam 	sp = getservbyname("telnet", "tcp");
588346Ssam 	if (sp == 0) {
598346Ssam 		fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
608346Ssam 		exit(1);
618346Ssam 	}
628346Ssam 	sin.sin_port = sp->s_port;
636002Sroot 	argc--, argv++;
6410418Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
6510418Ssam 		options |= SO_DEBUG;
6610418Ssam 		argc--, argv++;
6710418Ssam 	}
688346Ssam 	if (argc > 0) {
698346Ssam 		sin.sin_port = atoi(*argv);
708346Ssam 		if (sin.sin_port <= 0) {
718346Ssam 			fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
728346Ssam 			exit(1);
738346Ssam 		}
749969Ssam 		sin.sin_port = htons((u_short)sin.sin_port);
758346Ssam 	}
768456Ssam #ifndef DEBUG
778456Ssam 	if (fork())
788456Ssam 		exit(0);
798456Ssam 	for (s = 0; s < 10; s++)
808456Ssam 		(void) close(s);
818456Ssam 	(void) open("/", 0);
828456Ssam 	(void) dup2(0, 1);
838456Ssam 	(void) dup2(0, 2);
848456Ssam 	{ int tt = open("/dev/tty", 2);
858456Ssam 	  if (tt > 0) {
868456Ssam 		ioctl(tt, TIOCNOTTY, 0);
878456Ssam 		close(tt);
888456Ssam 	  }
898456Ssam 	}
908456Ssam #endif
919218Ssam again:
929288Ssam 	s = socket(AF_INET, SOCK_STREAM, 0, 0);
939218Ssam 	if (s < 0) {
949218Ssam 		perror("telnetd: socket");;
959218Ssam 		sleep(5);
969218Ssam 		goto again;
979218Ssam 	}
9810418Ssam 	if (options & SO_DEBUG)
9910418Ssam 		if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
10010418Ssam 			perror("telnetd: setsockopt (SO_DEBUG)");
10110418Ssam 	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
10210418Ssam 		perror("telnetd: setsockopt (SO_KEEPALIVE)");
1039218Ssam 	while (bind(s, (caddr_t)&sin, sizeof (sin), 0) < 0) {
1049218Ssam 		perror("telnetd: bind");
1059218Ssam 		sleep(5);
1069218Ssam 	}
10713028Ssam 	signal(SIGCHLD, reapchild);
1089218Ssam 	listen(s, 10);
1096002Sroot 	for (;;) {
11012683Ssam 		struct sockaddr_in from;
11112683Ssam 		int s2, fromlen = sizeof (from);
1129218Ssam 
11312683Ssam 		s2 = accept(s, (caddr_t)&from, &fromlen);
1149218Ssam 		if (s2 < 0) {
11510418Ssam 			if (errno == EINTR)
11610418Ssam 				continue;
1179244Ssam 			perror("telnetd: accept");
1186002Sroot 			sleep(1);
1196002Sroot 			continue;
1206002Sroot 		}
1216002Sroot 		if ((pid = fork()) < 0)
1226002Sroot 			printf("Out of processes\n");
12311221Ssam 		else if (pid == 0) {
12411221Ssam 			signal(SIGCHLD, SIG_IGN);
12512683Ssam 			doit(s2, &from);
12611221Ssam 		}
1279218Ssam 		close(s2);
1286002Sroot 	}
1296002Sroot 	/*NOTREACHED*/
1306002Sroot }
1316002Sroot 
13210418Ssam reapchild()
13310418Ssam {
13410418Ssam 	union wait status;
13510418Ssam 
13610418Ssam 	while (wait3(&status, WNOHANG, 0) > 0)
13710418Ssam 		;
13810418Ssam }
13910418Ssam 
140*13799Ssam char	*envinit[] = { "TERM=network", 0 };
1416002Sroot int	cleanup();
1426002Sroot 
1436002Sroot /*
1446002Sroot  * Get a pty, scan input lines.
1456002Sroot  */
14612683Ssam doit(f, who)
14712683Ssam 	int f;
14812683Ssam 	struct sockaddr_in *who;
1496002Sroot {
15012683Ssam 	char *cp = line, *host, *ntoa();
1516002Sroot 	int i, p, cc, t;
1526002Sroot 	struct sgttyb b;
15312683Ssam 	struct hostent *hp;
1546002Sroot 
1556002Sroot 	for (i = 0; i < 16; i++) {
1566002Sroot 		cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
1576002Sroot 		p = open(cp, 2);
1586002Sroot 		if (p > 0)
1596002Sroot 			goto gotpty;
1606002Sroot 	}
1619244Ssam 	fatal(f, "All network ports in use");
1629244Ssam 	/*NOTREACHED*/
1636002Sroot gotpty:
1646002Sroot 	dup2(f, 0);
1656002Sroot 	cp[strlen("/dev/")] = 't';
1666002Sroot 	t = open("/dev/tty", 2);
1676002Sroot 	if (t >= 0) {
1686002Sroot 		ioctl(t, TIOCNOTTY, 0);
1696002Sroot 		close(t);
1706002Sroot 	}
1716002Sroot 	t = open(cp, 2);
1729244Ssam 	if (t < 0)
1739244Ssam 		fatalperror(f, cp, errno);
1746002Sroot 	ioctl(t, TIOCGETP, &b);
1756388Ssam 	b.sg_flags = CRMOD|XTABS|ANYP;
1766002Sroot 	ioctl(t, TIOCSETP, &b);
1776388Ssam 	ioctl(p, TIOCGETP, &b);
1788379Ssam 	b.sg_flags &= ~ECHO;
1796388Ssam 	ioctl(p, TIOCSETP, &b);
18012683Ssam 	hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
18112683Ssam 		who->sin_family);
18212683Ssam 	if (hp)
18312683Ssam 		host = hp->h_name;
18412683Ssam 	else
18512683Ssam 		host = ntoa(who->sin_addr);
1869244Ssam 	if ((i = fork()) < 0)
1879244Ssam 		fatalperror(f, "fork", errno);
1886002Sroot 	if (i)
1896002Sroot 		telnet(f, p);
1906002Sroot 	close(f);
1916002Sroot 	close(p);
1926002Sroot 	dup2(t, 0);
1936002Sroot 	dup2(t, 1);
1946002Sroot 	dup2(t, 2);
1956002Sroot 	close(t);
196*13799Ssam 	environ = envinit;
19712713Ssam 	execl("/bin/login", "login", "-h", host, 0);
1989244Ssam 	fatalperror(f, "/bin/login", errno);
1999244Ssam 	/*NOTREACHED*/
2009244Ssam }
2019244Ssam 
2029244Ssam fatal(f, msg)
2039244Ssam 	int f;
2049244Ssam 	char *msg;
2059244Ssam {
2069244Ssam 	char buf[BUFSIZ];
2079244Ssam 
2089244Ssam 	(void) sprintf(buf, "telnetd: %s.\n", msg);
2099244Ssam 	(void) write(f, buf, strlen(buf));
2106002Sroot 	exit(1);
2116002Sroot }
2126002Sroot 
2139244Ssam fatalperror(f, msg, errno)
2149244Ssam 	int f;
2159244Ssam 	char *msg;
2169244Ssam 	int errno;
2179244Ssam {
2189244Ssam 	char buf[BUFSIZ];
2199244Ssam 	extern char *sys_errlist[];
2209244Ssam 
2219244Ssam 	(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
2229244Ssam 	fatal(f, buf);
2239244Ssam }
2249244Ssam 
2256002Sroot /*
2266002Sroot  * Main loop.  Select from pty and network, and
2276002Sroot  * hand data to telnet receiver finite state machine.
2286002Sroot  */
2296002Sroot telnet(f, p)
2306002Sroot {
2316002Sroot 	int on = 1;
23212713Ssam 	char hostname[32];
2336002Sroot 
2346002Sroot 	net = f, pty = p;
2356002Sroot 	ioctl(f, FIONBIO, &on);
2366002Sroot 	ioctl(p, FIONBIO, &on);
2376002Sroot 	signal(SIGTSTP, SIG_IGN);
23813028Ssam 	signal(SIGCHLD, cleanup);
2396002Sroot 
2408379Ssam 	/*
2418379Ssam 	 * Request to do remote echo.
2428379Ssam 	 */
2438379Ssam 	dooption(TELOPT_ECHO);
2448379Ssam 	myopts[TELOPT_ECHO] = 1;
24512713Ssam 	/*
24612713Ssam 	 * Show banner that getty never gave.
24712713Ssam 	 */
24812713Ssam 	gethostname(hostname, sizeof (hostname));
24912713Ssam 	sprintf(nfrontp, BANNER, hostname, "");
25012713Ssam 	nfrontp += strlen(nfrontp);
2516002Sroot 	for (;;) {
2526002Sroot 		int ibits = 0, obits = 0;
2536002Sroot 		register int c;
2546002Sroot 
2556002Sroot 		/*
2566002Sroot 		 * Never look for input if there's still
2576002Sroot 		 * stuff in the corresponding output buffer
2586002Sroot 		 */
2596002Sroot 		if (nfrontp - nbackp)
2606002Sroot 			obits |= (1 << f);
2616002Sroot 		else
2626002Sroot 			ibits |= (1 << p);
2636002Sroot 		if (pfrontp - pbackp)
2646002Sroot 			obits |= (1 << p);
2656002Sroot 		else
2666002Sroot 			ibits |= (1 << f);
2676002Sroot 		if (ncc < 0 && pcc < 0)
2686002Sroot 			break;
2699218Ssam 		select(16, &ibits, &obits, 0, 0);
2706002Sroot 		if (ibits == 0 && obits == 0) {
2716002Sroot 			sleep(5);
2726002Sroot 			continue;
2736002Sroot 		}
2746002Sroot 
2756002Sroot 		/*
2766002Sroot 		 * Something to read from the network...
2776002Sroot 		 */
2786002Sroot 		if (ibits & (1 << f)) {
2796002Sroot 			ncc = read(f, netibuf, BUFSIZ);
2806002Sroot 			if (ncc < 0 && errno == EWOULDBLOCK)
2816002Sroot 				ncc = 0;
2826002Sroot 			else {
2836002Sroot 				if (ncc <= 0)
2846002Sroot 					break;
2856002Sroot 				netip = netibuf;
2866002Sroot 			}
2876002Sroot 		}
2886002Sroot 
2896002Sroot 		/*
2906002Sroot 		 * Something to read from the pty...
2916002Sroot 		 */
2926002Sroot 		if (ibits & (1 << p)) {
2936002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
2946002Sroot 			if (pcc < 0 && errno == EWOULDBLOCK)
2956002Sroot 				pcc = 0;
2966002Sroot 			else {
2976002Sroot 				if (pcc <= 0)
2986002Sroot 					break;
2996002Sroot 				ptyip = ptyibuf;
3006002Sroot 			}
3016002Sroot 		}
3026002Sroot 
3036002Sroot 		while (pcc > 0) {
3046002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
3056002Sroot 				break;
3066002Sroot 			c = *ptyip++ & 0377, pcc--;
3076002Sroot 			if (c == IAC)
3086002Sroot 				*nfrontp++ = c;
3096002Sroot 			*nfrontp++ = c;
3106002Sroot 		}
3116002Sroot 		if ((obits & (1 << f)) && (nfrontp - nbackp) > 0)
3126002Sroot 			netflush();
3136002Sroot 		if (ncc > 0)
3146002Sroot 			telrcv();
3156002Sroot 		if ((obits & (1 << p)) && (pfrontp - pbackp) > 0)
3166002Sroot 			ptyflush();
3176002Sroot 	}
3186002Sroot 	cleanup();
3196002Sroot }
3206002Sroot 
3216002Sroot /*
3226002Sroot  * State for recv fsm
3236002Sroot  */
3246002Sroot #define	TS_DATA		0	/* base state */
3256002Sroot #define	TS_IAC		1	/* look for double IAC's */
3266002Sroot #define	TS_CR		2	/* CR-LF ->'s CR */
3276002Sroot #define	TS_BEGINNEG	3	/* throw away begin's... */
3286002Sroot #define	TS_ENDNEG	4	/* ...end's (suboption negotiation) */
3296002Sroot #define	TS_WILL		5	/* will option negotiation */
3306002Sroot #define	TS_WONT		6	/* wont " */
3316002Sroot #define	TS_DO		7	/* do " */
3326002Sroot #define	TS_DONT		8	/* dont " */
3336002Sroot 
3346002Sroot telrcv()
3356002Sroot {
3366002Sroot 	register int c;
3376002Sroot 	static int state = TS_DATA;
3386002Sroot 	struct sgttyb b;
3396002Sroot 
3406002Sroot 	while (ncc > 0) {
3416002Sroot 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
3426002Sroot 			return;
3436002Sroot 		c = *netip++ & 0377, ncc--;
3446002Sroot 		switch (state) {
3456002Sroot 
3466002Sroot 		case TS_DATA:
3476002Sroot 			if (c == IAC) {
3486002Sroot 				state = TS_IAC;
3496002Sroot 				break;
3506002Sroot 			}
3516002Sroot 			if (inter > 0)
3526002Sroot 				break;
3536002Sroot 			*pfrontp++ = c;
3546002Sroot 			if (!myopts[TELOPT_BINARY] && c == '\r')
3556002Sroot 				state = TS_CR;
3566002Sroot 			break;
3576002Sroot 
3586002Sroot 		case TS_CR:
3596002Sroot 			if (c && c != '\n')
3606002Sroot 				*pfrontp++ = c;
3616002Sroot 			state = TS_DATA;
3626002Sroot 			break;
3636002Sroot 
3646002Sroot 		case TS_IAC:
3656002Sroot 			switch (c) {
3666002Sroot 
3676002Sroot 			/*
3686002Sroot 			 * Send the process on the pty side an
3696002Sroot 			 * interrupt.  Do this with a NULL or
3706002Sroot 			 * interrupt char; depending on the tty mode.
3716002Sroot 			 */
3726002Sroot 			case BREAK:
3736002Sroot 			case IP:
3746002Sroot 				interrupt();
3756002Sroot 				break;
3766002Sroot 
3776002Sroot 			/*
3786002Sroot 			 * Are You There?
3796002Sroot 			 */
3806002Sroot 			case AYT:
3816002Sroot 				*pfrontp++ = BELL;
3826002Sroot 				break;
3836002Sroot 
3846002Sroot 			/*
3856002Sroot 			 * Erase Character and
3866002Sroot 			 * Erase Line
3876002Sroot 			 */
3886002Sroot 			case EC:
3896002Sroot 			case EL:
3906002Sroot 				ptyflush();	/* half-hearted */
3916002Sroot 				ioctl(pty, TIOCGETP, &b);
3926002Sroot 				*pfrontp++ = (c == EC) ?
3936002Sroot 					b.sg_erase : b.sg_kill;
3946002Sroot 				break;
3956002Sroot 
3966002Sroot 			/*
3976002Sroot 			 * Check for urgent data...
3986002Sroot 			 */
3996002Sroot 			case DM:
4006002Sroot 				break;
4016002Sroot 
4026002Sroot 			/*
4036002Sroot 			 * Begin option subnegotiation...
4046002Sroot 			 */
4056002Sroot 			case SB:
4066002Sroot 				state = TS_BEGINNEG;
4076002Sroot 				continue;
4086002Sroot 
4096002Sroot 			case WILL:
4106002Sroot 			case WONT:
4116002Sroot 			case DO:
4126002Sroot 			case DONT:
4136002Sroot 				state = TS_WILL + (c - WILL);
4146002Sroot 				continue;
4156002Sroot 
4166002Sroot 			case IAC:
4176002Sroot 				*pfrontp++ = c;
4186002Sroot 				break;
4196002Sroot 			}
4206002Sroot 			state = TS_DATA;
4216002Sroot 			break;
4226002Sroot 
4236002Sroot 		case TS_BEGINNEG:
4246002Sroot 			if (c == IAC)
4256002Sroot 				state = TS_ENDNEG;
4266002Sroot 			break;
4276002Sroot 
4286002Sroot 		case TS_ENDNEG:
4296002Sroot 			state = c == SE ? TS_DATA : TS_BEGINNEG;
4306002Sroot 			break;
4316002Sroot 
4326002Sroot 		case TS_WILL:
4336002Sroot 			if (!hisopts[c])
4346002Sroot 				willoption(c);
4356002Sroot 			state = TS_DATA;
4366002Sroot 			continue;
4376002Sroot 
4386002Sroot 		case TS_WONT:
4396002Sroot 			if (hisopts[c])
4406002Sroot 				wontoption(c);
4416002Sroot 			state = TS_DATA;
4426002Sroot 			continue;
4436002Sroot 
4446002Sroot 		case TS_DO:
4456002Sroot 			if (!myopts[c])
4466002Sroot 				dooption(c);
4476002Sroot 			state = TS_DATA;
4486002Sroot 			continue;
4496002Sroot 
4506002Sroot 		case TS_DONT:
4516002Sroot 			if (myopts[c]) {
4526002Sroot 				myopts[c] = 0;
4536002Sroot 				sprintf(nfrontp, wont, c);
4548379Ssam 				nfrontp += sizeof (wont) - 2;
4556002Sroot 			}
4566002Sroot 			state = TS_DATA;
4576002Sroot 			continue;
4586002Sroot 
4596002Sroot 		default:
4609218Ssam 			printf("telnetd: panic state=%d\n", state);
4616002Sroot 			exit(1);
4626002Sroot 		}
4636002Sroot 	}
4646002Sroot }
4656002Sroot 
4666002Sroot willoption(option)
4676002Sroot 	int option;
4686002Sroot {
4696002Sroot 	char *fmt;
4706002Sroot 
4716002Sroot 	switch (option) {
4726002Sroot 
4736002Sroot 	case TELOPT_BINARY:
4746002Sroot 		mode(RAW, 0);
4756002Sroot 		goto common;
4766002Sroot 
4776002Sroot 	case TELOPT_ECHO:
4786002Sroot 		mode(0, ECHO|CRMOD);
4796002Sroot 		/*FALL THRU*/
4806002Sroot 
4816002Sroot 	case TELOPT_SGA:
4826002Sroot 	common:
4836002Sroot 		hisopts[option] = 1;
4846002Sroot 		fmt = doopt;
4856002Sroot 		break;
4866002Sroot 
4876002Sroot 	case TELOPT_TM:
4886002Sroot 		fmt = dont;
4896002Sroot 		break;
4906002Sroot 
4916002Sroot 	default:
4926002Sroot 		fmt = dont;
4936002Sroot 		break;
4946002Sroot 	}
4956023Ssam 	sprintf(nfrontp, fmt, option);
4968379Ssam 	nfrontp += sizeof (dont) - 2;
4976002Sroot }
4986002Sroot 
4996002Sroot wontoption(option)
5006002Sroot 	int option;
5016002Sroot {
5026002Sroot 	char *fmt;
5036002Sroot 
5046002Sroot 	switch (option) {
5056002Sroot 
5066002Sroot 	case TELOPT_ECHO:
5076002Sroot 		mode(ECHO|CRMOD, 0);
5086002Sroot 		goto common;
5096002Sroot 
5106002Sroot 	case TELOPT_BINARY:
5116002Sroot 		mode(0, RAW);
5126002Sroot 		/*FALL THRU*/
5136002Sroot 
5146002Sroot 	case TELOPT_SGA:
5156002Sroot 	common:
5166002Sroot 		hisopts[option] = 0;
5176002Sroot 		fmt = dont;
5186002Sroot 		break;
5196002Sroot 
5206002Sroot 	default:
5216002Sroot 		fmt = dont;
5226002Sroot 	}
5236002Sroot 	sprintf(nfrontp, fmt, option);
5248379Ssam 	nfrontp += sizeof (doopt) - 2;
5256002Sroot }
5266002Sroot 
5276002Sroot dooption(option)
5286002Sroot 	int option;
5296002Sroot {
5306002Sroot 	char *fmt;
5316002Sroot 
5326002Sroot 	switch (option) {
5336002Sroot 
5346002Sroot 	case TELOPT_TM:
5356002Sroot 		fmt = wont;
5366002Sroot 		break;
5376002Sroot 
5386002Sroot 	case TELOPT_ECHO:
5396002Sroot 		mode(ECHO|CRMOD, 0);
5406002Sroot 		goto common;
5416002Sroot 
5426002Sroot 	case TELOPT_BINARY:
5436002Sroot 		mode(RAW, 0);
5446002Sroot 		/*FALL THRU*/
5456002Sroot 
5466002Sroot 	case TELOPT_SGA:
5476002Sroot 	common:
5486002Sroot 		fmt = will;
5496002Sroot 		break;
5506002Sroot 
5516002Sroot 	default:
5526002Sroot 		fmt = wont;
5536002Sroot 		break;
5546002Sroot 	}
5556002Sroot 	sprintf(nfrontp, fmt, option);
5568379Ssam 	nfrontp += sizeof (doopt) - 2;
5576002Sroot }
5586002Sroot 
5596002Sroot mode(on, off)
5606002Sroot 	int on, off;
5616002Sroot {
5626002Sroot 	struct sgttyb b;
5636002Sroot 
5646002Sroot 	ptyflush();
5656002Sroot 	ioctl(pty, TIOCGETP, &b);
5666002Sroot 	b.sg_flags |= on;
5676002Sroot 	b.sg_flags &= ~off;
5686002Sroot 	ioctl(pty, TIOCSETP, &b);
5696002Sroot }
5706002Sroot 
5716002Sroot /*
5726002Sroot  * Send interrupt to process on other side of pty.
5736002Sroot  * If it is in raw mode, just write NULL;
5746002Sroot  * otherwise, write intr char.
5756002Sroot  */
5766002Sroot interrupt()
5776002Sroot {
5786002Sroot 	struct sgttyb b;
5796002Sroot 	struct tchars tchars;
5806002Sroot 
5816002Sroot 	ptyflush();	/* half-hearted */
5826002Sroot 	ioctl(pty, TIOCGETP, &b);
5836002Sroot 	if (b.sg_flags & RAW) {
5846002Sroot 		*pfrontp++ = '\0';
5856002Sroot 		return;
5866002Sroot 	}
5876002Sroot 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
5886002Sroot 		'\177' : tchars.t_intrc;
5896002Sroot }
5906002Sroot 
5916002Sroot ptyflush()
5926002Sroot {
5936002Sroot 	int n;
5946002Sroot 
5956002Sroot 	if ((n = pfrontp - pbackp) > 0)
5966002Sroot 		n = write(pty, pbackp, n);
5978346Ssam 	if (n < 0)
5988346Ssam 		return;
5996002Sroot 	pbackp += n;
6006002Sroot 	if (pbackp == pfrontp)
6016002Sroot 		pbackp = pfrontp = ptyobuf;
6026002Sroot }
6036002Sroot 
6046002Sroot netflush()
6056002Sroot {
6066002Sroot 	int n;
6076002Sroot 
6086002Sroot 	if ((n = nfrontp - nbackp) > 0)
6096002Sroot 		n = write(net, nbackp, n);
6108346Ssam 	if (n < 0) {
6118346Ssam 		if (errno == EWOULDBLOCK)
6128346Ssam 			return;
6138346Ssam 		/* should blow this guy away... */
6148346Ssam 		return;
6158346Ssam 	}
6166002Sroot 	nbackp += n;
6176002Sroot 	if (nbackp == nfrontp)
6186002Sroot 		nbackp = nfrontp = netobuf;
6196002Sroot }
6206002Sroot 
6216002Sroot cleanup()
6226002Sroot {
6236002Sroot 
6246002Sroot 	rmut();
62510008Ssam 	vhangup();	/* XXX */
62610191Ssam 	shutdown(net, 2);
6276002Sroot 	kill(0, SIGKILL);
6286002Sroot 	exit(1);
6296002Sroot }
6306002Sroot 
6316002Sroot #include <utmp.h>
6326002Sroot 
6336002Sroot struct	utmp wtmp;
6346002Sroot char	wtmpf[]	= "/usr/adm/wtmp";
6356002Sroot char	utmp[] = "/etc/utmp";
6368379Ssam #define SCPYN(a, b)	strncpy(a, b, sizeof (a))
6378379Ssam #define SCMPN(a, b)	strncmp(a, b, sizeof (a))
6386002Sroot 
6396002Sroot rmut()
6406002Sroot {
6416002Sroot 	register f;
6426002Sroot 	int found = 0;
6436002Sroot 
6446002Sroot 	f = open(utmp, 2);
6456002Sroot 	if (f >= 0) {
6468379Ssam 		while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
6476002Sroot 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
6486002Sroot 				continue;
6498379Ssam 			lseek(f, -(long)sizeof (wtmp), 1);
6506002Sroot 			SCPYN(wtmp.ut_name, "");
65112683Ssam 			SCPYN(wtmp.ut_host, "");
6526002Sroot 			time(&wtmp.ut_time);
6538379Ssam 			write(f, (char *)&wtmp, sizeof (wtmp));
6546002Sroot 			found++;
6556002Sroot 		}
6566002Sroot 		close(f);
6576002Sroot 	}
6586002Sroot 	if (found) {
6596002Sroot 		f = open(wtmpf, 1);
6606002Sroot 		if (f >= 0) {
6616002Sroot 			SCPYN(wtmp.ut_line, line+5);
6626002Sroot 			SCPYN(wtmp.ut_name, "");
66312683Ssam 			SCPYN(wtmp.ut_host, "");
6646002Sroot 			time(&wtmp.ut_time);
6656002Sroot 			lseek(f, (long)0, 2);
6668379Ssam 			write(f, (char *)&wtmp, sizeof (wtmp));
6676002Sroot 			close(f);
6686002Sroot 		}
6696002Sroot 	}
6706002Sroot 	chmod(line, 0666);
6716002Sroot 	chown(line, 0, 0);
6726002Sroot 	line[strlen("/dev/")] = 'p';
6736002Sroot 	chmod(line, 0666);
6746002Sroot 	chown(line, 0, 0);
6756002Sroot }
67612683Ssam 
67712683Ssam /*
67812683Ssam  * Convert network-format internet address
67912683Ssam  * to base 256 d.d.d.d representation.
68012683Ssam  */
68112683Ssam char *
68212683Ssam ntoa(in)
68312683Ssam 	struct in_addr in;
68412683Ssam {
68512683Ssam 	static char b[18];
68612683Ssam 	register char *p;
68712683Ssam 
68812683Ssam 	p = (char *)&in;
68912683Ssam #define	UC(b)	(((int)b)&0xff)
69012683Ssam 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
69112683Ssam 	return (b);
69212683Ssam }
693