1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)rwhod.c	5.9 (Berkeley) 3/5/86";
  15: #endif not lint
  16: 
  17: #include <sys/types.h>
  18: #include <sys/socket.h>
  19: #include <sys/stat.h>
  20: #include <sys/ioctl.h>
  21: #include <sys/file.h>
  22: 
  23: #include <net/if.h>
  24: #include <netinet/in.h>
  25: 
  26: #include <nlist.h>
  27: #include <stdio.h>
  28: #include <signal.h>
  29: #include <errno.h>
  30: #include <utmp.h>
  31: #include <ctype.h>
  32: #include <netdb.h>
  33: #include <syslog.h>
  34: #include <protocols/rwhod.h>
  35: 
  36: /*
  37:  * Alarm interval. Don't forget to change the down time check in ruptime
  38:  * if this is changed.
  39:  */
  40: #define AL_INTERVAL (3 * 60)
  41: 
  42: struct  sockaddr_in sin = { AF_INET };
  43: 
  44: extern  errno;
  45: 
  46: char    myname[32];
  47: 
  48: struct  nlist nl[] = {
  49: #define NL_AVENRUN  0
  50:     { "_avenrun" },
  51: #define NL_BOOTTIME 1
  52:     { "_boottime" },
  53:     0
  54: };
  55: 
  56: /*
  57:  * We communicate with each neighbor in
  58:  * a list constructed at the time we're
  59:  * started up.  Neighbors are currently
  60:  * directly connected via a hardware interface.
  61:  */
  62: struct  neighbor {
  63:     struct  neighbor *n_next;
  64:     char    *n_name;        /* interface name */
  65:     char    *n_addr;        /* who to send to */
  66:     int n_addrlen;      /* size of address */
  67:     int n_flags;        /* should forward?, interface flags */
  68: };
  69: 
  70: struct  neighbor *neighbors;
  71: struct  whod mywd;
  72: struct  servent *sp;
  73: int s, utmpf, kmemf = -1;
  74: 
  75: #define WHDRSIZE    (sizeof (mywd) - sizeof (mywd.wd_we))
  76: #define RWHODIR     "/usr/spool/rwho"
  77: 
  78: int onalrm();
  79: char    *strcpy(), *sprintf(), *malloc();
  80: long    lseek();
  81: int getkmem();
  82: struct  in_addr inet_makeaddr();
  83: 
  84: main()
  85: {
  86:     struct sockaddr_in from;
  87:     struct stat st;
  88:     char path[64];
  89:     int on = 1;
  90:     char *cp;
  91:     extern char *index();
  92: 
  93:     if (getuid()) {
  94:         fprintf(stderr, "rwhod: not super user\n");
  95:         exit(1);
  96:     }
  97:     sp = getservbyname("who", "udp");
  98:     if (sp == 0) {
  99:         fprintf(stderr, "rwhod: udp/who: unknown service\n");
 100:         exit(1);
 101:     }
 102: #ifndef DEBUG
 103:     if (fork())
 104:         exit(0);
 105:     { int s;
 106:       for (s = 0; s < 10; s++)
 107:         (void) close(s);
 108:       (void) open("/", 0);
 109:       (void) dup2(0, 1);
 110:       (void) dup2(0, 2);
 111:       s = open("/dev/tty", 2);
 112:       if (s >= 0) {
 113:         ioctl(s, TIOCNOTTY, 0);
 114:         (void) close(s);
 115:       }
 116:     }
 117: #endif
 118:     if (chdir(RWHODIR) < 0) {
 119:         perror(RWHODIR);
 120:         exit(1);
 121:     }
 122:     (void) signal(SIGHUP, getkmem);
 123:     openlog("rwhod", LOG_PID, LOG_DAEMON);
 124:     /*
 125: 	 * Establish host name as returned by system.
 126: 	 */
 127:     if (gethostname(myname, sizeof (myname) - 1) < 0) {
 128:         syslog(LOG_ERR, "gethostname: %m");
 129:         exit(1);
 130:     }
 131:     if ((cp = index(myname, '.')) != NULL)
 132:         *cp = '\0';
 133:     strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
 134:     utmpf = open("/etc/utmp", O_RDONLY);
 135:     if (utmpf < 0) {
 136:         (void) close(creat("/etc/utmp", 0644));
 137:         utmpf = open("/etc/utmp", O_RDONLY);
 138:     }
 139:     if (utmpf < 0) {
 140:         syslog(LOG_ERR, "/etc/utmp: %m");
 141:         exit(1);
 142:     }
 143:     getkmem();
 144:     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 145:         syslog(LOG_ERR, "socket: %m");
 146:         exit(1);
 147:     }
 148:     if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
 149:         syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
 150:         exit(1);
 151:     }
 152:     sin.sin_port = sp->s_port;
 153:     if (bind(s, &sin, sizeof (sin)) < 0) {
 154:         syslog(LOG_ERR, "bind: %m");
 155:         exit(1);
 156:     }
 157:     if (!configure(s))
 158:         exit(1);
 159:     signal(SIGALRM, onalrm);
 160:     onalrm();
 161:     for (;;) {
 162:         struct whod wd;
 163:         int cc, whod, len = sizeof (from);
 164: 
 165:         cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
 166:             &from, &len);
 167:         if (cc <= 0) {
 168:             if (cc < 0 && errno != EINTR)
 169:                 syslog(LOG_WARNING, "recv: %m");
 170:             continue;
 171:         }
 172:         if (from.sin_port != sp->s_port) {
 173:             syslog(LOG_WARNING, "%d: bad from port",
 174:                 ntohs(from.sin_port));
 175:             continue;
 176:         }
 177: #ifdef notdef
 178:         if (gethostbyname(wd.wd_hostname) == 0) {
 179:             syslog(LOG_WARNING, "%s: unknown host",
 180:                 wd.wd_hostname);
 181:             continue;
 182:         }
 183: #endif
 184:         if (wd.wd_vers != WHODVERSION)
 185:             continue;
 186:         if (wd.wd_type != WHODTYPE_STATUS)
 187:             continue;
 188:         if (!verify(wd.wd_hostname)) {
 189:             syslog(LOG_WARNING, "malformed host name from %x",
 190:                 from.sin_addr);
 191:             continue;
 192:         }
 193:         (void) sprintf(path, "whod.%s", wd.wd_hostname);
 194:         /*
 195: 		 * Rather than truncating and growing the file each time,
 196: 		 * use ftruncate if size is less than previous size.
 197: 		 */
 198:         whod = open(path, O_WRONLY | O_CREAT, 0644);
 199:         if (whod < 0) {
 200:             syslog(LOG_WARNING, "%s: %m", path);
 201:             continue;
 202:         }
 203: #if vax || pdp11
 204:         {
 205:             int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
 206:             struct whoent *we;
 207: 
 208:             /* undo header byte swapping before writing to file */
 209:             wd.wd_sendtime = ntohl(wd.wd_sendtime);
 210:             for (i = 0; i < 3; i++)
 211:                 wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
 212:             wd.wd_boottime = ntohl(wd.wd_boottime);
 213:             we = wd.wd_we;
 214:             for (i = 0; i < n; i++) {
 215:                 we->we_idle = ntohl(we->we_idle);
 216:                 we->we_utmp.out_time =
 217:                     ntohl(we->we_utmp.out_time);
 218:                 we++;
 219:             }
 220:         }
 221: #endif
 222:         (void) time(&wd.wd_recvtime);
 223:         (void) write(whod, (char *)&wd, cc);
 224:         if (fstat(whod, &st) < 0 || st.st_size > cc)
 225:             ftruncate(whod, cc);
 226:         (void) close(whod);
 227:     }
 228: }
 229: 
 230: /*
 231:  * Check out host name for unprintables
 232:  * and other funnies before allowing a file
 233:  * to be created.  Sorry, but blanks aren't allowed.
 234:  */
 235: verify(name)
 236:     register char *name;
 237: {
 238:     register int size = 0;
 239: 
 240:     while (*name) {
 241:         if (!isascii(*name) || !(isalnum(*name) || ispunct(*name)))
 242:             return (0);
 243:         name++, size++;
 244:     }
 245:     return (size > 0);
 246: }
 247: 
 248: int utmptime;
 249: int utmpent;
 250: int utmpsize = 0;
 251: struct  utmp *utmp;
 252: int alarmcount;
 253: 
 254: onalrm()
 255: {
 256:     register int i;
 257:     struct stat stb;
 258:     register struct whoent *we = mywd.wd_we, *wlast;
 259:     int cc;
 260:     double avenrun[3];
 261:     time_t now = time(0);
 262:     register struct neighbor *np;
 263: 
 264:     if (alarmcount % 10 == 0)
 265:         getkmem();
 266:     alarmcount++;
 267:     (void) fstat(utmpf, &stb);
 268:     if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
 269:         utmptime = stb.st_mtime;
 270:         if (stb.st_size > utmpsize) {
 271:             utmpsize = stb.st_size + 10 * sizeof(struct utmp);
 272:             if (utmp)
 273:                 utmp = (struct utmp *)realloc(utmp, utmpsize);
 274:             else
 275:                 utmp = (struct utmp *)malloc(utmpsize);
 276:             if (! utmp) {
 277:                 fprintf(stderr, "rwhod: malloc failed\n");
 278:                 utmpsize = 0;
 279:                 goto done;
 280:             }
 281:         }
 282:         (void) lseek(utmpf, (long)0, L_SET);
 283:         cc = read(utmpf, (char *)utmp, stb.st_size);
 284:         if (cc < 0) {
 285:             perror("/etc/utmp");
 286:             goto done;
 287:         }
 288:         wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
 289:         utmpent = cc / sizeof (struct utmp);
 290:         for (i = 0; i < utmpent; i++)
 291:             if (utmp[i].ut_name[0]) {
 292:                 bcopy(utmp[i].ut_line, we->we_utmp.out_line,
 293:                    sizeof (utmp[i].ut_line));
 294:                 bcopy(utmp[i].ut_name, we->we_utmp.out_name,
 295:                    sizeof (utmp[i].ut_name));
 296:                 we->we_utmp.out_time = htonl(utmp[i].ut_time);
 297:                 if (we >= wlast)
 298:                     break;
 299:                 we++;
 300:             }
 301:         utmpent = we - mywd.wd_we;
 302:     }
 303: 
 304:     /*
 305: 	 * The test on utmpent looks silly---after all, if no one is
 306: 	 * logged on, why worry about efficiency?---but is useful on
 307: 	 * (e.g.) compute servers.
 308: 	 */
 309:     if (utmpent && chdir("/dev")) {
 310:         syslog(LOG_ERR, "chdir(/dev): %m");
 311:         exit(1);
 312:     }
 313:     we = mywd.wd_we;
 314:     for (i = 0; i < utmpent; i++) {
 315:         if (stat(we->we_utmp.out_line, &stb) >= 0)
 316:             we->we_idle = htonl(now - stb.st_atime);
 317:         we++;
 318:     }
 319:     (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, L_SET);
 320:     (void) read(kmemf, (char *)avenrun, sizeof (avenrun));
 321:     for (i = 0; i < 3; i++)
 322:         mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
 323:     cc = (char *)we - (char *)&mywd;
 324:     mywd.wd_sendtime = htonl(time(0));
 325:     mywd.wd_vers = WHODVERSION;
 326:     mywd.wd_type = WHODTYPE_STATUS;
 327:     for (np = neighbors; np != NULL; np = np->n_next)
 328:         (void) sendto(s, (char *)&mywd, cc, 0,
 329:             np->n_addr, np->n_addrlen);
 330:     if (utmpent && chdir(RWHODIR)) {
 331:         syslog(LOG_ERR, "chdir(%s): %m", RWHODIR);
 332:         exit(1);
 333:     }
 334: done:
 335:     (void) alarm(AL_INTERVAL);
 336: }
 337: 
 338: getkmem()
 339: {
 340:     static ino_t vmunixino;
 341:     static time_t vmunixctime;
 342:     struct stat sb;
 343: 
 344:     if (stat("/vmunix", &sb) < 0) {
 345:         if (vmunixctime)
 346:             return;
 347:     } else {
 348:         if (sb.st_ctime == vmunixctime && sb.st_ino == vmunixino)
 349:             return;
 350:         vmunixctime = sb.st_ctime;
 351:         vmunixino= sb.st_ino;
 352:     }
 353:     if (kmemf >= 0)
 354:         (void) close(kmemf);
 355: loop:
 356:     if (nlist("/vmunix", nl)) {
 357:         syslog(LOG_WARNING, "/vmunix namelist botch");
 358:         sleep(300);
 359:         goto loop;
 360:     }
 361:     kmemf = open("/dev/kmem", O_RDONLY);
 362:     if (kmemf < 0) {
 363:         syslog(LOG_ERR, "/dev/kmem: %m");
 364:         exit(1);
 365:     }
 366:     (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET);
 367:     (void) read(kmemf, (char *)&mywd.wd_boottime,
 368:         sizeof (mywd.wd_boottime));
 369:     mywd.wd_boottime = htonl(mywd.wd_boottime);
 370: }
 371: 
 372: /*
 373:  * Figure out device configuration and select
 374:  * networks which deserve status information.
 375:  */
 376: configure(s)
 377:     int s;
 378: {
 379:     char buf[BUFSIZ];
 380:     struct ifconf ifc;
 381:     struct ifreq ifreq, *ifr;
 382:     struct sockaddr_in *sin;
 383:     register struct neighbor *np;
 384:     int n;
 385: 
 386:     ifc.ifc_len = sizeof (buf);
 387:     ifc.ifc_buf = buf;
 388:     if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
 389:         syslog(LOG_ERR, "ioctl (get interface configuration)");
 390:         return (0);
 391:     }
 392:     ifr = ifc.ifc_req;
 393:     for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
 394:         for (np = neighbors; np != NULL; np = np->n_next)
 395:             if (np->n_name &&
 396:                 strcmp(ifr->ifr_name, np->n_name) == 0)
 397:                 break;
 398:         if (np != NULL)
 399:             continue;
 400:         ifreq = *ifr;
 401:         np = (struct neighbor *)malloc(sizeof (*np));
 402:         if (np == NULL)
 403:             continue;
 404:         np->n_name = malloc(strlen(ifr->ifr_name) + 1);
 405:         if (np->n_name == NULL) {
 406:             free((char *)np);
 407:             continue;
 408:         }
 409:         strcpy(np->n_name, ifr->ifr_name);
 410:         np->n_addrlen = sizeof (ifr->ifr_addr);
 411:         np->n_addr = malloc(np->n_addrlen);
 412:         if (np->n_addr == NULL) {
 413:             free(np->n_name);
 414:             free((char *)np);
 415:             continue;
 416:         }
 417:         bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
 418:         if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
 419:             syslog(LOG_ERR, "ioctl (get interface flags)");
 420:             free((char *)np);
 421:             continue;
 422:         }
 423:         if ((ifreq.ifr_flags & IFF_UP) == 0 ||
 424:             (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
 425:             free((char *)np);
 426:             continue;
 427:         }
 428:         np->n_flags = ifreq.ifr_flags;
 429:         if (np->n_flags & IFF_POINTOPOINT) {
 430:             if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
 431:                 syslog(LOG_ERR, "ioctl (get dstaddr)");
 432:                 free((char *)np);
 433:                 continue;
 434:             }
 435:             /* we assume addresses are all the same size */
 436:             bcopy((char *)&ifreq.ifr_dstaddr,
 437:               np->n_addr, np->n_addrlen);
 438:         }
 439:         if (np->n_flags & IFF_BROADCAST) {
 440:             if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
 441:                 syslog(LOG_ERR, "ioctl (get broadaddr)");
 442:                 free((char *)np);
 443:                 continue;
 444:             }
 445:             /* we assume addresses are all the same size */
 446:             bcopy((char *)&ifreq.ifr_broadaddr,
 447:               np->n_addr, np->n_addrlen);
 448:         }
 449:         /* gag, wish we could get rid of Internet dependencies */
 450:         sin = (struct sockaddr_in *)np->n_addr;
 451:         sin->sin_port = sp->s_port;
 452:         np->n_next = neighbors;
 453:         neighbors = np;
 454:     }
 455:     return (1);
 456: }
 457: 
 458: #ifdef DEBUG
 459: sendto(s, buf, cc, flags, to, tolen)
 460:     int s;
 461:     char *buf;
 462:     int cc, flags;
 463:     char *to;
 464:     int tolen;
 465: {
 466:     register struct whod *w = (struct whod *)buf;
 467:     register struct whoent *we;
 468:     struct sockaddr_in *sin = (struct sockaddr_in *)to;
 469:     char *interval();
 470: 
 471:     printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
 472:     printf("hostname %s %s\n", w->wd_hostname,
 473:        interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), "  up"));
 474:     printf("load %4.2f, %4.2f, %4.2f\n",
 475:         ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
 476:         ntohl(w->wd_loadav[2]) / 100.0);
 477:     cc -= WHDRSIZE;
 478:     for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
 479:         time_t t = ntohl(we->we_utmp.out_time);
 480:         printf("%-8.8s %s:%s %.12s",
 481:             we->we_utmp.out_name,
 482:             w->wd_hostname, we->we_utmp.out_line,
 483:             ctime(&t)+4);
 484:         we->we_idle = ntohl(we->we_idle) / 60;
 485:         if (we->we_idle) {
 486:             if (we->we_idle >= 100*60)
 487:                 we->we_idle = 100*60 - 1;
 488:             if (we->we_idle >= 60)
 489:                 printf(" %2d", we->we_idle / 60);
 490:             else
 491:                 printf("   ");
 492:             printf(":%02d", we->we_idle % 60);
 493:         }
 494:         printf("\n");
 495:     }
 496: }
 497: 
 498: char *
 499: interval(time, updown)
 500:     int time;
 501:     char *updown;
 502: {
 503:     static char resbuf[32];
 504:     int days, hours, minutes;
 505: 
 506:     if (time < 0 || time > 3*30*24*60*60) {
 507:         (void) sprintf(resbuf, "   %s ??:??", updown);
 508:         return (resbuf);
 509:     }
 510:     minutes = (time + 59) / 60;     /* round to minutes */
 511:     hours = minutes / 60; minutes %= 60;
 512:     days = hours / 24; hours %= 24;
 513:     if (days)
 514:         (void) sprintf(resbuf, "%s %2d+%02d:%02d",
 515:             updown, days, hours, minutes);
 516:     else
 517:         (void) sprintf(resbuf, "%s    %2d:%02d",
 518:             updown, hours, minutes);
 519:     return (resbuf);
 520: }
 521: #endif

Defined functions

configure defined in line 376; used 1 times
getkmem defined in line 338; used 4 times
interval defined in line 498; used 2 times
main defined in line 84; never used
onalrm defined in line 254; used 3 times
sendto defined in line 459; used 7 times
verify defined in line 235; used 1 times

Defined variables

alarmcount defined in line 252; used 2 times
copyright defined in line 8; never used
kmemf defined in line 73; used 8 times
myname defined in line 46; used 5 times
mywd defined in line 71; used 17 times
neighbors defined in line 70; used 4 times
nl defined in line 48; used 3 times
s defined in line 73; used 23 times
sccsid defined in line 14; never used
sin defined in line 42; used 9 times
sp defined in line 72; used 5 times
utmp defined in line 251; used 12 times
utmpent defined in line 249; used 6 times
utmpf defined in line 73; used 7 times
utmpsize defined in line 250; used 6 times
utmptime defined in line 248; used 2 times

Defined struct's

neighbor defined in line 62; used 10 times

Defined macros

AL_INTERVAL defined in line 40; used 1 times
NL_AVENRUN defined in line 49; used 1 times
NL_BOOTTIME defined in line 51; used 1 times
RWHODIR defined in line 76; used 4 times
WHDRSIZE defined in line 75; used 2 times
Last modified: 1986-03-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2293
Valid CSS Valid XHTML 1.0 Strict