xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 26499)
121182Sdist /*
221182Sdist  * Copyright (c) 1983 Regents of the University of California.
321182Sdist  * All rights reserved.  The Berkeley software License Agreement
421182Sdist  * specifies the terms and conditions for redistribution.
521182Sdist  */
621182Sdist 
76295Sroot #ifndef lint
821182Sdist char copyright[] =
921182Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021182Sdist  All rights reserved.\n";
1121182Sdist #endif not lint
126295Sroot 
1321182Sdist #ifndef lint
14*26499Sminshall static char sccsid[] = "@(#)telnetd.c	5.7 (Berkeley) 03/07/86";
1521182Sdist #endif not lint
1621182Sdist 
176002Sroot /*
186002Sroot  * Stripped-down telnet server.
196002Sroot  */
209218Ssam #include <sys/types.h>
219218Ssam #include <sys/socket.h>
2213608Ssam #include <sys/wait.h>
2317583Ssam #include <sys/file.h>
2420188Skarels #include <sys/stat.h>
259218Ssam 
269218Ssam #include <netinet/in.h>
279218Ssam 
2812216Ssam #include <arpa/telnet.h>
2912216Ssam 
306002Sroot #include <stdio.h>
316002Sroot #include <signal.h>
326002Sroot #include <errno.h>
336002Sroot #include <sgtty.h>
348346Ssam #include <netdb.h>
3517187Sralph #include <syslog.h>
369218Ssam 
3713798Ssam #define	BELL	'\07'
3823567Sbloom #define BANNER	"\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s"
396002Sroot 
406002Sroot char	hisopts[256];
416002Sroot char	myopts[256];
426002Sroot 
436002Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
446002Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
456002Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
466002Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
476002Sroot 
486002Sroot /*
496002Sroot  * I/O data buffers, pointers, and counters.
506002Sroot  */
516002Sroot char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
526002Sroot char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
536002Sroot char	netibuf[BUFSIZ], *netip = netibuf;
546388Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
556002Sroot int	pcc, ncc;
566002Sroot 
576002Sroot int	pty, net;
586002Sroot int	inter;
5913799Ssam extern	char **environ;
606002Sroot extern	int errno;
6120188Skarels char	*line;
626002Sroot 
636002Sroot main(argc, argv)
646002Sroot 	char *argv[];
656002Sroot {
6616371Skarels 	struct sockaddr_in from;
6717156Ssam 	int on = 1, fromlen;
686002Sroot 
6924855Seric 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
7016371Skarels 	fromlen = sizeof (from);
7116371Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
7216371Skarels 		fprintf(stderr, "%s: ", argv[0]);
7316371Skarels 		perror("getpeername");
7416371Skarels 		_exit(1);
758346Ssam 	}
7617156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
7717187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
7810418Ssam 	}
7916371Skarels 	doit(0, &from);
806002Sroot }
816002Sroot 
8213799Ssam char	*envinit[] = { "TERM=network", 0 };
836002Sroot int	cleanup();
846002Sroot 
856002Sroot /*
866002Sroot  * Get a pty, scan input lines.
876002Sroot  */
8812683Ssam doit(f, who)
8912683Ssam 	int f;
9012683Ssam 	struct sockaddr_in *who;
916002Sroot {
9220188Skarels 	char *host, *inet_ntoa();
9317583Ssam 	int i, p, t;
946002Sroot 	struct sgttyb b;
9512683Ssam 	struct hostent *hp;
9620188Skarels 	char c;
976002Sroot 
9820188Skarels 	for (c = 'p'; c <= 's'; c++) {
9920188Skarels 		struct stat stb;
10020188Skarels 
10120188Skarels 		line = "/dev/ptyXX";
10220188Skarels 		line[strlen("/dev/pty")] = c;
10320188Skarels 		line[strlen("/dev/ptyp")] = '0';
10420188Skarels 		if (stat(line, &stb) < 0)
10520188Skarels 			break;
10617583Ssam 		for (i = 0; i < 16; i++) {
10720188Skarels 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
10820188Skarels 			p = open(line, 2);
10917583Ssam 			if (p > 0)
11017583Ssam 				goto gotpty;
11117583Ssam 		}
1126002Sroot 	}
1139244Ssam 	fatal(f, "All network ports in use");
1149244Ssam 	/*NOTREACHED*/
1156002Sroot gotpty:
1166002Sroot 	dup2(f, 0);
11720188Skarels 	line[strlen("/dev/")] = 't';
11817583Ssam 	t = open("/dev/tty", O_RDWR);
1196002Sroot 	if (t >= 0) {
1206002Sroot 		ioctl(t, TIOCNOTTY, 0);
1216002Sroot 		close(t);
1226002Sroot 	}
12320188Skarels 	t = open(line, O_RDWR);
1249244Ssam 	if (t < 0)
12520188Skarels 		fatalperror(f, line, errno);
1266002Sroot 	ioctl(t, TIOCGETP, &b);
1276388Ssam 	b.sg_flags = CRMOD|XTABS|ANYP;
1286002Sroot 	ioctl(t, TIOCSETP, &b);
1296388Ssam 	ioctl(p, TIOCGETP, &b);
1308379Ssam 	b.sg_flags &= ~ECHO;
1316388Ssam 	ioctl(p, TIOCSETP, &b);
13212683Ssam 	hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
13312683Ssam 		who->sin_family);
13412683Ssam 	if (hp)
13512683Ssam 		host = hp->h_name;
13612683Ssam 	else
13717444Sralph 		host = inet_ntoa(who->sin_addr);
1389244Ssam 	if ((i = fork()) < 0)
1399244Ssam 		fatalperror(f, "fork", errno);
1406002Sroot 	if (i)
1416002Sroot 		telnet(f, p);
1426002Sroot 	close(f);
1436002Sroot 	close(p);
1446002Sroot 	dup2(t, 0);
1456002Sroot 	dup2(t, 1);
1466002Sroot 	dup2(t, 2);
1476002Sroot 	close(t);
14813799Ssam 	environ = envinit;
14912713Ssam 	execl("/bin/login", "login", "-h", host, 0);
1509244Ssam 	fatalperror(f, "/bin/login", errno);
1519244Ssam 	/*NOTREACHED*/
1529244Ssam }
1539244Ssam 
1549244Ssam fatal(f, msg)
1559244Ssam 	int f;
1569244Ssam 	char *msg;
1579244Ssam {
1589244Ssam 	char buf[BUFSIZ];
1599244Ssam 
16017583Ssam 	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
1619244Ssam 	(void) write(f, buf, strlen(buf));
1626002Sroot 	exit(1);
1636002Sroot }
1646002Sroot 
1659244Ssam fatalperror(f, msg, errno)
1669244Ssam 	int f;
1679244Ssam 	char *msg;
1689244Ssam 	int errno;
1699244Ssam {
1709244Ssam 	char buf[BUFSIZ];
1719244Ssam 	extern char *sys_errlist[];
1729244Ssam 
17317583Ssam 	(void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
1749244Ssam 	fatal(f, buf);
1759244Ssam }
1769244Ssam 
1776002Sroot /*
1786002Sroot  * Main loop.  Select from pty and network, and
1796002Sroot  * hand data to telnet receiver finite state machine.
1806002Sroot  */
1816002Sroot telnet(f, p)
1826002Sroot {
1836002Sroot 	int on = 1;
18412713Ssam 	char hostname[32];
1856002Sroot 
1866002Sroot 	net = f, pty = p;
1876002Sroot 	ioctl(f, FIONBIO, &on);
1886002Sroot 	ioctl(p, FIONBIO, &on);
1896002Sroot 	signal(SIGTSTP, SIG_IGN);
19013028Ssam 	signal(SIGCHLD, cleanup);
19126083Slepreau 	setpgrp(0, 0);
1926002Sroot 
1938379Ssam 	/*
1948379Ssam 	 * Request to do remote echo.
1958379Ssam 	 */
1968379Ssam 	dooption(TELOPT_ECHO);
1978379Ssam 	myopts[TELOPT_ECHO] = 1;
19812713Ssam 	/*
19912713Ssam 	 * Show banner that getty never gave.
20012713Ssam 	 */
20112713Ssam 	gethostname(hostname, sizeof (hostname));
20212713Ssam 	sprintf(nfrontp, BANNER, hostname, "");
20312713Ssam 	nfrontp += strlen(nfrontp);
2046002Sroot 	for (;;) {
2056002Sroot 		int ibits = 0, obits = 0;
2066002Sroot 		register int c;
2076002Sroot 
2086002Sroot 		/*
2096002Sroot 		 * Never look for input if there's still
2106002Sroot 		 * stuff in the corresponding output buffer
2116002Sroot 		 */
21217583Ssam 		if (nfrontp - nbackp || pcc > 0)
2136002Sroot 			obits |= (1 << f);
2146002Sroot 		else
2156002Sroot 			ibits |= (1 << p);
21617583Ssam 		if (pfrontp - pbackp || ncc > 0)
2176002Sroot 			obits |= (1 << p);
2186002Sroot 		else
2196002Sroot 			ibits |= (1 << f);
2206002Sroot 		if (ncc < 0 && pcc < 0)
2216002Sroot 			break;
2229218Ssam 		select(16, &ibits, &obits, 0, 0);
2236002Sroot 		if (ibits == 0 && obits == 0) {
2246002Sroot 			sleep(5);
2256002Sroot 			continue;
2266002Sroot 		}
2276002Sroot 
2286002Sroot 		/*
2296002Sroot 		 * Something to read from the network...
2306002Sroot 		 */
2316002Sroot 		if (ibits & (1 << f)) {
2326002Sroot 			ncc = read(f, netibuf, BUFSIZ);
2336002Sroot 			if (ncc < 0 && errno == EWOULDBLOCK)
2346002Sroot 				ncc = 0;
2356002Sroot 			else {
2366002Sroot 				if (ncc <= 0)
2376002Sroot 					break;
2386002Sroot 				netip = netibuf;
2396002Sroot 			}
2406002Sroot 		}
2416002Sroot 
2426002Sroot 		/*
2436002Sroot 		 * Something to read from the pty...
2446002Sroot 		 */
2456002Sroot 		if (ibits & (1 << p)) {
2466002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
2476002Sroot 			if (pcc < 0 && errno == EWOULDBLOCK)
2486002Sroot 				pcc = 0;
2496002Sroot 			else {
2506002Sroot 				if (pcc <= 0)
2516002Sroot 					break;
2526002Sroot 				ptyip = ptyibuf;
2536002Sroot 			}
2546002Sroot 		}
2556002Sroot 
2566002Sroot 		while (pcc > 0) {
2576002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
2586002Sroot 				break;
2596002Sroot 			c = *ptyip++ & 0377, pcc--;
2606002Sroot 			if (c == IAC)
2616002Sroot 				*nfrontp++ = c;
2626002Sroot 			*nfrontp++ = c;
2636002Sroot 		}
2646002Sroot 		if ((obits & (1 << f)) && (nfrontp - nbackp) > 0)
2656002Sroot 			netflush();
2666002Sroot 		if (ncc > 0)
2676002Sroot 			telrcv();
2686002Sroot 		if ((obits & (1 << p)) && (pfrontp - pbackp) > 0)
2696002Sroot 			ptyflush();
2706002Sroot 	}
2716002Sroot 	cleanup();
2726002Sroot }
2736002Sroot 
2746002Sroot /*
2756002Sroot  * State for recv fsm
2766002Sroot  */
2776002Sroot #define	TS_DATA		0	/* base state */
2786002Sroot #define	TS_IAC		1	/* look for double IAC's */
2796002Sroot #define	TS_CR		2	/* CR-LF ->'s CR */
2806002Sroot #define	TS_BEGINNEG	3	/* throw away begin's... */
2816002Sroot #define	TS_ENDNEG	4	/* ...end's (suboption negotiation) */
2826002Sroot #define	TS_WILL		5	/* will option negotiation */
2836002Sroot #define	TS_WONT		6	/* wont " */
2846002Sroot #define	TS_DO		7	/* do " */
2856002Sroot #define	TS_DONT		8	/* dont " */
2866002Sroot 
2876002Sroot telrcv()
2886002Sroot {
2896002Sroot 	register int c;
2906002Sroot 	static int state = TS_DATA;
2916002Sroot 	struct sgttyb b;
2926002Sroot 
2936002Sroot 	while (ncc > 0) {
2946002Sroot 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
2956002Sroot 			return;
2966002Sroot 		c = *netip++ & 0377, ncc--;
2976002Sroot 		switch (state) {
2986002Sroot 
29926090Sminshall 		case TS_CR:
30026090Sminshall 			state = TS_DATA;
301*26499Sminshall 			if ((c == 0) || (c == '\n')) {
30226090Sminshall 				break;
303*26499Sminshall 			}
30426090Sminshall 			/* FALL THROUGH */
30526090Sminshall 
3066002Sroot 		case TS_DATA:
3076002Sroot 			if (c == IAC) {
3086002Sroot 				state = TS_IAC;
3096002Sroot 				break;
3106002Sroot 			}
3116002Sroot 			if (inter > 0)
3126002Sroot 				break;
313*26499Sminshall 			if (!myopts[TELOPT_BINARY] && c == '\r') {
3146002Sroot 				state = TS_CR;
315*26499Sminshall 			}
316*26499Sminshall 			*pfrontp++ = c;
3176002Sroot 			break;
3186002Sroot 
3196002Sroot 		case TS_IAC:
3206002Sroot 			switch (c) {
3216002Sroot 
3226002Sroot 			/*
3236002Sroot 			 * Send the process on the pty side an
3246002Sroot 			 * interrupt.  Do this with a NULL or
3256002Sroot 			 * interrupt char; depending on the tty mode.
3266002Sroot 			 */
3276002Sroot 			case BREAK:
3286002Sroot 			case IP:
3296002Sroot 				interrupt();
3306002Sroot 				break;
3316002Sroot 
3326002Sroot 			/*
3336002Sroot 			 * Are You There?
3346002Sroot 			 */
3356002Sroot 			case AYT:
33617583Ssam 				strcpy(nfrontp, "\r\n[Yes]\r\n");
33717583Ssam 				nfrontp += 9;
3386002Sroot 				break;
3396002Sroot 
3406002Sroot 			/*
3416002Sroot 			 * Erase Character and
3426002Sroot 			 * Erase Line
3436002Sroot 			 */
3446002Sroot 			case EC:
3456002Sroot 			case EL:
3466002Sroot 				ptyflush();	/* half-hearted */
3476002Sroot 				ioctl(pty, TIOCGETP, &b);
3486002Sroot 				*pfrontp++ = (c == EC) ?
3496002Sroot 					b.sg_erase : b.sg_kill;
3506002Sroot 				break;
3516002Sroot 
3526002Sroot 			/*
3536002Sroot 			 * Check for urgent data...
3546002Sroot 			 */
3556002Sroot 			case DM:
3566002Sroot 				break;
3576002Sroot 
3586002Sroot 			/*
3596002Sroot 			 * Begin option subnegotiation...
3606002Sroot 			 */
3616002Sroot 			case SB:
3626002Sroot 				state = TS_BEGINNEG;
3636002Sroot 				continue;
3646002Sroot 
3656002Sroot 			case WILL:
3666002Sroot 			case WONT:
3676002Sroot 			case DO:
3686002Sroot 			case DONT:
3696002Sroot 				state = TS_WILL + (c - WILL);
3706002Sroot 				continue;
3716002Sroot 
3726002Sroot 			case IAC:
3736002Sroot 				*pfrontp++ = c;
3746002Sroot 				break;
3756002Sroot 			}
3766002Sroot 			state = TS_DATA;
3776002Sroot 			break;
3786002Sroot 
3796002Sroot 		case TS_BEGINNEG:
3806002Sroot 			if (c == IAC)
3816002Sroot 				state = TS_ENDNEG;
3826002Sroot 			break;
3836002Sroot 
3846002Sroot 		case TS_ENDNEG:
3856002Sroot 			state = c == SE ? TS_DATA : TS_BEGINNEG;
3866002Sroot 			break;
3876002Sroot 
3886002Sroot 		case TS_WILL:
3896002Sroot 			if (!hisopts[c])
3906002Sroot 				willoption(c);
3916002Sroot 			state = TS_DATA;
3926002Sroot 			continue;
3936002Sroot 
3946002Sroot 		case TS_WONT:
3956002Sroot 			if (hisopts[c])
3966002Sroot 				wontoption(c);
3976002Sroot 			state = TS_DATA;
3986002Sroot 			continue;
3996002Sroot 
4006002Sroot 		case TS_DO:
4016002Sroot 			if (!myopts[c])
4026002Sroot 				dooption(c);
4036002Sroot 			state = TS_DATA;
4046002Sroot 			continue;
4056002Sroot 
4066002Sroot 		case TS_DONT:
4076002Sroot 			if (myopts[c]) {
4086002Sroot 				myopts[c] = 0;
4096002Sroot 				sprintf(nfrontp, wont, c);
4108379Ssam 				nfrontp += sizeof (wont) - 2;
4116002Sroot 			}
4126002Sroot 			state = TS_DATA;
4136002Sroot 			continue;
4146002Sroot 
4156002Sroot 		default:
4169218Ssam 			printf("telnetd: panic state=%d\n", state);
4176002Sroot 			exit(1);
4186002Sroot 		}
4196002Sroot 	}
4206002Sroot }
4216002Sroot 
4226002Sroot willoption(option)
4236002Sroot 	int option;
4246002Sroot {
4256002Sroot 	char *fmt;
4266002Sroot 
4276002Sroot 	switch (option) {
4286002Sroot 
4296002Sroot 	case TELOPT_BINARY:
4306002Sroot 		mode(RAW, 0);
4316002Sroot 		goto common;
4326002Sroot 
4336002Sroot 	case TELOPT_ECHO:
4346002Sroot 		mode(0, ECHO|CRMOD);
4356002Sroot 		/*FALL THRU*/
4366002Sroot 
4376002Sroot 	case TELOPT_SGA:
4386002Sroot 	common:
4396002Sroot 		hisopts[option] = 1;
4406002Sroot 		fmt = doopt;
4416002Sroot 		break;
4426002Sroot 
4436002Sroot 	case TELOPT_TM:
4446002Sroot 		fmt = dont;
4456002Sroot 		break;
4466002Sroot 
4476002Sroot 	default:
4486002Sroot 		fmt = dont;
4496002Sroot 		break;
4506002Sroot 	}
4516023Ssam 	sprintf(nfrontp, fmt, option);
4528379Ssam 	nfrontp += sizeof (dont) - 2;
4536002Sroot }
4546002Sroot 
4556002Sroot wontoption(option)
4566002Sroot 	int option;
4576002Sroot {
4586002Sroot 	char *fmt;
4596002Sroot 
4606002Sroot 	switch (option) {
4616002Sroot 
4626002Sroot 	case TELOPT_ECHO:
4636002Sroot 		mode(ECHO|CRMOD, 0);
4646002Sroot 		goto common;
4656002Sroot 
4666002Sroot 	case TELOPT_BINARY:
4676002Sroot 		mode(0, RAW);
4686002Sroot 		/*FALL THRU*/
4696002Sroot 
4706002Sroot 	case TELOPT_SGA:
4716002Sroot 	common:
4726002Sroot 		hisopts[option] = 0;
4736002Sroot 		fmt = dont;
4746002Sroot 		break;
4756002Sroot 
4766002Sroot 	default:
4776002Sroot 		fmt = dont;
4786002Sroot 	}
4796002Sroot 	sprintf(nfrontp, fmt, option);
4808379Ssam 	nfrontp += sizeof (doopt) - 2;
4816002Sroot }
4826002Sroot 
4836002Sroot dooption(option)
4846002Sroot 	int option;
4856002Sroot {
4866002Sroot 	char *fmt;
4876002Sroot 
4886002Sroot 	switch (option) {
4896002Sroot 
4906002Sroot 	case TELOPT_TM:
4916002Sroot 		fmt = wont;
4926002Sroot 		break;
4936002Sroot 
4946002Sroot 	case TELOPT_ECHO:
4956002Sroot 		mode(ECHO|CRMOD, 0);
4966002Sroot 		goto common;
4976002Sroot 
4986002Sroot 	case TELOPT_BINARY:
4996002Sroot 		mode(RAW, 0);
5006002Sroot 		/*FALL THRU*/
5016002Sroot 
5026002Sroot 	case TELOPT_SGA:
5036002Sroot 	common:
5046002Sroot 		fmt = will;
5056002Sroot 		break;
5066002Sroot 
5076002Sroot 	default:
5086002Sroot 		fmt = wont;
5096002Sroot 		break;
5106002Sroot 	}
5116002Sroot 	sprintf(nfrontp, fmt, option);
5128379Ssam 	nfrontp += sizeof (doopt) - 2;
5136002Sroot }
5146002Sroot 
5156002Sroot mode(on, off)
5166002Sroot 	int on, off;
5176002Sroot {
5186002Sroot 	struct sgttyb b;
5196002Sroot 
5206002Sroot 	ptyflush();
5216002Sroot 	ioctl(pty, TIOCGETP, &b);
5226002Sroot 	b.sg_flags |= on;
5236002Sroot 	b.sg_flags &= ~off;
5246002Sroot 	ioctl(pty, TIOCSETP, &b);
5256002Sroot }
5266002Sroot 
5276002Sroot /*
5286002Sroot  * Send interrupt to process on other side of pty.
5296002Sroot  * If it is in raw mode, just write NULL;
5306002Sroot  * otherwise, write intr char.
5316002Sroot  */
5326002Sroot interrupt()
5336002Sroot {
5346002Sroot 	struct sgttyb b;
5356002Sroot 	struct tchars tchars;
5366002Sroot 
5376002Sroot 	ptyflush();	/* half-hearted */
5386002Sroot 	ioctl(pty, TIOCGETP, &b);
5396002Sroot 	if (b.sg_flags & RAW) {
5406002Sroot 		*pfrontp++ = '\0';
5416002Sroot 		return;
5426002Sroot 	}
5436002Sroot 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
5446002Sroot 		'\177' : tchars.t_intrc;
5456002Sroot }
5466002Sroot 
5476002Sroot ptyflush()
5486002Sroot {
5496002Sroot 	int n;
5506002Sroot 
5516002Sroot 	if ((n = pfrontp - pbackp) > 0)
5526002Sroot 		n = write(pty, pbackp, n);
5538346Ssam 	if (n < 0)
5548346Ssam 		return;
5556002Sroot 	pbackp += n;
5566002Sroot 	if (pbackp == pfrontp)
5576002Sroot 		pbackp = pfrontp = ptyobuf;
5586002Sroot }
5596002Sroot 
5606002Sroot netflush()
5616002Sroot {
5626002Sroot 	int n;
5636002Sroot 
5646002Sroot 	if ((n = nfrontp - nbackp) > 0)
5656002Sroot 		n = write(net, nbackp, n);
5668346Ssam 	if (n < 0) {
5678346Ssam 		if (errno == EWOULDBLOCK)
5688346Ssam 			return;
5698346Ssam 		/* should blow this guy away... */
5708346Ssam 		return;
5718346Ssam 	}
5726002Sroot 	nbackp += n;
5736002Sroot 	if (nbackp == nfrontp)
5746002Sroot 		nbackp = nfrontp = netobuf;
5756002Sroot }
5766002Sroot 
5776002Sroot cleanup()
5786002Sroot {
5796002Sroot 
5806002Sroot 	rmut();
58110008Ssam 	vhangup();	/* XXX */
58210191Ssam 	shutdown(net, 2);
5836002Sroot 	exit(1);
5846002Sroot }
5856002Sroot 
5866002Sroot #include <utmp.h>
5876002Sroot 
5886002Sroot struct	utmp wtmp;
5896002Sroot char	wtmpf[]	= "/usr/adm/wtmp";
59023567Sbloom char	utmpf[] = "/etc/utmp";
59123567Sbloom #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
59223567Sbloom #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
5936002Sroot 
5946002Sroot rmut()
5956002Sroot {
5966002Sroot 	register f;
5976002Sroot 	int found = 0;
59823567Sbloom 	struct utmp *u, *utmp;
59923567Sbloom 	int nutmp;
60023567Sbloom 	struct stat statbf;
6016002Sroot 
60223567Sbloom 	f = open(utmpf, O_RDWR);
6036002Sroot 	if (f >= 0) {
60423567Sbloom 		fstat(f, &statbf);
60523567Sbloom 		utmp = (struct utmp *)malloc(statbf.st_size);
60623567Sbloom 		if (!utmp)
60723567Sbloom 			syslog(LOG_ERR, "utmp malloc failed");
60823567Sbloom 		if (statbf.st_size && utmp) {
60923567Sbloom 			nutmp = read(f, utmp, statbf.st_size);
61023567Sbloom 			nutmp /= sizeof(struct utmp);
61123567Sbloom 
61223567Sbloom 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
61323567Sbloom 				if (SCMPN(u->ut_line, line+5) ||
61423567Sbloom 				    u->ut_name[0]==0)
61523567Sbloom 					continue;
61623567Sbloom 				lseek(f, ((long)u)-((long)utmp), L_SET);
61723567Sbloom 				SCPYN(u->ut_name, "");
61823567Sbloom 				SCPYN(u->ut_host, "");
61923567Sbloom 				time(&u->ut_time);
62023567Sbloom 				write(f, (char *)u, sizeof(wtmp));
62123567Sbloom 				found++;
62223567Sbloom 			}
6236002Sroot 		}
6246002Sroot 		close(f);
6256002Sroot 	}
6266002Sroot 	if (found) {
62717583Ssam 		f = open(wtmpf, O_WRONLY|O_APPEND);
6286002Sroot 		if (f >= 0) {
6296002Sroot 			SCPYN(wtmp.ut_line, line+5);
6306002Sroot 			SCPYN(wtmp.ut_name, "");
63112683Ssam 			SCPYN(wtmp.ut_host, "");
6326002Sroot 			time(&wtmp.ut_time);
63323567Sbloom 			write(f, (char *)&wtmp, sizeof(wtmp));
6346002Sroot 			close(f);
6356002Sroot 		}
6366002Sroot 	}
6376002Sroot 	chmod(line, 0666);
6386002Sroot 	chown(line, 0, 0);
6396002Sroot 	line[strlen("/dev/")] = 'p';
6406002Sroot 	chmod(line, 0666);
6416002Sroot 	chown(line, 0, 0);
6426002Sroot }
643