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*27020Sminshall static char sccsid[] = "@(#)telnetd.c 5.8 (Berkeley) 04/09/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; 263*27020Sminshall if (c == '\r') { 264*27020Sminshall if (pcc > 0 && ((*ptyip & 0377) == '\n')) { 265*27020Sminshall *nfrontp++ = *ptyip++ & 0377; 266*27020Sminshall pcc--; 267*27020Sminshall } else 268*27020Sminshall *nfrontp++ = '\0'; 269*27020Sminshall } 2706002Sroot } 2716002Sroot if ((obits & (1 << f)) && (nfrontp - nbackp) > 0) 2726002Sroot netflush(); 2736002Sroot if (ncc > 0) 2746002Sroot telrcv(); 2756002Sroot if ((obits & (1 << p)) && (pfrontp - pbackp) > 0) 2766002Sroot ptyflush(); 2776002Sroot } 2786002Sroot cleanup(); 2796002Sroot } 2806002Sroot 2816002Sroot /* 2826002Sroot * State for recv fsm 2836002Sroot */ 2846002Sroot #define TS_DATA 0 /* base state */ 2856002Sroot #define TS_IAC 1 /* look for double IAC's */ 2866002Sroot #define TS_CR 2 /* CR-LF ->'s CR */ 2876002Sroot #define TS_BEGINNEG 3 /* throw away begin's... */ 2886002Sroot #define TS_ENDNEG 4 /* ...end's (suboption negotiation) */ 2896002Sroot #define TS_WILL 5 /* will option negotiation */ 2906002Sroot #define TS_WONT 6 /* wont " */ 2916002Sroot #define TS_DO 7 /* do " */ 2926002Sroot #define TS_DONT 8 /* dont " */ 2936002Sroot 2946002Sroot telrcv() 2956002Sroot { 2966002Sroot register int c; 2976002Sroot static int state = TS_DATA; 2986002Sroot struct sgttyb b; 2996002Sroot 3006002Sroot while (ncc > 0) { 3016002Sroot if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 3026002Sroot return; 3036002Sroot c = *netip++ & 0377, ncc--; 3046002Sroot switch (state) { 3056002Sroot 30626090Sminshall case TS_CR: 30726090Sminshall state = TS_DATA; 30826499Sminshall if ((c == 0) || (c == '\n')) { 30926090Sminshall break; 31026499Sminshall } 31126090Sminshall /* FALL THROUGH */ 31226090Sminshall 3136002Sroot case TS_DATA: 3146002Sroot if (c == IAC) { 3156002Sroot state = TS_IAC; 3166002Sroot break; 3176002Sroot } 3186002Sroot if (inter > 0) 3196002Sroot break; 320*27020Sminshall /* 321*27020Sminshall * We map \r\n ==> \n, since \r\n says 322*27020Sminshall * that we want to be in column 1 of the next 323*27020Sminshall * printable line, and \n is the standard 324*27020Sminshall * unix way of saying that (\r is only good 325*27020Sminshall * if CRMOD is set, which it normally is). 326*27020Sminshall */ 32726499Sminshall if (!myopts[TELOPT_BINARY] && c == '\r') { 328*27020Sminshall if ((ncc > 0) && ('\n' == *netip)) { 329*27020Sminshall netip++; ncc--; 330*27020Sminshall c = '\n'; 331*27020Sminshall } else { 332*27020Sminshall state = TS_CR; 333*27020Sminshall } 33426499Sminshall } 33526499Sminshall *pfrontp++ = c; 3366002Sroot break; 3376002Sroot 3386002Sroot case TS_IAC: 3396002Sroot switch (c) { 3406002Sroot 3416002Sroot /* 3426002Sroot * Send the process on the pty side an 3436002Sroot * interrupt. Do this with a NULL or 3446002Sroot * interrupt char; depending on the tty mode. 3456002Sroot */ 3466002Sroot case BREAK: 3476002Sroot case IP: 3486002Sroot interrupt(); 3496002Sroot break; 3506002Sroot 3516002Sroot /* 3526002Sroot * Are You There? 3536002Sroot */ 3546002Sroot case AYT: 35517583Ssam strcpy(nfrontp, "\r\n[Yes]\r\n"); 35617583Ssam nfrontp += 9; 3576002Sroot break; 3586002Sroot 3596002Sroot /* 3606002Sroot * Erase Character and 3616002Sroot * Erase Line 3626002Sroot */ 3636002Sroot case EC: 3646002Sroot case EL: 3656002Sroot ptyflush(); /* half-hearted */ 3666002Sroot ioctl(pty, TIOCGETP, &b); 3676002Sroot *pfrontp++ = (c == EC) ? 3686002Sroot b.sg_erase : b.sg_kill; 3696002Sroot break; 3706002Sroot 3716002Sroot /* 3726002Sroot * Check for urgent data... 3736002Sroot */ 3746002Sroot case DM: 3756002Sroot break; 3766002Sroot 3776002Sroot /* 3786002Sroot * Begin option subnegotiation... 3796002Sroot */ 3806002Sroot case SB: 3816002Sroot state = TS_BEGINNEG; 3826002Sroot continue; 3836002Sroot 3846002Sroot case WILL: 3856002Sroot case WONT: 3866002Sroot case DO: 3876002Sroot case DONT: 3886002Sroot state = TS_WILL + (c - WILL); 3896002Sroot continue; 3906002Sroot 3916002Sroot case IAC: 3926002Sroot *pfrontp++ = c; 3936002Sroot break; 3946002Sroot } 3956002Sroot state = TS_DATA; 3966002Sroot break; 3976002Sroot 3986002Sroot case TS_BEGINNEG: 3996002Sroot if (c == IAC) 4006002Sroot state = TS_ENDNEG; 4016002Sroot break; 4026002Sroot 4036002Sroot case TS_ENDNEG: 4046002Sroot state = c == SE ? TS_DATA : TS_BEGINNEG; 4056002Sroot break; 4066002Sroot 4076002Sroot case TS_WILL: 4086002Sroot if (!hisopts[c]) 4096002Sroot willoption(c); 4106002Sroot state = TS_DATA; 4116002Sroot continue; 4126002Sroot 4136002Sroot case TS_WONT: 4146002Sroot if (hisopts[c]) 4156002Sroot wontoption(c); 4166002Sroot state = TS_DATA; 4176002Sroot continue; 4186002Sroot 4196002Sroot case TS_DO: 4206002Sroot if (!myopts[c]) 4216002Sroot dooption(c); 4226002Sroot state = TS_DATA; 4236002Sroot continue; 4246002Sroot 4256002Sroot case TS_DONT: 4266002Sroot if (myopts[c]) { 4276002Sroot myopts[c] = 0; 4286002Sroot sprintf(nfrontp, wont, c); 4298379Ssam nfrontp += sizeof (wont) - 2; 4306002Sroot } 4316002Sroot state = TS_DATA; 4326002Sroot continue; 4336002Sroot 4346002Sroot default: 4359218Ssam printf("telnetd: panic state=%d\n", state); 4366002Sroot exit(1); 4376002Sroot } 4386002Sroot } 4396002Sroot } 4406002Sroot 4416002Sroot willoption(option) 4426002Sroot int option; 4436002Sroot { 4446002Sroot char *fmt; 4456002Sroot 4466002Sroot switch (option) { 4476002Sroot 4486002Sroot case TELOPT_BINARY: 4496002Sroot mode(RAW, 0); 4506002Sroot goto common; 4516002Sroot 4526002Sroot case TELOPT_ECHO: 4536002Sroot mode(0, ECHO|CRMOD); 4546002Sroot /*FALL THRU*/ 4556002Sroot 4566002Sroot case TELOPT_SGA: 4576002Sroot common: 4586002Sroot hisopts[option] = 1; 4596002Sroot fmt = doopt; 4606002Sroot break; 4616002Sroot 4626002Sroot case TELOPT_TM: 4636002Sroot fmt = dont; 4646002Sroot break; 4656002Sroot 4666002Sroot default: 4676002Sroot fmt = dont; 4686002Sroot break; 4696002Sroot } 4706023Ssam sprintf(nfrontp, fmt, option); 4718379Ssam nfrontp += sizeof (dont) - 2; 4726002Sroot } 4736002Sroot 4746002Sroot wontoption(option) 4756002Sroot int option; 4766002Sroot { 4776002Sroot char *fmt; 4786002Sroot 4796002Sroot switch (option) { 4806002Sroot 4816002Sroot case TELOPT_ECHO: 4826002Sroot mode(ECHO|CRMOD, 0); 4836002Sroot goto common; 4846002Sroot 4856002Sroot case TELOPT_BINARY: 4866002Sroot mode(0, RAW); 4876002Sroot /*FALL THRU*/ 4886002Sroot 4896002Sroot case TELOPT_SGA: 4906002Sroot common: 4916002Sroot hisopts[option] = 0; 4926002Sroot fmt = dont; 4936002Sroot break; 4946002Sroot 4956002Sroot default: 4966002Sroot fmt = dont; 4976002Sroot } 4986002Sroot sprintf(nfrontp, fmt, option); 4998379Ssam nfrontp += sizeof (doopt) - 2; 5006002Sroot } 5016002Sroot 5026002Sroot dooption(option) 5036002Sroot int option; 5046002Sroot { 5056002Sroot char *fmt; 5066002Sroot 5076002Sroot switch (option) { 5086002Sroot 5096002Sroot case TELOPT_TM: 5106002Sroot fmt = wont; 5116002Sroot break; 5126002Sroot 5136002Sroot case TELOPT_ECHO: 5146002Sroot mode(ECHO|CRMOD, 0); 5156002Sroot goto common; 5166002Sroot 5176002Sroot case TELOPT_BINARY: 5186002Sroot mode(RAW, 0); 5196002Sroot /*FALL THRU*/ 5206002Sroot 5216002Sroot case TELOPT_SGA: 5226002Sroot common: 5236002Sroot fmt = will; 5246002Sroot break; 5256002Sroot 5266002Sroot default: 5276002Sroot fmt = wont; 5286002Sroot break; 5296002Sroot } 5306002Sroot sprintf(nfrontp, fmt, option); 5318379Ssam nfrontp += sizeof (doopt) - 2; 5326002Sroot } 5336002Sroot 5346002Sroot mode(on, off) 5356002Sroot int on, off; 5366002Sroot { 5376002Sroot struct sgttyb b; 5386002Sroot 5396002Sroot ptyflush(); 5406002Sroot ioctl(pty, TIOCGETP, &b); 5416002Sroot b.sg_flags |= on; 5426002Sroot b.sg_flags &= ~off; 5436002Sroot ioctl(pty, TIOCSETP, &b); 5446002Sroot } 5456002Sroot 5466002Sroot /* 5476002Sroot * Send interrupt to process on other side of pty. 5486002Sroot * If it is in raw mode, just write NULL; 5496002Sroot * otherwise, write intr char. 5506002Sroot */ 5516002Sroot interrupt() 5526002Sroot { 5536002Sroot struct sgttyb b; 5546002Sroot struct tchars tchars; 5556002Sroot 5566002Sroot ptyflush(); /* half-hearted */ 5576002Sroot ioctl(pty, TIOCGETP, &b); 5586002Sroot if (b.sg_flags & RAW) { 5596002Sroot *pfrontp++ = '\0'; 5606002Sroot return; 5616002Sroot } 5626002Sroot *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ? 5636002Sroot '\177' : tchars.t_intrc; 5646002Sroot } 5656002Sroot 5666002Sroot ptyflush() 5676002Sroot { 5686002Sroot int n; 5696002Sroot 5706002Sroot if ((n = pfrontp - pbackp) > 0) 5716002Sroot n = write(pty, pbackp, n); 5728346Ssam if (n < 0) 5738346Ssam return; 5746002Sroot pbackp += n; 5756002Sroot if (pbackp == pfrontp) 5766002Sroot pbackp = pfrontp = ptyobuf; 5776002Sroot } 5786002Sroot 5796002Sroot netflush() 5806002Sroot { 5816002Sroot int n; 5826002Sroot 5836002Sroot if ((n = nfrontp - nbackp) > 0) 5846002Sroot n = write(net, nbackp, n); 5858346Ssam if (n < 0) { 5868346Ssam if (errno == EWOULDBLOCK) 5878346Ssam return; 5888346Ssam /* should blow this guy away... */ 5898346Ssam return; 5908346Ssam } 5916002Sroot nbackp += n; 5926002Sroot if (nbackp == nfrontp) 5936002Sroot nbackp = nfrontp = netobuf; 5946002Sroot } 5956002Sroot 5966002Sroot cleanup() 5976002Sroot { 5986002Sroot 5996002Sroot rmut(); 60010008Ssam vhangup(); /* XXX */ 60110191Ssam shutdown(net, 2); 6026002Sroot exit(1); 6036002Sroot } 6046002Sroot 6056002Sroot #include <utmp.h> 6066002Sroot 6076002Sroot struct utmp wtmp; 6086002Sroot char wtmpf[] = "/usr/adm/wtmp"; 60923567Sbloom char utmpf[] = "/etc/utmp"; 61023567Sbloom #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 61123567Sbloom #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 6126002Sroot 6136002Sroot rmut() 6146002Sroot { 6156002Sroot register f; 6166002Sroot int found = 0; 61723567Sbloom struct utmp *u, *utmp; 61823567Sbloom int nutmp; 61923567Sbloom struct stat statbf; 6206002Sroot 62123567Sbloom f = open(utmpf, O_RDWR); 6226002Sroot if (f >= 0) { 62323567Sbloom fstat(f, &statbf); 62423567Sbloom utmp = (struct utmp *)malloc(statbf.st_size); 62523567Sbloom if (!utmp) 62623567Sbloom syslog(LOG_ERR, "utmp malloc failed"); 62723567Sbloom if (statbf.st_size && utmp) { 62823567Sbloom nutmp = read(f, utmp, statbf.st_size); 62923567Sbloom nutmp /= sizeof(struct utmp); 63023567Sbloom 63123567Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 63223567Sbloom if (SCMPN(u->ut_line, line+5) || 63323567Sbloom u->ut_name[0]==0) 63423567Sbloom continue; 63523567Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 63623567Sbloom SCPYN(u->ut_name, ""); 63723567Sbloom SCPYN(u->ut_host, ""); 63823567Sbloom time(&u->ut_time); 63923567Sbloom write(f, (char *)u, sizeof(wtmp)); 64023567Sbloom found++; 64123567Sbloom } 6426002Sroot } 6436002Sroot close(f); 6446002Sroot } 6456002Sroot if (found) { 64617583Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 6476002Sroot if (f >= 0) { 6486002Sroot SCPYN(wtmp.ut_line, line+5); 6496002Sroot SCPYN(wtmp.ut_name, ""); 65012683Ssam SCPYN(wtmp.ut_host, ""); 6516002Sroot time(&wtmp.ut_time); 65223567Sbloom write(f, (char *)&wtmp, sizeof(wtmp)); 6536002Sroot close(f); 6546002Sroot } 6556002Sroot } 6566002Sroot chmod(line, 0666); 6576002Sroot chown(line, 0, 0); 6586002Sroot line[strlen("/dev/")] = 'p'; 6596002Sroot chmod(line, 0666); 6606002Sroot chown(line, 0, 0); 6616002Sroot } 662