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 *)∈ 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