16295Sroot #ifndef lint 2*12683Ssam static char sccsid[] = "@(#)telnetd.c 4.20 83/05/22"; 36295Sroot #endif 46295Sroot 56002Sroot /* 66002Sroot * Stripped-down telnet server. 76002Sroot */ 89218Ssam #include <sys/types.h> 99218Ssam #include <sys/socket.h> 109218Ssam 119218Ssam #include <netinet/in.h> 129218Ssam 1312216Ssam #include <arpa/telnet.h> 1412216Ssam 156002Sroot #include <stdio.h> 166002Sroot #include <signal.h> 176002Sroot #include <errno.h> 186002Sroot #include <sgtty.h> 196002Sroot #include <wait.h> 208346Ssam #include <netdb.h> 219218Ssam 226002Sroot #define BELL '\07' 236002Sroot 246002Sroot char hisopts[256]; 256002Sroot char myopts[256]; 266002Sroot 276002Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 286002Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 296002Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 306002Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 316002Sroot 326002Sroot /* 336002Sroot * I/O data buffers, pointers, and counters. 346002Sroot */ 356002Sroot char ptyibuf[BUFSIZ], *ptyip = ptyibuf; 366002Sroot char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; 376002Sroot char netibuf[BUFSIZ], *netip = netibuf; 386388Ssam char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 396002Sroot int pcc, ncc; 406002Sroot 416002Sroot int pty, net; 426002Sroot int inter; 4310418Ssam int reapchild(); 446002Sroot extern int errno; 456002Sroot char line[] = "/dev/ptyp0"; 466002Sroot 478346Ssam struct sockaddr_in sin = { AF_INET }; 486002Sroot 496002Sroot main(argc, argv) 506002Sroot char *argv[]; 516002Sroot { 5210418Ssam int s, pid, options; 538346Ssam struct servent *sp; 546002Sroot 558346Ssam sp = getservbyname("telnet", "tcp"); 568346Ssam if (sp == 0) { 578346Ssam fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); 588346Ssam exit(1); 598346Ssam } 608346Ssam sin.sin_port = sp->s_port; 616002Sroot argc--, argv++; 6210418Ssam if (argc > 0 && !strcmp(*argv, "-d")) { 6310418Ssam options |= SO_DEBUG; 6410418Ssam argc--, argv++; 6510418Ssam } 668346Ssam if (argc > 0) { 678346Ssam sin.sin_port = atoi(*argv); 688346Ssam if (sin.sin_port <= 0) { 698346Ssam fprintf(stderr, "telnetd: %s: bad port #\n", *argv); 708346Ssam exit(1); 718346Ssam } 729969Ssam sin.sin_port = htons((u_short)sin.sin_port); 738346Ssam } 748456Ssam #ifndef DEBUG 758456Ssam if (fork()) 768456Ssam exit(0); 778456Ssam for (s = 0; s < 10; s++) 788456Ssam (void) close(s); 798456Ssam (void) open("/", 0); 808456Ssam (void) dup2(0, 1); 818456Ssam (void) dup2(0, 2); 828456Ssam { int tt = open("/dev/tty", 2); 838456Ssam if (tt > 0) { 848456Ssam ioctl(tt, TIOCNOTTY, 0); 858456Ssam close(tt); 868456Ssam } 878456Ssam } 888456Ssam #endif 899218Ssam again: 909288Ssam s = socket(AF_INET, SOCK_STREAM, 0, 0); 919218Ssam if (s < 0) { 929218Ssam perror("telnetd: socket");; 939218Ssam sleep(5); 949218Ssam goto again; 959218Ssam } 9610418Ssam if (options & SO_DEBUG) 9710418Ssam if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 9810418Ssam perror("telnetd: setsockopt (SO_DEBUG)"); 9910418Ssam if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 10010418Ssam perror("telnetd: setsockopt (SO_KEEPALIVE)"); 1019218Ssam while (bind(s, (caddr_t)&sin, sizeof (sin), 0) < 0) { 1029218Ssam perror("telnetd: bind"); 1039218Ssam sleep(5); 1049218Ssam } 10510587Ssam sigset(SIGCHLD, reapchild); 1069218Ssam listen(s, 10); 1076002Sroot for (;;) { 108*12683Ssam struct sockaddr_in from; 109*12683Ssam int s2, fromlen = sizeof (from); 1109218Ssam 111*12683Ssam s2 = accept(s, (caddr_t)&from, &fromlen); 1129218Ssam if (s2 < 0) { 11310418Ssam if (errno == EINTR) 11410418Ssam continue; 1159244Ssam perror("telnetd: accept"); 1166002Sroot sleep(1); 1176002Sroot continue; 1186002Sroot } 1196002Sroot if ((pid = fork()) < 0) 1206002Sroot printf("Out of processes\n"); 12111221Ssam else if (pid == 0) { 12211221Ssam signal(SIGCHLD, SIG_IGN); 123*12683Ssam doit(s2, &from); 12411221Ssam } 1259218Ssam close(s2); 1266002Sroot } 1276002Sroot /*NOTREACHED*/ 1286002Sroot } 1296002Sroot 13010418Ssam reapchild() 13110418Ssam { 13210418Ssam union wait status; 13310418Ssam 13410418Ssam while (wait3(&status, WNOHANG, 0) > 0) 13510418Ssam ; 13610418Ssam } 13710418Ssam 1386002Sroot int cleanup(); 1396002Sroot 1406002Sroot /* 1416002Sroot * Get a pty, scan input lines. 1426002Sroot */ 143*12683Ssam doit(f, who) 144*12683Ssam int f; 145*12683Ssam struct sockaddr_in *who; 1466002Sroot { 147*12683Ssam char *cp = line, *host, *ntoa(); 1486002Sroot int i, p, cc, t; 1496002Sroot struct sgttyb b; 150*12683Ssam struct hostent *hp; 1516002Sroot 1526002Sroot for (i = 0; i < 16; i++) { 1536002Sroot cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 1546002Sroot p = open(cp, 2); 1556002Sroot if (p > 0) 1566002Sroot goto gotpty; 1576002Sroot } 1589244Ssam fatal(f, "All network ports in use"); 1599244Ssam /*NOTREACHED*/ 1606002Sroot gotpty: 1616002Sroot dup2(f, 0); 1626002Sroot cp[strlen("/dev/")] = 't'; 1636002Sroot t = open("/dev/tty", 2); 1646002Sroot if (t >= 0) { 1656002Sroot ioctl(t, TIOCNOTTY, 0); 1666002Sroot close(t); 1676002Sroot } 1686002Sroot t = open(cp, 2); 1699244Ssam if (t < 0) 1709244Ssam fatalperror(f, cp, errno); 1716002Sroot ioctl(t, TIOCGETP, &b); 1726388Ssam b.sg_flags = CRMOD|XTABS|ANYP; 1736002Sroot ioctl(t, TIOCSETP, &b); 1746388Ssam ioctl(p, TIOCGETP, &b); 1758379Ssam b.sg_flags &= ~ECHO; 1766388Ssam ioctl(p, TIOCSETP, &b); 177*12683Ssam hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr), 178*12683Ssam who->sin_family); 179*12683Ssam if (hp) 180*12683Ssam host = hp->h_name; 181*12683Ssam else 182*12683Ssam host = ntoa(who->sin_addr); 1839244Ssam if ((i = fork()) < 0) 1849244Ssam fatalperror(f, "fork", errno); 1856002Sroot if (i) 1866002Sroot telnet(f, p); 1876002Sroot close(f); 1886002Sroot close(p); 1896002Sroot dup2(t, 0); 1906002Sroot dup2(t, 1); 1916002Sroot dup2(t, 2); 1926002Sroot close(t); 193*12683Ssam execl("/bin/login", "telnet-login", "-h", host, 0); 1949244Ssam fatalperror(f, "/bin/login", errno); 1959244Ssam /*NOTREACHED*/ 1969244Ssam } 1979244Ssam 1989244Ssam fatal(f, msg) 1999244Ssam int f; 2009244Ssam char *msg; 2019244Ssam { 2029244Ssam char buf[BUFSIZ]; 2039244Ssam 2049244Ssam (void) sprintf(buf, "telnetd: %s.\n", msg); 2059244Ssam (void) write(f, buf, strlen(buf)); 2066002Sroot exit(1); 2076002Sroot } 2086002Sroot 2099244Ssam fatalperror(f, msg, errno) 2109244Ssam int f; 2119244Ssam char *msg; 2129244Ssam int errno; 2139244Ssam { 2149244Ssam char buf[BUFSIZ]; 2159244Ssam extern char *sys_errlist[]; 2169244Ssam 2179244Ssam (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 2189244Ssam fatal(f, buf); 2199244Ssam } 2209244Ssam 2216002Sroot /* 2226002Sroot * Main loop. Select from pty and network, and 2236002Sroot * hand data to telnet receiver finite state machine. 2246002Sroot */ 2256002Sroot telnet(f, p) 2266002Sroot { 2276002Sroot int on = 1; 2286002Sroot 2296002Sroot net = f, pty = p; 2306002Sroot ioctl(f, FIONBIO, &on); 2316002Sroot ioctl(p, FIONBIO, &on); 2326002Sroot signal(SIGTSTP, SIG_IGN); 2336002Sroot sigset(SIGCHLD, cleanup); 2346002Sroot 2358379Ssam /* 2368379Ssam * Request to do remote echo. 2378379Ssam */ 2388379Ssam dooption(TELOPT_ECHO); 2398379Ssam myopts[TELOPT_ECHO] = 1; 2406002Sroot for (;;) { 2416002Sroot int ibits = 0, obits = 0; 2426002Sroot register int c; 2436002Sroot 2446002Sroot /* 2456002Sroot * Never look for input if there's still 2466002Sroot * stuff in the corresponding output buffer 2476002Sroot */ 2486002Sroot if (nfrontp - nbackp) 2496002Sroot obits |= (1 << f); 2506002Sroot else 2516002Sroot ibits |= (1 << p); 2526002Sroot if (pfrontp - pbackp) 2536002Sroot obits |= (1 << p); 2546002Sroot else 2556002Sroot ibits |= (1 << f); 2566002Sroot if (ncc < 0 && pcc < 0) 2576002Sroot break; 2589218Ssam select(16, &ibits, &obits, 0, 0); 2596002Sroot if (ibits == 0 && obits == 0) { 2606002Sroot sleep(5); 2616002Sroot continue; 2626002Sroot } 2636002Sroot 2646002Sroot /* 2656002Sroot * Something to read from the network... 2666002Sroot */ 2676002Sroot if (ibits & (1 << f)) { 2686002Sroot ncc = read(f, netibuf, BUFSIZ); 2696002Sroot if (ncc < 0 && errno == EWOULDBLOCK) 2706002Sroot ncc = 0; 2716002Sroot else { 2726002Sroot if (ncc <= 0) 2736002Sroot break; 2746002Sroot netip = netibuf; 2756002Sroot } 2766002Sroot } 2776002Sroot 2786002Sroot /* 2796002Sroot * Something to read from the pty... 2806002Sroot */ 2816002Sroot if (ibits & (1 << p)) { 2826002Sroot pcc = read(p, ptyibuf, BUFSIZ); 2836002Sroot if (pcc < 0 && errno == EWOULDBLOCK) 2846002Sroot pcc = 0; 2856002Sroot else { 2866002Sroot if (pcc <= 0) 2876002Sroot break; 2886002Sroot ptyip = ptyibuf; 2896002Sroot } 2906002Sroot } 2916002Sroot 2926002Sroot while (pcc > 0) { 2936002Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 2946002Sroot break; 2956002Sroot c = *ptyip++ & 0377, pcc--; 2966002Sroot if (c == IAC) 2976002Sroot *nfrontp++ = c; 2986002Sroot *nfrontp++ = c; 2996002Sroot } 3006002Sroot if ((obits & (1 << f)) && (nfrontp - nbackp) > 0) 3016002Sroot netflush(); 3026002Sroot if (ncc > 0) 3036002Sroot telrcv(); 3046002Sroot if ((obits & (1 << p)) && (pfrontp - pbackp) > 0) 3056002Sroot ptyflush(); 3066002Sroot } 3076002Sroot cleanup(); 3086002Sroot } 3096002Sroot 3106002Sroot /* 3116002Sroot * State for recv fsm 3126002Sroot */ 3136002Sroot #define TS_DATA 0 /* base state */ 3146002Sroot #define TS_IAC 1 /* look for double IAC's */ 3156002Sroot #define TS_CR 2 /* CR-LF ->'s CR */ 3166002Sroot #define TS_BEGINNEG 3 /* throw away begin's... */ 3176002Sroot #define TS_ENDNEG 4 /* ...end's (suboption negotiation) */ 3186002Sroot #define TS_WILL 5 /* will option negotiation */ 3196002Sroot #define TS_WONT 6 /* wont " */ 3206002Sroot #define TS_DO 7 /* do " */ 3216002Sroot #define TS_DONT 8 /* dont " */ 3226002Sroot 3236002Sroot telrcv() 3246002Sroot { 3256002Sroot register int c; 3266002Sroot static int state = TS_DATA; 3276002Sroot struct sgttyb b; 3286002Sroot 3296002Sroot while (ncc > 0) { 3306002Sroot if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 3316002Sroot return; 3326002Sroot c = *netip++ & 0377, ncc--; 3336002Sroot switch (state) { 3346002Sroot 3356002Sroot case TS_DATA: 3366002Sroot if (c == IAC) { 3376002Sroot state = TS_IAC; 3386002Sroot break; 3396002Sroot } 3406002Sroot if (inter > 0) 3416002Sroot break; 3426002Sroot *pfrontp++ = c; 3436002Sroot if (!myopts[TELOPT_BINARY] && c == '\r') 3446002Sroot state = TS_CR; 3456002Sroot break; 3466002Sroot 3476002Sroot case TS_CR: 3486002Sroot if (c && c != '\n') 3496002Sroot *pfrontp++ = c; 3506002Sroot state = TS_DATA; 3516002Sroot break; 3526002Sroot 3536002Sroot case TS_IAC: 3546002Sroot switch (c) { 3556002Sroot 3566002Sroot /* 3576002Sroot * Send the process on the pty side an 3586002Sroot * interrupt. Do this with a NULL or 3596002Sroot * interrupt char; depending on the tty mode. 3606002Sroot */ 3616002Sroot case BREAK: 3626002Sroot case IP: 3636002Sroot interrupt(); 3646002Sroot break; 3656002Sroot 3666002Sroot /* 3676002Sroot * Are You There? 3686002Sroot */ 3696002Sroot case AYT: 3706002Sroot *pfrontp++ = BELL; 3716002Sroot break; 3726002Sroot 3736002Sroot /* 3746002Sroot * Erase Character and 3756002Sroot * Erase Line 3766002Sroot */ 3776002Sroot case EC: 3786002Sroot case EL: 3796002Sroot ptyflush(); /* half-hearted */ 3806002Sroot ioctl(pty, TIOCGETP, &b); 3816002Sroot *pfrontp++ = (c == EC) ? 3826002Sroot b.sg_erase : b.sg_kill; 3836002Sroot break; 3846002Sroot 3856002Sroot /* 3866002Sroot * Check for urgent data... 3876002Sroot */ 3886002Sroot case DM: 3896002Sroot break; 3906002Sroot 3916002Sroot /* 3926002Sroot * Begin option subnegotiation... 3936002Sroot */ 3946002Sroot case SB: 3956002Sroot state = TS_BEGINNEG; 3966002Sroot continue; 3976002Sroot 3986002Sroot case WILL: 3996002Sroot case WONT: 4006002Sroot case DO: 4016002Sroot case DONT: 4026002Sroot state = TS_WILL + (c - WILL); 4036002Sroot continue; 4046002Sroot 4056002Sroot case IAC: 4066002Sroot *pfrontp++ = c; 4076002Sroot break; 4086002Sroot } 4096002Sroot state = TS_DATA; 4106002Sroot break; 4116002Sroot 4126002Sroot case TS_BEGINNEG: 4136002Sroot if (c == IAC) 4146002Sroot state = TS_ENDNEG; 4156002Sroot break; 4166002Sroot 4176002Sroot case TS_ENDNEG: 4186002Sroot state = c == SE ? TS_DATA : TS_BEGINNEG; 4196002Sroot break; 4206002Sroot 4216002Sroot case TS_WILL: 4226002Sroot if (!hisopts[c]) 4236002Sroot willoption(c); 4246002Sroot state = TS_DATA; 4256002Sroot continue; 4266002Sroot 4276002Sroot case TS_WONT: 4286002Sroot if (hisopts[c]) 4296002Sroot wontoption(c); 4306002Sroot state = TS_DATA; 4316002Sroot continue; 4326002Sroot 4336002Sroot case TS_DO: 4346002Sroot if (!myopts[c]) 4356002Sroot dooption(c); 4366002Sroot state = TS_DATA; 4376002Sroot continue; 4386002Sroot 4396002Sroot case TS_DONT: 4406002Sroot if (myopts[c]) { 4416002Sroot myopts[c] = 0; 4426002Sroot sprintf(nfrontp, wont, c); 4438379Ssam nfrontp += sizeof (wont) - 2; 4446002Sroot } 4456002Sroot state = TS_DATA; 4466002Sroot continue; 4476002Sroot 4486002Sroot default: 4499218Ssam printf("telnetd: panic state=%d\n", state); 4506002Sroot exit(1); 4516002Sroot } 4526002Sroot } 4536002Sroot } 4546002Sroot 4556002Sroot willoption(option) 4566002Sroot int option; 4576002Sroot { 4586002Sroot char *fmt; 4596002Sroot 4606002Sroot switch (option) { 4616002Sroot 4626002Sroot case TELOPT_BINARY: 4636002Sroot mode(RAW, 0); 4646002Sroot goto common; 4656002Sroot 4666002Sroot case TELOPT_ECHO: 4676002Sroot mode(0, ECHO|CRMOD); 4686002Sroot /*FALL THRU*/ 4696002Sroot 4706002Sroot case TELOPT_SGA: 4716002Sroot common: 4726002Sroot hisopts[option] = 1; 4736002Sroot fmt = doopt; 4746002Sroot break; 4756002Sroot 4766002Sroot case TELOPT_TM: 4776002Sroot fmt = dont; 4786002Sroot break; 4796002Sroot 4806002Sroot default: 4816002Sroot fmt = dont; 4826002Sroot break; 4836002Sroot } 4846023Ssam sprintf(nfrontp, fmt, option); 4858379Ssam nfrontp += sizeof (dont) - 2; 4866002Sroot } 4876002Sroot 4886002Sroot wontoption(option) 4896002Sroot int option; 4906002Sroot { 4916002Sroot char *fmt; 4926002Sroot 4936002Sroot switch (option) { 4946002Sroot 4956002Sroot case TELOPT_ECHO: 4966002Sroot mode(ECHO|CRMOD, 0); 4976002Sroot goto common; 4986002Sroot 4996002Sroot case TELOPT_BINARY: 5006002Sroot mode(0, RAW); 5016002Sroot /*FALL THRU*/ 5026002Sroot 5036002Sroot case TELOPT_SGA: 5046002Sroot common: 5056002Sroot hisopts[option] = 0; 5066002Sroot fmt = dont; 5076002Sroot break; 5086002Sroot 5096002Sroot default: 5106002Sroot fmt = dont; 5116002Sroot } 5126002Sroot sprintf(nfrontp, fmt, option); 5138379Ssam nfrontp += sizeof (doopt) - 2; 5146002Sroot } 5156002Sroot 5166002Sroot dooption(option) 5176002Sroot int option; 5186002Sroot { 5196002Sroot char *fmt; 5206002Sroot 5216002Sroot switch (option) { 5226002Sroot 5236002Sroot case TELOPT_TM: 5246002Sroot fmt = wont; 5256002Sroot break; 5266002Sroot 5276002Sroot case TELOPT_ECHO: 5286002Sroot mode(ECHO|CRMOD, 0); 5296002Sroot goto common; 5306002Sroot 5316002Sroot case TELOPT_BINARY: 5326002Sroot mode(RAW, 0); 5336002Sroot /*FALL THRU*/ 5346002Sroot 5356002Sroot case TELOPT_SGA: 5366002Sroot common: 5376002Sroot fmt = will; 5386002Sroot break; 5396002Sroot 5406002Sroot default: 5416002Sroot fmt = wont; 5426002Sroot break; 5436002Sroot } 5446002Sroot sprintf(nfrontp, fmt, option); 5458379Ssam nfrontp += sizeof (doopt) - 2; 5466002Sroot } 5476002Sroot 5486002Sroot mode(on, off) 5496002Sroot int on, off; 5506002Sroot { 5516002Sroot struct sgttyb b; 5526002Sroot 5536002Sroot ptyflush(); 5546002Sroot ioctl(pty, TIOCGETP, &b); 5556002Sroot b.sg_flags |= on; 5566002Sroot b.sg_flags &= ~off; 5576002Sroot ioctl(pty, TIOCSETP, &b); 5586002Sroot } 5596002Sroot 5606002Sroot /* 5616002Sroot * Send interrupt to process on other side of pty. 5626002Sroot * If it is in raw mode, just write NULL; 5636002Sroot * otherwise, write intr char. 5646002Sroot */ 5656002Sroot interrupt() 5666002Sroot { 5676002Sroot struct sgttyb b; 5686002Sroot struct tchars tchars; 5696002Sroot 5706002Sroot ptyflush(); /* half-hearted */ 5716002Sroot ioctl(pty, TIOCGETP, &b); 5726002Sroot if (b.sg_flags & RAW) { 5736002Sroot *pfrontp++ = '\0'; 5746002Sroot return; 5756002Sroot } 5766002Sroot *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 5776002Sroot '\177' : tchars.t_intrc; 5786002Sroot } 5796002Sroot 5806002Sroot ptyflush() 5816002Sroot { 5826002Sroot int n; 5836002Sroot 5846002Sroot if ((n = pfrontp - pbackp) > 0) 5856002Sroot n = write(pty, pbackp, n); 5868346Ssam if (n < 0) 5878346Ssam return; 5886002Sroot pbackp += n; 5896002Sroot if (pbackp == pfrontp) 5906002Sroot pbackp = pfrontp = ptyobuf; 5916002Sroot } 5926002Sroot 5936002Sroot netflush() 5946002Sroot { 5956002Sroot int n; 5966002Sroot 5976002Sroot if ((n = nfrontp - nbackp) > 0) 5986002Sroot n = write(net, nbackp, n); 5998346Ssam if (n < 0) { 6008346Ssam if (errno == EWOULDBLOCK) 6018346Ssam return; 6028346Ssam /* should blow this guy away... */ 6038346Ssam return; 6048346Ssam } 6056002Sroot nbackp += n; 6066002Sroot if (nbackp == nfrontp) 6076002Sroot nbackp = nfrontp = netobuf; 6086002Sroot } 6096002Sroot 6106002Sroot cleanup() 6116002Sroot { 6126002Sroot 6136002Sroot rmut(); 61410008Ssam vhangup(); /* XXX */ 61510191Ssam shutdown(net, 2); 6166002Sroot kill(0, SIGKILL); 6176002Sroot exit(1); 6186002Sroot } 6196002Sroot 6206002Sroot #include <utmp.h> 6216002Sroot 6226002Sroot struct utmp wtmp; 6236002Sroot char wtmpf[] = "/usr/adm/wtmp"; 6246002Sroot char utmp[] = "/etc/utmp"; 6258379Ssam #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 6268379Ssam #define SCMPN(a, b) strncmp(a, b, sizeof (a)) 6276002Sroot 6286002Sroot rmut() 6296002Sroot { 6306002Sroot register f; 6316002Sroot int found = 0; 6326002Sroot 6336002Sroot f = open(utmp, 2); 6346002Sroot if (f >= 0) { 6358379Ssam while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { 6366002Sroot if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 6376002Sroot continue; 6388379Ssam lseek(f, -(long)sizeof (wtmp), 1); 6396002Sroot SCPYN(wtmp.ut_name, ""); 640*12683Ssam SCPYN(wtmp.ut_host, ""); 6416002Sroot time(&wtmp.ut_time); 6428379Ssam write(f, (char *)&wtmp, sizeof (wtmp)); 6436002Sroot found++; 6446002Sroot } 6456002Sroot close(f); 6466002Sroot } 6476002Sroot if (found) { 6486002Sroot f = open(wtmpf, 1); 6496002Sroot if (f >= 0) { 6506002Sroot SCPYN(wtmp.ut_line, line+5); 6516002Sroot SCPYN(wtmp.ut_name, ""); 652*12683Ssam SCPYN(wtmp.ut_host, ""); 6536002Sroot time(&wtmp.ut_time); 6546002Sroot lseek(f, (long)0, 2); 6558379Ssam write(f, (char *)&wtmp, sizeof (wtmp)); 6566002Sroot close(f); 6576002Sroot } 6586002Sroot } 6596002Sroot chmod(line, 0666); 6606002Sroot chown(line, 0, 0); 6616002Sroot line[strlen("/dev/")] = 'p'; 6626002Sroot chmod(line, 0666); 6636002Sroot chown(line, 0, 0); 6646002Sroot } 665*12683Ssam 666*12683Ssam /* 667*12683Ssam * Convert network-format internet address 668*12683Ssam * to base 256 d.d.d.d representation. 669*12683Ssam */ 670*12683Ssam char * 671*12683Ssam ntoa(in) 672*12683Ssam struct in_addr in; 673*12683Ssam { 674*12683Ssam static char b[18]; 675*12683Ssam register char *p; 676*12683Ssam 677*12683Ssam p = (char *)∈ 678*12683Ssam #define UC(b) (((int)b)&0xff) 679*12683Ssam sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 680*12683Ssam return (b); 681*12683Ssam } 682