1 #ifndef lint 2 static char sccsid[] = "@(#)rwhod.c 4.6 82/11/15"; 3 #endif 4 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <sys/stat.h> 8 #include <sys/ioctl.h> 9 10 #include <netinet/in.h> 11 12 #include <nlist.h> 13 #include <stdio.h> 14 #include <signal.h> 15 #include <errno.h> 16 #include <utmp.h> 17 #include <ctype.h> 18 #include <netdb.h> 19 20 #include "rwhod.h" 21 22 struct sockaddr_in sin = { AF_INET }; 23 24 extern errno; 25 26 char *localnet = "localnet"; 27 char *myname = "myname"; 28 29 struct nlist nl[] = { 30 #define NL_AVENRUN 0 31 { "_avenrun" }, 32 #define NL_BOOTTIME 1 33 { "_boottime" }, 34 0 35 }; 36 37 struct whod mywd; 38 int s, utmpf, kmemf = -1; 39 40 int onalrm(); 41 char *strcpy(), *sprintf(); 42 long lseek(); 43 int getkmem(); 44 45 main() 46 { 47 struct sockaddr_in from; 48 char path[64]; 49 int addr; 50 struct servent *sp; 51 52 sp = getservbyname("who", "udp"); 53 if (sp == 0) { 54 fprintf(stderr, "rwhod: udp/who: unknown service\n"); 55 exit(1); 56 } 57 sp->s_port = htons(sp->s_port); 58 #ifndef DEBUG 59 if (fork()) 60 exit(0); 61 { int s; 62 for (s = 0; s < 10; s++) 63 (void) close(s); 64 (void) open("/", 0); 65 (void) dup2(0, 1); 66 (void) dup2(0, 2); 67 s = open("/dev/tty", 2); 68 if (s >= 0) { 69 ioctl(s, TIOCNOTTY, 0); 70 (void) close(s); 71 } 72 } 73 #endif 74 (void) chdir("/dev"); 75 (void) signal(SIGHUP, getkmem); 76 if (getuid()) { 77 fprintf(stderr, "rwhod: not super user\n"); 78 exit(1); 79 } 80 addr = rhost(&localnet); 81 if (addr == -1) { 82 fprintf(stderr, "rwhod: no localnet\n"); 83 exit(1); 84 } 85 sin.sin_addr.s_addr = addr; 86 if (rhost(&myname) == -1) { 87 fprintf(stderr, "rwhod: don't know \"myname\"\n"); 88 exit(1); 89 } 90 strncpy(mywd.wd_hostname, myname, sizeof (mywd.wd_hostname) - 1); 91 utmpf = open("/etc/utmp", 0); 92 if (utmpf < 0) { 93 (void) close(creat("/etc/utmp", 0644)); 94 utmpf = open("/etc/utmp", 0); 95 } 96 if (utmpf < 0) { 97 perror("rwhod: /etc/utmp"); 98 exit(1); 99 } 100 sin.sin_port = sp->s_port; 101 getkmem(); 102 if ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) { 103 perror("rwhod: socket"); 104 exit(1); 105 } 106 if (bind(s, &sin, sizeof (sin), 0) < 0) { 107 perror("rwhod: bind"); 108 exit(1); 109 } 110 sigset(SIGALRM, onalrm); 111 onalrm(); 112 for (;;) { 113 struct whod wd; 114 int cc, whod, len=sizeof (from); 115 116 cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0, &from, &len); 117 if (cc <= 0) { 118 if (cc < 0 && errno != EINTR) 119 perror("rwhod: recv"); 120 continue; 121 } 122 if (from.sin_port != sp->s_port) { 123 fprintf(stderr, "rwhod: %d: bad from port\n", 124 ntohs(from.sin_port)); 125 continue; 126 } 127 #ifdef notdef 128 if (gethostbyname(wd.wd_hostname) == 0) { 129 fprintf(stderr, "rwhod: %s: unknown host\n", 130 wd.wd_hostname); 131 continue; 132 } 133 #endif 134 if (!verify(wd.wd_hostname)) { 135 fprintf(stderr, "rwhod: malformed host name from %x\n", 136 from.sin_addr); 137 continue; 138 } 139 (void) sprintf(path, "/etc/whod.%s", wd.wd_hostname); 140 whod = creat(path, 0666); 141 if (whod < 0) { 142 fprintf(stderr, "rwhod: "); 143 perror(path); 144 continue; 145 } 146 (void) time(&wd.wd_recvtime); 147 (void) write(whod, (char *)&wd, cc); 148 (void) close(whod); 149 } 150 } 151 152 /* 153 * Check out host name for unprintables 154 * and other funnies before allowing a file 155 * to be created. Sorry, but blanks aren't allowed. 156 */ 157 verify(name) 158 register char *name; 159 { 160 register int size = 0; 161 162 while (*name) { 163 if (!isascii(*name) || !isalnum(*name)) 164 return (0); 165 name++, size++; 166 } 167 return (size > 0); 168 } 169 170 int utmptime; 171 int utmpent; 172 struct utmp utmp[100]; 173 int alarmcount; 174 175 onalrm() 176 { 177 register int i; 178 struct stat stb; 179 register struct whoent *we = mywd.wd_we, *wlast; 180 int cc; 181 double avenrun[3]; 182 time_t now = time(0); 183 184 if (alarmcount % 10 == 0) 185 getkmem(); 186 alarmcount++; 187 (void) fstat(utmpf, &stb); 188 if (stb.st_mtime != utmptime) { 189 (void) lseek(utmpf, (long)0, 0); 190 cc = read(utmpf, (char *)utmp, sizeof (utmp)); 191 if (cc < 0) { 192 perror("/etc/utmp"); 193 return; 194 } 195 wlast = &mywd.wd_we[(1024 / sizeof (struct whoent)) - 1]; 196 utmpent = cc / sizeof (struct utmp); 197 for (i = 0; i < utmpent; i++) 198 if (utmp[i].ut_name[0]) { 199 we->we_utmp = utmp[i]; 200 if (we >= wlast) 201 break; 202 we++; 203 } 204 utmpent = we - mywd.wd_we; 205 } 206 we = mywd.wd_we; 207 for (i = 0; i < utmpent; i++) { 208 if (stat(we->we_utmp.ut_line, &stb) >= 0) 209 we->we_idle = now - stb.st_atime; 210 we++; 211 } 212 (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0); 213 (void) read(kmemf, (char *)avenrun, sizeof (avenrun)); 214 for (i = 0; i < 3; i++) 215 mywd.wd_loadav[i] = avenrun[i] * 100; 216 cc = (char *)we - (char *)&mywd; 217 (void) time(&mywd.wd_sendtime); 218 (void) sendto(s, (char *)&mywd, cc, 0, &sin, sizeof (sin)); 219 (void) alarm(60); 220 } 221 222 getkmem() 223 { 224 struct nlist *nlp; 225 226 signal(SIGHUP, getkmem); 227 if (kmemf >= 0) 228 (void) close(kmemf); 229 loop: 230 for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) { 231 nlp->n_value = 0; 232 nlp->n_type = 0; 233 } 234 nlist("/vmunix", nl); 235 if (nl[0].n_value == 0) { 236 fprintf(stderr, "/vmunix namelist botch\n"); 237 sleep(300); 238 goto loop; 239 } 240 kmemf = open("/dev/kmem", 0); 241 if (kmemf < 0) { 242 perror("/dev/kmem"); 243 sleep(300); 244 goto loop; 245 } 246 (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, 0); 247 (void) read(kmemf, (char *)&mywd.wd_boottime, sizeof (mywd.wd_boottime)); 248 } 249