xref: /csrg-svn/libexec/telnetd/telnetd.c (revision 6023)
1*6023Ssam /*	telnetd.c	4.2	82/03/01	*/
26002Sroot 
36002Sroot /*
46002Sroot  * Stripped-down telnet server.
56002Sroot  */
66002Sroot #include <stdio.h>
76002Sroot #include <signal.h>
86002Sroot #include <errno.h>
96002Sroot #include <sgtty.h>
106002Sroot #include <wait.h>
116002Sroot #include <sys/types.h>
126002Sroot #include <sys/socket.h>
136002Sroot #include <net/in.h>
146002Sroot #include "telnet.h"
156002Sroot 
166002Sroot #define	INFINITY	10000000
176002Sroot #define	BELL		'\07'
186002Sroot #define	swab(x)		((((x) >> 8) | ((x) << 8)) & 0xffff)
196002Sroot 
206002Sroot char	hisopts[256];
216002Sroot char	myopts[256];
226002Sroot 
236002Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
246002Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
256002Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
266002Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
276002Sroot 
286002Sroot /*
296002Sroot  * I/O data buffers, pointers, and counters.
306002Sroot  */
316002Sroot char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
326002Sroot char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
336002Sroot char	netibuf[BUFSIZ], *netip = netibuf;
346002Sroot char	netobuf[BUFSIZ] =
356002Sroot 	{ IAC, DO, TELOPT_ECHO, '\r', '\n' },
366002Sroot 	*nfrontp = netobuf + 5, *nbackp = netobuf;
376002Sroot int	pcc, ncc;
386002Sroot 
396002Sroot int	pty, net;
406002Sroot int	inter;
416002Sroot extern	int errno;
426002Sroot char	line[] = "/dev/ptyp0";
436002Sroot 
446002Sroot struct	sockaddr_in sin = { AF_INET, swab(IPPORT_TELNET) };
456002Sroot int	options = SO_ACCEPTCONN;
466002Sroot 
47*6023Ssam /*
48*6023Ssam  * Debugging hooks.  Turned on with a SIGTERM.
49*6023Ssam  * Successive SIGTERM's toggle the switch.
50*6023Ssam  */
51*6023Ssam int	toggle();
52*6023Ssam int	debug;
53*6023Ssam FILE	*log;
54*6023Ssam char	logfile[80] = "/tmp/teldebugx";
55*6023Ssam 
566002Sroot main(argc, argv)
576002Sroot 	char *argv[];
586002Sroot {
596002Sroot 	int s, pid;
606002Sroot 	union wait status;
616002Sroot 
626002Sroot 	argc--, argv++;
636002Sroot 	if (argc > 0 && !strcmp(argv[0], "-d"))
646002Sroot 		options |= SO_DEBUG;
656002Sroot 	for (;;) {
666002Sroot 		errno = 0;
676002Sroot 		if ((s = socket(SOCK_STREAM, 0, &sin, options)) < 0) {
686002Sroot 			perror("socket");
696002Sroot 			sleep(5);
706002Sroot 			continue;
716002Sroot 		}
726002Sroot 		if (accept(s, 0) < 0) {
736002Sroot 			perror("accept");
746002Sroot 			close(s);
756002Sroot 			sleep(1);
766002Sroot 			continue;
776002Sroot 		}
786002Sroot 		if ((pid = fork()) < 0)
796002Sroot 			printf("Out of processes\n");
806002Sroot 		else if (pid == 0)
816002Sroot 			doit(s);
826002Sroot 		close(s);
836002Sroot 		while (wait3(status, WNOHANG, 0) > 0)
846002Sroot 			continue;
856002Sroot 	}
866002Sroot 	/*NOTREACHED*/
876002Sroot }
886002Sroot 
896002Sroot int	cleanup();
906002Sroot 
916002Sroot /*
926002Sroot  * Get a pty, scan input lines.
936002Sroot  */
946002Sroot doit(f)
956002Sroot {
966002Sroot 	char *cp = line;
976002Sroot 	int i, p, cc, t;
986002Sroot 	struct sgttyb b;
996002Sroot 
1006002Sroot 	for (i = 0; i < 16; i++) {
1016002Sroot 		cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
1026002Sroot 		p = open(cp, 2);
1036002Sroot 		if (p > 0)
1046002Sroot 			goto gotpty;
1056002Sroot 	}
1066002Sroot 	dup2(f, 1);
1076002Sroot 	printf("All network ports in use.\n");
1086002Sroot 	exit(1);
1096002Sroot gotpty:
110*6023Ssam 	logfile[strlen("/tmp/teldebug")] = "0123456789abcdef"[i];
1116002Sroot 	dup2(f, 0);
1126002Sroot 	cp[strlen("/dev/")] = 't';
1136002Sroot 	t = open("/dev/tty", 2);
1146002Sroot 	if (t >= 0) {
1156002Sroot 		ioctl(t, TIOCNOTTY, 0);
1166002Sroot 		close(t);
1176002Sroot 	}
1186002Sroot 	t = open(cp, 2);
1196002Sroot 	if (t < 0) {
1206002Sroot 		dup2(f, 2);
1216002Sroot 		perror(cp);
1226002Sroot 		exit(1);
1236002Sroot 	}
1246002Sroot 	ioctl(t, TIOCGETP, &b);
1256002Sroot 	b.sg_flags = ECHO|CRMOD|XTABS|ANYP;
1266002Sroot 	ioctl(t, TIOCSETP, &b);
1276002Sroot 	if ((i = fork()) < 0) {
1286002Sroot 		dup2(f, 2);
1296002Sroot 		perror("fork");
1306002Sroot 		exit(1);
1316002Sroot 	}
1326002Sroot 	if (i)
1336002Sroot 		telnet(f, p);
1346002Sroot 	close(f);
1356002Sroot 	close(p);
1366002Sroot 	dup2(t, 0);
1376002Sroot 	dup2(t, 1);
1386002Sroot 	dup2(t, 2);
1396002Sroot 	close(t);
1406002Sroot 	execl("/bin/login", "telnet-login", 0);
1416002Sroot 	perror("/bin/login");
1426002Sroot 	exit(1);
1436002Sroot }
1446002Sroot 
1456002Sroot /*
1466002Sroot  * Main loop.  Select from pty and network, and
1476002Sroot  * hand data to telnet receiver finite state machine.
1486002Sroot  */
1496002Sroot telnet(f, p)
1506002Sroot {
1516002Sroot 	int on = 1;
1526002Sroot 
1536002Sroot 	net = f, pty = p;
1546002Sroot 	ioctl(f, FIONBIO, &on);
1556002Sroot 	ioctl(p, FIONBIO, &on);
1566002Sroot 	signal(SIGTSTP, SIG_IGN);
1576002Sroot 	sigset(SIGCHLD, cleanup);
158*6023Ssam 	sigset(SIGTERM, toggle);
1596002Sroot 
1606002Sroot 	for (;;) {
1616002Sroot 		int ibits = 0, obits = 0;
1626002Sroot 		register int c;
1636002Sroot 
1646002Sroot 		/*
1656002Sroot 		 * Never look for input if there's still
1666002Sroot 		 * stuff in the corresponding output buffer
1676002Sroot 		 */
1686002Sroot 		if (nfrontp - nbackp)
1696002Sroot 			obits |= (1 << f);
1706002Sroot 		else
1716002Sroot 			ibits |= (1 << p);
1726002Sroot 		if (pfrontp - pbackp)
1736002Sroot 			obits |= (1 << p);
1746002Sroot 		else
1756002Sroot 			ibits |= (1 << f);
1766002Sroot 		if (ncc < 0 && pcc < 0)
1776002Sroot 			break;
178*6023Ssam 		if (debug)
179*6023Ssam 			fprintf(log, "select: ibits=%d, obits=%d\n",
180*6023Ssam 				ibits, obits);
1816002Sroot 		select(32, &ibits, &obits, INFINITY);
182*6023Ssam 		if (debug)
183*6023Ssam 			fprintf(log, "ibits=%d, obits=%d\n", ibits, obits);
1846002Sroot 		if (ibits == 0 && obits == 0) {
1856002Sroot 			sleep(5);
1866002Sroot 			continue;
1876002Sroot 		}
1886002Sroot 
1896002Sroot 		/*
1906002Sroot 		 * Something to read from the network...
1916002Sroot 		 */
1926002Sroot 		if (ibits & (1 << f)) {
1936002Sroot 			ncc = read(f, netibuf, BUFSIZ);
194*6023Ssam 			if (debug)
195*6023Ssam 				fprintf(log, "read %d from net\n", ncc);
1966002Sroot 			if (ncc < 0 && errno == EWOULDBLOCK)
1976002Sroot 				ncc = 0;
1986002Sroot 			else {
1996002Sroot 				if (ncc <= 0)
2006002Sroot 					break;
2016002Sroot 				netip = netibuf;
2026002Sroot 			}
2036002Sroot 		}
2046002Sroot 
2056002Sroot 		/*
2066002Sroot 		 * Something to read from the pty...
2076002Sroot 		 */
2086002Sroot 		if (ibits & (1 << p)) {
2096002Sroot 			pcc = read(p, ptyibuf, BUFSIZ);
210*6023Ssam 			if (debug)
211*6023Ssam 				fprintf(log, "read %d from pty\n", pcc);
2126002Sroot 			if (pcc < 0 && errno == EWOULDBLOCK)
2136002Sroot 				pcc = 0;
2146002Sroot 			else {
2156002Sroot 				if (pcc <= 0)
2166002Sroot 					break;
2176002Sroot 				ptyip = ptyibuf;
2186002Sroot 			}
2196002Sroot 		}
2206002Sroot 
2216002Sroot 		while (pcc > 0) {
2226002Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
2236002Sroot 				break;
2246002Sroot 			c = *ptyip++ & 0377, pcc--;
2256002Sroot 			if (c == IAC)
2266002Sroot 				*nfrontp++ = c;
2276002Sroot 			*nfrontp++ = c;
2286002Sroot 		}
2296002Sroot 		if ((obits & (1 << f)) && (nfrontp - nbackp) > 0)
2306002Sroot 			netflush();
2316002Sroot 		if (ncc > 0)
2326002Sroot 			telrcv();
2336002Sroot 		if ((obits & (1 << p)) && (pfrontp - pbackp) > 0)
2346002Sroot 			ptyflush();
2356002Sroot 	}
2366002Sroot 	cleanup();
2376002Sroot }
2386002Sroot 
2396002Sroot /*
2406002Sroot  * State for recv fsm
2416002Sroot  */
2426002Sroot #define	TS_DATA		0	/* base state */
2436002Sroot #define	TS_IAC		1	/* look for double IAC's */
2446002Sroot #define	TS_CR		2	/* CR-LF ->'s CR */
2456002Sroot #define	TS_BEGINNEG	3	/* throw away begin's... */
2466002Sroot #define	TS_ENDNEG	4	/* ...end's (suboption negotiation) */
2476002Sroot #define	TS_WILL		5	/* will option negotiation */
2486002Sroot #define	TS_WONT		6	/* wont " */
2496002Sroot #define	TS_DO		7	/* do " */
2506002Sroot #define	TS_DONT		8	/* dont " */
2516002Sroot 
2526002Sroot telrcv()
2536002Sroot {
2546002Sroot 	register int c;
2556002Sroot 	static int state = TS_DATA;
2566002Sroot 	struct sgttyb b;
2576002Sroot 
2586002Sroot 	while (ncc > 0) {
2596002Sroot 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
2606002Sroot 			return;
2616002Sroot 		c = *netip++ & 0377, ncc--;
2626002Sroot 		switch (state) {
2636002Sroot 
2646002Sroot 		case TS_DATA:
2656002Sroot 			if (c == IAC) {
2666002Sroot 				state = TS_IAC;
2676002Sroot 				break;
2686002Sroot 			}
2696002Sroot 			if (inter > 0)
2706002Sroot 				break;
2716002Sroot 			*pfrontp++ = c;
2726002Sroot 			if (!myopts[TELOPT_BINARY] && c == '\r')
2736002Sroot 				state = TS_CR;
2746002Sroot 			break;
2756002Sroot 
2766002Sroot 		case TS_CR:
2776002Sroot 			if (c && c != '\n')
2786002Sroot 				*pfrontp++ = c;
2796002Sroot 			state = TS_DATA;
2806002Sroot 			break;
2816002Sroot 
2826002Sroot 		case TS_IAC:
2836002Sroot 			switch (c) {
2846002Sroot 
2856002Sroot 			/*
2866002Sroot 			 * Send the process on the pty side an
2876002Sroot 			 * interrupt.  Do this with a NULL or
2886002Sroot 			 * interrupt char; depending on the tty mode.
2896002Sroot 			 */
2906002Sroot 			case BREAK:
2916002Sroot 			case IP:
2926002Sroot 				interrupt();
2936002Sroot 				break;
2946002Sroot 
2956002Sroot 			/*
2966002Sroot 			 * Are You There?
2976002Sroot 			 */
2986002Sroot 			case AYT:
2996002Sroot 				*pfrontp++ = BELL;
3006002Sroot 				break;
3016002Sroot 
3026002Sroot 			/*
3036002Sroot 			 * Erase Character and
3046002Sroot 			 * Erase Line
3056002Sroot 			 */
3066002Sroot 			case EC:
3076002Sroot 			case EL:
3086002Sroot 				ptyflush();	/* half-hearted */
3096002Sroot 				ioctl(pty, TIOCGETP, &b);
3106002Sroot 				*pfrontp++ = (c == EC) ?
3116002Sroot 					b.sg_erase : b.sg_kill;
3126002Sroot 				break;
3136002Sroot 
3146002Sroot 			/*
3156002Sroot 			 * Check for urgent data...
3166002Sroot 			 */
3176002Sroot 			case DM:
3186002Sroot 				break;
3196002Sroot 
3206002Sroot 			/*
3216002Sroot 			 * Begin option subnegotiation...
3226002Sroot 			 */
3236002Sroot 			case SB:
3246002Sroot 				state = TS_BEGINNEG;
3256002Sroot 				continue;
3266002Sroot 
3276002Sroot 			case WILL:
3286002Sroot 			case WONT:
3296002Sroot 			case DO:
3306002Sroot 			case DONT:
3316002Sroot 				state = TS_WILL + (c - WILL);
3326002Sroot 				continue;
3336002Sroot 
3346002Sroot 			case IAC:
3356002Sroot 				*pfrontp++ = c;
3366002Sroot 				break;
3376002Sroot 			}
3386002Sroot 			state = TS_DATA;
3396002Sroot 			break;
3406002Sroot 
3416002Sroot 		case TS_BEGINNEG:
3426002Sroot 			if (c == IAC)
3436002Sroot 				state = TS_ENDNEG;
3446002Sroot 			break;
3456002Sroot 
3466002Sroot 		case TS_ENDNEG:
3476002Sroot 			state = c == SE ? TS_DATA : TS_BEGINNEG;
3486002Sroot 			break;
3496002Sroot 
3506002Sroot 		case TS_WILL:
3516002Sroot 			if (!hisopts[c])
3526002Sroot 				willoption(c);
3536002Sroot 			state = TS_DATA;
3546002Sroot 			continue;
3556002Sroot 
3566002Sroot 		case TS_WONT:
3576002Sroot 			if (hisopts[c])
3586002Sroot 				wontoption(c);
3596002Sroot 			state = TS_DATA;
3606002Sroot 			continue;
3616002Sroot 
3626002Sroot 		case TS_DO:
3636002Sroot 			if (!myopts[c])
3646002Sroot 				dooption(c);
3656002Sroot 			state = TS_DATA;
3666002Sroot 			continue;
3676002Sroot 
3686002Sroot 		case TS_DONT:
3696002Sroot 			if (myopts[c]) {
3706002Sroot 				myopts[c] = 0;
3716002Sroot 				sprintf(nfrontp, wont, c);
3726002Sroot 				nfrontp += sizeof(wont) - 2;
3736002Sroot 			}
3746002Sroot 			state = TS_DATA;
3756002Sroot 			continue;
3766002Sroot 
3776002Sroot 		default:
3786002Sroot 			printf("netser: panic state=%d\n", state);
3796002Sroot 			exit(1);
3806002Sroot 		}
3816002Sroot 	}
3826002Sroot }
3836002Sroot 
3846002Sroot willoption(option)
3856002Sroot 	int option;
3866002Sroot {
3876002Sroot 	char *fmt;
3886002Sroot 
3896002Sroot 	switch (option) {
3906002Sroot 
3916002Sroot 	case TELOPT_BINARY:
3926002Sroot 		mode(RAW, 0);
3936002Sroot 		goto common;
3946002Sroot 
3956002Sroot 	case TELOPT_ECHO:
3966002Sroot 		mode(0, ECHO|CRMOD);
3976002Sroot 		/*FALL THRU*/
3986002Sroot 
3996002Sroot 	case TELOPT_SGA:
4006002Sroot 	common:
4016002Sroot 		hisopts[option] = 1;
4026002Sroot 		fmt = doopt;
4036002Sroot 		break;
4046002Sroot 
4056002Sroot 	case TELOPT_TM:
4066002Sroot 		fmt = dont;
4076002Sroot 		break;
4086002Sroot 
4096002Sroot 	default:
4106002Sroot 		fmt = dont;
4116002Sroot 		break;
4126002Sroot 	}
413*6023Ssam 	sprintf(nfrontp, fmt, option);
4146002Sroot 	nfrontp += sizeof(dont) - 2;
4156002Sroot }
4166002Sroot 
4176002Sroot wontoption(option)
4186002Sroot 	int option;
4196002Sroot {
4206002Sroot 	char *fmt;
4216002Sroot 
4226002Sroot 	switch (option) {
4236002Sroot 
4246002Sroot 	case TELOPT_ECHO:
4256002Sroot 		mode(ECHO|CRMOD, 0);
4266002Sroot 		goto common;
4276002Sroot 
4286002Sroot 	case TELOPT_BINARY:
4296002Sroot 		mode(0, RAW);
4306002Sroot 		/*FALL THRU*/
4316002Sroot 
4326002Sroot 	case TELOPT_SGA:
4336002Sroot 	common:
4346002Sroot 		hisopts[option] = 0;
4356002Sroot 		fmt = dont;
4366002Sroot 		break;
4376002Sroot 
4386002Sroot 	default:
4396002Sroot 		fmt = dont;
4406002Sroot 	}
4416002Sroot 	sprintf(nfrontp, fmt, option);
4426002Sroot 	nfrontp += sizeof(doopt) - 2;
4436002Sroot }
4446002Sroot 
4456002Sroot dooption(option)
4466002Sroot 	int option;
4476002Sroot {
4486002Sroot 	char *fmt;
4496002Sroot 
4506002Sroot 	switch (option) {
4516002Sroot 
4526002Sroot 	case TELOPT_TM:
4536002Sroot 		fmt = wont;
4546002Sroot 		break;
4556002Sroot 
4566002Sroot 	case TELOPT_ECHO:
4576002Sroot 		mode(ECHO|CRMOD, 0);
4586002Sroot 		goto common;
4596002Sroot 
4606002Sroot 	case TELOPT_BINARY:
4616002Sroot 		mode(RAW, 0);
4626002Sroot 		/*FALL THRU*/
4636002Sroot 
4646002Sroot 	case TELOPT_SGA:
4656002Sroot 	common:
4666002Sroot 		fmt = will;
4676002Sroot 		break;
4686002Sroot 
4696002Sroot 	default:
4706002Sroot 		fmt = wont;
4716002Sroot 		break;
4726002Sroot 	}
4736002Sroot 	sprintf(nfrontp, fmt, option);
4746002Sroot 	nfrontp += sizeof(doopt) - 2;
4756002Sroot }
4766002Sroot 
4776002Sroot mode(on, off)
4786002Sroot 	int on, off;
4796002Sroot {
4806002Sroot 	struct sgttyb b;
4816002Sroot 
4826002Sroot 	ptyflush();
4836002Sroot 	ioctl(pty, TIOCGETP, &b);
4846002Sroot 	b.sg_flags |= on;
4856002Sroot 	b.sg_flags &= ~off;
4866002Sroot 	ioctl(pty, TIOCSETP, &b);
4876002Sroot }
4886002Sroot 
4896002Sroot /*
4906002Sroot  * Send interrupt to process on other side of pty.
4916002Sroot  * If it is in raw mode, just write NULL;
4926002Sroot  * otherwise, write intr char.
4936002Sroot  */
4946002Sroot interrupt()
4956002Sroot {
4966002Sroot 	struct sgttyb b;
4976002Sroot 	struct tchars tchars;
4986002Sroot 
4996002Sroot 	ptyflush();	/* half-hearted */
5006002Sroot 	ioctl(pty, TIOCGETP, &b);
5016002Sroot 	if (b.sg_flags & RAW) {
5026002Sroot 		*pfrontp++ = '\0';
5036002Sroot 		return;
5046002Sroot 	}
5056002Sroot 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
5066002Sroot 		'\177' : tchars.t_intrc;
5076002Sroot }
5086002Sroot 
5096002Sroot ptyflush()
5106002Sroot {
5116002Sroot 	int n;
5126002Sroot 
5136002Sroot 	if ((n = pfrontp - pbackp) > 0)
5146002Sroot 		n = write(pty, pbackp, n);
5156002Sroot 	if (n < 0 && errno == EWOULDBLOCK)
5166002Sroot 		n = 0;
5176002Sroot 	pbackp += n;
5186002Sroot 	if (pbackp == pfrontp)
5196002Sroot 		pbackp = pfrontp = ptyobuf;
5206002Sroot }
5216002Sroot 
5226002Sroot netflush()
5236002Sroot {
5246002Sroot 	int n;
5256002Sroot 
5266002Sroot 	if ((n = nfrontp - nbackp) > 0)
5276002Sroot 		n = write(net, nbackp, n);
5286002Sroot 	if (n < 0 && errno == EWOULDBLOCK)
5296002Sroot 		n = 0;
5306002Sroot 	nbackp += n;
5316002Sroot 	if (nbackp == nfrontp)
5326002Sroot 		nbackp = nfrontp = netobuf;
5336002Sroot }
5346002Sroot 
535*6023Ssam toggle()
536*6023Ssam {
537*6023Ssam 	if (debug) {
538*6023Ssam 		fprintf(log, "log stopped\n");
539*6023Ssam 		if (log)
540*6023Ssam 			fclose(log);
541*6023Ssam 	} else {
542*6023Ssam 		if ((log = fopen(logfile, "a")) != NULL) {
543*6023Ssam 			setbuf(log, 0);
544*6023Ssam 			fprintf(log, "log started on /dev/pty%c\n",
545*6023Ssam 				logfile[strlen("/tmp/teldebug")]);
546*6023Ssam 			fprintf(log, "net=%d, pty=%d\n", net, pty);
547*6023Ssam 		}
548*6023Ssam 	}
549*6023Ssam 	debug = !debug;
550*6023Ssam }
551*6023Ssam 
5526002Sroot cleanup()
5536002Sroot {
5546002Sroot 	int how = 2;
5556002Sroot 
5566002Sroot 	rmut();
5576002Sroot 	vhangup();
5586002Sroot 	ioctl(net, SIOCDONE, &how);
5596002Sroot 	kill(0, SIGKILL);
5606002Sroot 	exit(1);
5616002Sroot }
5626002Sroot 
5636002Sroot #include <utmp.h>
5646002Sroot 
5656002Sroot struct	utmp wtmp;
5666002Sroot char	wtmpf[]	= "/usr/adm/wtmp";
5676002Sroot char	utmp[] = "/etc/utmp";
5686002Sroot #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
5696002Sroot #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
5706002Sroot 
5716002Sroot rmut()
5726002Sroot {
5736002Sroot 	register f;
5746002Sroot 	int found = 0;
5756002Sroot 
5766002Sroot 	f = open(utmp, 2);
5776002Sroot 	if (f >= 0) {
5786002Sroot 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
5796002Sroot 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
5806002Sroot 				continue;
5816002Sroot 			lseek(f, -(long)sizeof(wtmp), 1);
5826002Sroot 			SCPYN(wtmp.ut_name, "");
5836002Sroot 			time(&wtmp.ut_time);
5846002Sroot 			write(f, (char *)&wtmp, sizeof(wtmp));
5856002Sroot 			found++;
5866002Sroot 		}
5876002Sroot 		close(f);
5886002Sroot 	}
5896002Sroot 	if (found) {
5906002Sroot 		f = open(wtmpf, 1);
5916002Sroot 		if (f >= 0) {
5926002Sroot 			SCPYN(wtmp.ut_line, line+5);
5936002Sroot 			SCPYN(wtmp.ut_name, "");
5946002Sroot 			time(&wtmp.ut_time);
5956002Sroot 			lseek(f, (long)0, 2);
5966002Sroot 			write(f, (char *)&wtmp, sizeof(wtmp));
5976002Sroot 			close(f);
5986002Sroot 		}
5996002Sroot 	}
6006002Sroot 	chmod(line, 0666);
6016002Sroot 	chown(line, 0, 0);
6026002Sroot 	line[strlen("/dev/")] = 'p';
6036002Sroot 	chmod(line, 0666);
6046002Sroot 	chown(line, 0, 0);
6056002Sroot }
606