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

Defined functions

configure defined in line 341; used 1 times
getboottime defined in line 320; used 4 times
interval defined in line 463; used 2 times
main defined in line 72; never used
onalrm defined in line 237; used 3 times
sendto defined in line 424; used 1 times
verify defined in line 218; used 1 times

Defined variables

Utmp defined in line 70; used 5 times
alarmcount defined in line 235; used 2 times
copyright defined in line 8; never used
myname defined in line 45; used 5 times
mywd defined in line 62; used 14 times
neighbors defined in line 61; used 4 times
s defined in line 64; used 23 times
sccsid defined in line 12; never used
sin defined in line 43; used 9 times
sp defined in line 63; used 5 times
utmp defined in line 234; used 10 times
utmpent defined in line 232; used 6 times
utmpf defined in line 64; used 7 times
utmpsize defined in line 233; used 6 times
utmptime defined in line 231; used 2 times

Defined struct's

neighbor defined in line 53; used 10 times

Defined macros

ALLREAD defined in line 206; used 3 times
AL_INTERVAL defined in line 41; used 1 times
RWHODIR defined in line 67; used 4 times
WHDRSIZE defined in line 66; used 2 times
Last modified: 1999-09-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5163
Valid CSS Valid XHTML 1.0 Strict