16460Swnj #ifndef lint 2*11834Ssam static char sccsid[] = "@(#)rwhod.c 4.8 04/04/83"; 36460Swnj #endif 46460Swnj 59215Ssam #include <sys/types.h> 69215Ssam #include <sys/socket.h> 79215Ssam #include <sys/stat.h> 89215Ssam #include <sys/ioctl.h> 99215Ssam 109215Ssam #include <netinet/in.h> 119215Ssam 129215Ssam #include <nlist.h> 136460Swnj #include <stdio.h> 146460Swnj #include <signal.h> 156460Swnj #include <errno.h> 166460Swnj #include <utmp.h> 178486Ssam #include <ctype.h> 188486Ssam #include <netdb.h> 196460Swnj 209215Ssam #include "rwhod.h" 219215Ssam 228486Ssam struct sockaddr_in sin = { AF_INET }; 236460Swnj 246460Swnj extern errno; 256460Swnj 266460Swnj char *localnet = "localnet"; 276460Swnj char *myname = "myname"; 286460Swnj 296460Swnj struct nlist nl[] = { 306460Swnj #define NL_AVENRUN 0 316460Swnj { "_avenrun" }, 329215Ssam #define NL_BOOTTIME 1 339215Ssam { "_boottime" }, 346460Swnj 0 356460Swnj }; 366460Swnj 376460Swnj struct whod mywd; 386460Swnj int s, utmpf, kmemf = -1; 396460Swnj 40*11834Ssam #define WHDRSIZE (sizeof (wd) - sizeof (wd.wd_we)) 41*11834Ssam 426460Swnj int onalrm(); 436460Swnj char *strcpy(), *sprintf(); 446460Swnj long lseek(); 456460Swnj int getkmem(); 466460Swnj 476460Swnj main() 486460Swnj { 496460Swnj struct sockaddr_in from; 506460Swnj char path[64]; 516460Swnj int addr; 528486Ssam struct servent *sp; 536460Swnj 548486Ssam sp = getservbyname("who", "udp"); 558486Ssam if (sp == 0) { 568486Ssam fprintf(stderr, "rwhod: udp/who: unknown service\n"); 578486Ssam exit(1); 588486Ssam } 596460Swnj #ifndef DEBUG 606460Swnj if (fork()) 616460Swnj exit(0); 626460Swnj { int s; 636460Swnj for (s = 0; s < 10; s++) 646460Swnj (void) close(s); 656460Swnj (void) open("/", 0); 666460Swnj (void) dup2(0, 1); 676460Swnj (void) dup2(0, 2); 686460Swnj s = open("/dev/tty", 2); 696460Swnj if (s >= 0) { 706460Swnj ioctl(s, TIOCNOTTY, 0); 716460Swnj (void) close(s); 726460Swnj } 736460Swnj } 746460Swnj #endif 756460Swnj (void) chdir("/dev"); 766460Swnj (void) signal(SIGHUP, getkmem); 776460Swnj if (getuid()) { 788486Ssam fprintf(stderr, "rwhod: not super user\n"); 796460Swnj exit(1); 806460Swnj } 816460Swnj addr = rhost(&localnet); 826460Swnj if (addr == -1) { 838486Ssam fprintf(stderr, "rwhod: no localnet\n"); 846460Swnj exit(1); 856460Swnj } 866460Swnj sin.sin_addr.s_addr = addr; 876460Swnj if (rhost(&myname) == -1) { 888486Ssam fprintf(stderr, "rwhod: don't know \"myname\"\n"); 896460Swnj exit(1); 906460Swnj } 916460Swnj strncpy(mywd.wd_hostname, myname, sizeof (mywd.wd_hostname) - 1); 926460Swnj utmpf = open("/etc/utmp", 0); 936460Swnj if (utmpf < 0) { 946460Swnj (void) close(creat("/etc/utmp", 0644)); 956460Swnj utmpf = open("/etc/utmp", 0); 966460Swnj } 976460Swnj if (utmpf < 0) { 988486Ssam perror("rwhod: /etc/utmp"); 996460Swnj exit(1); 1006460Swnj } 1019215Ssam sin.sin_port = sp->s_port; 1026460Swnj getkmem(); 1039261Ssam if ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) { 1048486Ssam perror("rwhod: socket"); 1059215Ssam exit(1); 1066460Swnj } 1079215Ssam if (bind(s, &sin, sizeof (sin), 0) < 0) { 1089215Ssam perror("rwhod: bind"); 1099215Ssam exit(1); 1109215Ssam } 1116460Swnj sigset(SIGALRM, onalrm); 1126460Swnj onalrm(); 1136460Swnj for (;;) { 1146460Swnj struct whod wd; 1159215Ssam int cc, whod, len=sizeof (from); 1166460Swnj 1179215Ssam cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0, &from, &len); 1186460Swnj if (cc <= 0) { 1196460Swnj if (cc < 0 && errno != EINTR) 1209215Ssam perror("rwhod: recv"); 1216460Swnj continue; 1226460Swnj } 1238486Ssam if (from.sin_port != sp->s_port) { 1248486Ssam fprintf(stderr, "rwhod: %d: bad from port\n", 1258486Ssam ntohs(from.sin_port)); 1266460Swnj continue; 1276460Swnj } 1288486Ssam #ifdef notdef 1298486Ssam if (gethostbyname(wd.wd_hostname) == 0) { 1308486Ssam fprintf(stderr, "rwhod: %s: unknown host\n", 1318486Ssam wd.wd_hostname); 1326460Swnj continue; 1336460Swnj } 1348486Ssam #endif 1358486Ssam if (!verify(wd.wd_hostname)) { 1368486Ssam fprintf(stderr, "rwhod: malformed host name from %x\n", 1378486Ssam from.sin_addr); 1388486Ssam continue; 1398486Ssam } 1409914Ssam (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname); 1416460Swnj whod = creat(path, 0666); 1426460Swnj if (whod < 0) { 1438486Ssam fprintf(stderr, "rwhod: "); 1448486Ssam perror(path); 1456460Swnj continue; 1466460Swnj } 147*11834Ssam #if vax || pdp11 148*11834Ssam { 149*11834Ssam int i, n = (cc - WHDRSIZE)/sizeof(struct utmp); 150*11834Ssam struct whoent *we; 151*11834Ssam 152*11834Ssam /* undo header byte swapping before writing to file */ 153*11834Ssam wd.wd_sendtime = ntohl(wd.wd_sendtime); 154*11834Ssam for (i = 0; i < 3; i++) 155*11834Ssam wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); 156*11834Ssam wd.wd_boottime = ntohl(wd.wd_boottime); 157*11834Ssam we = wd.wd_we; 158*11834Ssam for (i = 0; i < n; i++) { 159*11834Ssam we->we_idle = ntohl(we->we_idle); 160*11834Ssam we->we_utmp.ut_time = ntohl(we->we_utmp.ut_time); 161*11834Ssam we++; 162*11834Ssam } 163*11834Ssam } 164*11834Ssam #endif 1656460Swnj (void) time(&wd.wd_recvtime); 1666460Swnj (void) write(whod, (char *)&wd, cc); 1676460Swnj (void) close(whod); 1686460Swnj } 1696460Swnj } 1706460Swnj 1718486Ssam /* 1728486Ssam * Check out host name for unprintables 1738486Ssam * and other funnies before allowing a file 1748486Ssam * to be created. Sorry, but blanks aren't allowed. 1758486Ssam */ 1768486Ssam verify(name) 1778486Ssam register char *name; 1788486Ssam { 1798486Ssam register int size = 0; 1808486Ssam 1818486Ssam while (*name) { 1828486Ssam if (!isascii(*name) || !isalnum(*name)) 1838486Ssam return (0); 1848486Ssam name++, size++; 1858486Ssam } 1868486Ssam return (size > 0); 1878486Ssam } 1888486Ssam 1896460Swnj int utmptime; 1906460Swnj int utmpent; 1916577Ssam struct utmp utmp[100]; 1926460Swnj int alarmcount; 1936460Swnj 1946460Swnj onalrm() 1956460Swnj { 1966460Swnj register int i; 1976460Swnj struct stat stb; 1986577Ssam register struct whoent *we = mywd.wd_we, *wlast; 1996460Swnj int cc; 2006460Swnj double avenrun[3]; 2016460Swnj time_t now = time(0); 2026460Swnj 2036460Swnj if (alarmcount % 10 == 0) 2046460Swnj getkmem(); 2056460Swnj alarmcount++; 2066460Swnj (void) fstat(utmpf, &stb); 2076460Swnj if (stb.st_mtime != utmptime) { 2086460Swnj (void) lseek(utmpf, (long)0, 0); 2096460Swnj cc = read(utmpf, (char *)utmp, sizeof (utmp)); 2106460Swnj if (cc < 0) { 2116460Swnj perror("/etc/utmp"); 2126460Swnj return; 2136460Swnj } 2146577Ssam wlast = &mywd.wd_we[(1024 / sizeof (struct whoent)) - 1]; 2156460Swnj utmpent = cc / sizeof (struct utmp); 2166460Swnj for (i = 0; i < utmpent; i++) 2176460Swnj if (utmp[i].ut_name[0]) { 2186460Swnj we->we_utmp = utmp[i]; 2196577Ssam if (we >= wlast) 2206577Ssam break; 2216460Swnj we++; 2226460Swnj } 2236460Swnj utmpent = we - mywd.wd_we; 2246460Swnj } 2256460Swnj we = mywd.wd_we; 2266460Swnj for (i = 0; i < utmpent; i++) { 2276460Swnj if (stat(we->we_utmp.ut_line, &stb) >= 0) 2286460Swnj we->we_idle = now - stb.st_atime; 2296460Swnj we++; 2306460Swnj } 2316460Swnj (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0); 2326460Swnj (void) read(kmemf, (char *)avenrun, sizeof (avenrun)); 2336460Swnj for (i = 0; i < 3; i++) 2346460Swnj mywd.wd_loadav[i] = avenrun[i] * 100; 2356460Swnj cc = (char *)we - (char *)&mywd; 2366460Swnj (void) time(&mywd.wd_sendtime); 237*11834Ssam #if vax || pdp11 238*11834Ssam mywd.wd_sendtime = htonl(mywd.wd_sendtime); 239*11834Ssam for (i = 0; i < 3; i++) 240*11834Ssam mywd.wd_loadav[i] = htonl(mywd.wd_loadav[i]); 241*11834Ssam mywd.wd_boottime = htonl(mywd.wd_boottime); 242*11834Ssam we = mywd.wd_we; 243*11834Ssam for (i = 0; i < utmpent; i++) { 244*11834Ssam we->we_idle = htonl(we->we_idle); 245*11834Ssam we->we_utmp.ut_time = htonl(we->we_utmp.ut_time); 246*11834Ssam we++; 247*11834Ssam } 248*11834Ssam #endif 2499215Ssam (void) sendto(s, (char *)&mywd, cc, 0, &sin, sizeof (sin)); 2506460Swnj (void) alarm(60); 2516460Swnj } 2526460Swnj 2536460Swnj getkmem() 2546460Swnj { 2556460Swnj struct nlist *nlp; 2566460Swnj 2576460Swnj signal(SIGHUP, getkmem); 2586460Swnj if (kmemf >= 0) 2596460Swnj (void) close(kmemf); 2606460Swnj loop: 2616460Swnj for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) { 2626460Swnj nlp->n_value = 0; 2636460Swnj nlp->n_type = 0; 2646460Swnj } 2656460Swnj nlist("/vmunix", nl); 2666460Swnj if (nl[0].n_value == 0) { 2676460Swnj fprintf(stderr, "/vmunix namelist botch\n"); 2686460Swnj sleep(300); 2696460Swnj goto loop; 2706460Swnj } 2716460Swnj kmemf = open("/dev/kmem", 0); 2726460Swnj if (kmemf < 0) { 2736460Swnj perror("/dev/kmem"); 2746460Swnj sleep(300); 2756460Swnj goto loop; 2766460Swnj } 2779215Ssam (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, 0); 2789215Ssam (void) read(kmemf, (char *)&mywd.wd_boottime, sizeof (mywd.wd_boottime)); 2796460Swnj } 280