ignore old packets
[unix-history] / usr / src / usr.sbin / rwhod / rwhod.c
CommitLineData
52b4fb0c 1#ifndef lint
aaddf8a1 2static char sccsid[] = "@(#)rwhod.c 4.10 83/05/09";
52b4fb0c
BJ
3#endif
4
52b4fb0c 5#include <sys/types.h>
52b4fb0c 6#include <sys/socket.h>
52b4fb0c 7#include <sys/stat.h>
52b4fb0c 8#include <sys/ioctl.h>
de3b21e8 9
7af17b3e 10#include <net/if.h>
de3b21e8
SL
11#include <netinet/in.h>
12
13#include <nlist.h>
14#include <stdio.h>
15#include <signal.h>
16#include <errno.h>
17#include <utmp.h>
a0f59ac1
SL
18#include <ctype.h>
19#include <netdb.h>
7af17b3e 20#include <rwhod.h>
de3b21e8 21
a0f59ac1 22struct sockaddr_in sin = { AF_INET };
52b4fb0c
BJ
23
24extern errno;
25
7af17b3e 26char myname[32];
52b4fb0c
BJ
27
28struct nlist nl[] = {
29#define NL_AVENRUN 0
30 { "_avenrun" },
de3b21e8
SL
31#define NL_BOOTTIME 1
32 { "_boottime" },
52b4fb0c
BJ
33 0
34};
35
7af17b3e
SL
36/*
37 * We communicate with each neighbor in
38 * a list constructed at the time we're
39 * started up. Neighbors are currently
40 * directly connected via a hardware interface.
41 */
42struct neighbor {
43 struct neighbor *n_next;
44 char *n_name; /* interface name */
45 char *n_addr; /* who to send to */
46 int n_addrlen; /* size of address */
47 int n_flags; /* should forward?, interface flags */
48};
49
50struct neighbor *neighbors;
52b4fb0c 51struct whod mywd;
7af17b3e 52struct servent *sp;
52b4fb0c
BJ
53int s, utmpf, kmemf = -1;
54
7af17b3e
SL
55#define WHDRSIZE (sizeof (mywd) - sizeof (mywd.wd_we))
56#define RWHODIR "/usr/spool/rwho"
fea387f0 57
52b4fb0c 58int onalrm();
7af17b3e 59char *strcpy(), *sprintf(), *malloc();
52b4fb0c
BJ
60long lseek();
61int getkmem();
7af17b3e 62struct in_addr inet_makeaddr();
52b4fb0c
BJ
63
64main()
65{
66 struct sockaddr_in from;
67 char path[64];
68 int addr;
7af17b3e 69 struct hostent *hp;
52b4fb0c 70
a0f59ac1
SL
71 sp = getservbyname("who", "udp");
72 if (sp == 0) {
73 fprintf(stderr, "rwhod: udp/who: unknown service\n");
74 exit(1);
75 }
52b4fb0c
BJ
76#ifndef DEBUG
77 if (fork())
78 exit(0);
79 { int s;
80 for (s = 0; s < 10; s++)
81 (void) close(s);
82 (void) open("/", 0);
83 (void) dup2(0, 1);
84 (void) dup2(0, 2);
85 s = open("/dev/tty", 2);
86 if (s >= 0) {
87 ioctl(s, TIOCNOTTY, 0);
88 (void) close(s);
89 }
90 }
91#endif
92 (void) chdir("/dev");
93 (void) signal(SIGHUP, getkmem);
94 if (getuid()) {
a0f59ac1 95 fprintf(stderr, "rwhod: not super user\n");
52b4fb0c
BJ
96 exit(1);
97 }
7af17b3e
SL
98 /*
99 * Establish host name as returned by system.
100 */
101 if (gethostname(myname, sizeof (myname) - 1) < 0) {
102 perror("gethostname");
52b4fb0c
BJ
103 exit(1);
104 }
7af17b3e 105 strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
52b4fb0c
BJ
106 utmpf = open("/etc/utmp", 0);
107 if (utmpf < 0) {
108 (void) close(creat("/etc/utmp", 0644));
109 utmpf = open("/etc/utmp", 0);
110 }
111 if (utmpf < 0) {
a0f59ac1 112 perror("rwhod: /etc/utmp");
52b4fb0c
BJ
113 exit(1);
114 }
115 getkmem();
85b11450 116 if ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
a0f59ac1 117 perror("rwhod: socket");
de3b21e8
SL
118 exit(1);
119 }
7af17b3e
SL
120 hp = gethostbyname(myname);
121 if (hp == NULL) {
122 fprintf(stderr, "%s: don't know my own name\n", myname);
123 exit(1);
124 }
125 sin.sin_family = hp->h_addrtype;
126 sin.sin_port = sp->s_port;
de3b21e8
SL
127 if (bind(s, &sin, sizeof (sin), 0) < 0) {
128 perror("rwhod: bind");
129 exit(1);
52b4fb0c 130 }
7af17b3e
SL
131 if (!configure(s))
132 exit(1);
52b4fb0c
BJ
133 sigset(SIGALRM, onalrm);
134 onalrm();
135 for (;;) {
136 struct whod wd;
7af17b3e 137 int cc, whod, len = sizeof (from);
52b4fb0c 138
7af17b3e
SL
139 cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
140 &from, &len);
52b4fb0c
BJ
141 if (cc <= 0) {
142 if (cc < 0 && errno != EINTR)
de3b21e8 143 perror("rwhod: recv");
52b4fb0c
BJ
144 continue;
145 }
a0f59ac1
SL
146 if (from.sin_port != sp->s_port) {
147 fprintf(stderr, "rwhod: %d: bad from port\n",
148 ntohs(from.sin_port));
52b4fb0c
BJ
149 continue;
150 }
a0f59ac1
SL
151#ifdef notdef
152 if (gethostbyname(wd.wd_hostname) == 0) {
153 fprintf(stderr, "rwhod: %s: unknown host\n",
154 wd.wd_hostname);
155 continue;
156 }
157#endif
aaddf8a1
SL
158 if (wd.wd_vers != WHODVERSION)
159 continue;
7af17b3e
SL
160 if (wd.wd_type != WHODTYPE_STATUS)
161 continue;
a0f59ac1
SL
162 if (!verify(wd.wd_hostname)) {
163 fprintf(stderr, "rwhod: malformed host name from %x\n",
164 from.sin_addr);
52b4fb0c
BJ
165 continue;
166 }
a82aa56a 167 (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
52b4fb0c
BJ
168 whod = creat(path, 0666);
169 if (whod < 0) {
a0f59ac1
SL
170 fprintf(stderr, "rwhod: ");
171 perror(path);
52b4fb0c
BJ
172 continue;
173 }
fea387f0
SL
174#if vax || pdp11
175 {
176 int i, n = (cc - WHDRSIZE)/sizeof(struct utmp);
177 struct whoent *we;
178
179 /* undo header byte swapping before writing to file */
180 wd.wd_sendtime = ntohl(wd.wd_sendtime);
181 for (i = 0; i < 3; i++)
182 wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
183 wd.wd_boottime = ntohl(wd.wd_boottime);
184 we = wd.wd_we;
185 for (i = 0; i < n; i++) {
186 we->we_idle = ntohl(we->we_idle);
187 we->we_utmp.ut_time = ntohl(we->we_utmp.ut_time);
188 we++;
189 }
190 }
191#endif
52b4fb0c
BJ
192 (void) time(&wd.wd_recvtime);
193 (void) write(whod, (char *)&wd, cc);
194 (void) close(whod);
195 }
196}
197
a0f59ac1
SL
198/*
199 * Check out host name for unprintables
200 * and other funnies before allowing a file
201 * to be created. Sorry, but blanks aren't allowed.
202 */
203verify(name)
204 register char *name;
205{
206 register int size = 0;
207
208 while (*name) {
209 if (!isascii(*name) || !isalnum(*name))
210 return (0);
211 name++, size++;
212 }
213 return (size > 0);
214}
215
52b4fb0c
BJ
216int utmptime;
217int utmpent;
76886f32 218struct utmp utmp[100];
52b4fb0c
BJ
219int alarmcount;
220
221onalrm()
222{
223 register int i;
224 struct stat stb;
76886f32 225 register struct whoent *we = mywd.wd_we, *wlast;
52b4fb0c
BJ
226 int cc;
227 double avenrun[3];
228 time_t now = time(0);
7af17b3e 229 register struct neighbor *np;
52b4fb0c
BJ
230
231 if (alarmcount % 10 == 0)
232 getkmem();
233 alarmcount++;
234 (void) fstat(utmpf, &stb);
235 if (stb.st_mtime != utmptime) {
236 (void) lseek(utmpf, (long)0, 0);
237 cc = read(utmpf, (char *)utmp, sizeof (utmp));
238 if (cc < 0) {
239 perror("/etc/utmp");
240 return;
241 }
7af17b3e 242 wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
52b4fb0c
BJ
243 utmpent = cc / sizeof (struct utmp);
244 for (i = 0; i < utmpent; i++)
245 if (utmp[i].ut_name[0]) {
246 we->we_utmp = utmp[i];
76886f32
SL
247 if (we >= wlast)
248 break;
52b4fb0c
BJ
249 we++;
250 }
251 utmpent = we - mywd.wd_we;
252 }
253 we = mywd.wd_we;
254 for (i = 0; i < utmpent; i++) {
255 if (stat(we->we_utmp.ut_line, &stb) >= 0)
256 we->we_idle = now - stb.st_atime;
257 we++;
258 }
259 (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0);
260 (void) read(kmemf, (char *)avenrun, sizeof (avenrun));
261 for (i = 0; i < 3; i++)
262 mywd.wd_loadav[i] = avenrun[i] * 100;
263 cc = (char *)we - (char *)&mywd;
264 (void) time(&mywd.wd_sendtime);
fea387f0
SL
265#if vax || pdp11
266 mywd.wd_sendtime = htonl(mywd.wd_sendtime);
267 for (i = 0; i < 3; i++)
268 mywd.wd_loadav[i] = htonl(mywd.wd_loadav[i]);
269 mywd.wd_boottime = htonl(mywd.wd_boottime);
270 we = mywd.wd_we;
271 for (i = 0; i < utmpent; i++) {
272 we->we_idle = htonl(we->we_idle);
273 we->we_utmp.ut_time = htonl(we->we_utmp.ut_time);
274 we++;
275 }
276#endif
7af17b3e
SL
277 mywd.wd_vers = WHODVERSION;
278 mywd.wd_type = WHODTYPE_STATUS;
279 for (np = neighbors; np != NULL; np = np->n_next)
280 (void) sendto(s, (char *)&mywd, cc, 0,
281 np->n_addr, np->n_addrlen);
52b4fb0c
BJ
282 (void) alarm(60);
283}
284
285getkmem()
286{
287 struct nlist *nlp;
288
289 signal(SIGHUP, getkmem);
290 if (kmemf >= 0)
291 (void) close(kmemf);
292loop:
293 for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) {
294 nlp->n_value = 0;
295 nlp->n_type = 0;
296 }
297 nlist("/vmunix", nl);
298 if (nl[0].n_value == 0) {
299 fprintf(stderr, "/vmunix namelist botch\n");
300 sleep(300);
301 goto loop;
302 }
303 kmemf = open("/dev/kmem", 0);
304 if (kmemf < 0) {
305 perror("/dev/kmem");
306 sleep(300);
307 goto loop;
308 }
de3b21e8
SL
309 (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, 0);
310 (void) read(kmemf, (char *)&mywd.wd_boottime, sizeof (mywd.wd_boottime));
52b4fb0c 311}
7af17b3e
SL
312
313/*
314 * Figure out device configuration and select
315 * networks which deserve status information.
316 */
317configure(s)
318 int s;
319{
320 char buf[BUFSIZ];
321 struct ifconf ifc;
322 struct ifreq ifreq, *ifr;
323 int n;
324 struct sockaddr_in *sin;
325 register struct neighbor *np;
326
327 ifc.ifc_len = sizeof (buf);
328 ifc.ifc_buf = buf;
329 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
330 perror("rwhod: ioctl (get interface configuration)");
331 return (0);
332 }
333 ifr = ifc.ifc_req;
334 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
335 for (np = neighbors; np != NULL; np = np->n_next)
336 if (np->n_name &&
337 strcmp(ifr->ifr_name, np->n_name) == 0)
338 break;
339 if (np != NULL)
340 continue;
341 ifreq = *ifr;
342 np = (struct neighbor *)malloc(sizeof (*np));
343 if (np == NULL)
344 continue;
345 np->n_name = malloc(strlen(ifr->ifr_name) + 1);
346 if (np->n_name == NULL) {
347 free((char *)np);
348 continue;
349 }
350 strcpy(np->n_name, ifr->ifr_name);
351 np->n_addrlen = sizeof (ifr->ifr_addr);
352 np->n_addr = malloc(np->n_addrlen);
353 if (np->n_addr == NULL) {
354 free(np->n_name);
355 free((char *)np);
356 continue;
357 }
358 bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
359 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
360 perror("rwhod: ioctl (get interface flags)");
361 free((char *)np);
362 continue;
363 }
364 if ((ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
365 free((char *)np);
366 continue;
367 }
368 np->n_flags = ifreq.ifr_flags;
369 if (np->n_flags & IFF_POINTOPOINT) {
370 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
371 perror("rwhod: ioctl (get dstaddr)");
372 free((char *)np);
373 continue;
374 }
375 /* we assume addresses are all the same size */
376 bcopy((char *)&ifreq.ifr_dstaddr,
377 np->n_addr, np->n_addrlen);
378 }
379 if (np->n_flags & IFF_BROADCAST) {
380 /* we assume addresses are all the same size */
381 sin = (struct sockaddr_in *)np->n_addr;
382 sin->sin_addr =
383 inet_makeaddr(inet_netof(sin->sin_addr), INADDR_ANY);
384 }
385 /* gag, wish we could get rid of Internet dependencies */
386 sin = (struct sockaddr_in *)np->n_addr;
387 sin->sin_port = sp->s_port;
388 np->n_next = neighbors;
389 neighbors = np;
390 }
391 return (1);
392}