home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / xntpres / xntpres.c < prev   
C/C++ Source or Header  |  1992-08-04  |  18KB  |  813 lines

  1. /*
  2.  * xntpres - process configuration entries which require use of the resolver
  3.  *
  4.  * This is meant to be run by xntpd on the fly.  It is not guaranteed
  5.  * to work properly if run by hand.  This is actually a quick hack to
  6.  * stave off violence from people who hate using numbers in the
  7.  * configuration file (at least I hope the rest of the daemon is
  8.  * better than this).  Also might provide some ideas about how one
  9.  * might go about autoconfiguring an NTP distribution network.
  10.  *
  11.  * Usage is:
  12.  *   xntpres [-d] [-r] keyid keyfile configuration_data
  13.  */
  14. #include <stdio.h>
  15. #include <strings.h>
  16. #include <ctype.h>
  17. #include <sys/types.h>
  18. #include <sys/time.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <sys/file.h>
  22. #include <netdb.h>
  23. #include <syslog.h>
  24. #include <signal.h>
  25. #include <errno.h>
  26.  
  27. #include "ntp_fp.h"
  28. #include "ntp.h"
  29. #include "ntp_request.h"
  30.  
  31. #define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  32.  
  33. #ifndef FD_SET
  34. #define    NFDBITS        32
  35. #define    FD_SETSIZE    32
  36. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  37. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  38. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  39. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  40. #endif
  41.  
  42. /*
  43.  * Each item we are to resolve and configure gets one of these
  44.  * structures defined for it.
  45.  */
  46. struct conf_entry {
  47.     struct conf_entry *ce_next;
  48.     char *ce_name;            /* name we are trying to resolve */
  49.     struct conf_peer ce_config;    /* configuration info for peer */
  50. };
  51. #define    ce_peeraddr    ce_config.peeraddr
  52. #define    ce_hmode    ce_config.hmode
  53. #define    ce_version    ce_config.version
  54. #define    ce_flags    ce_config.flags
  55. #define    ce_keyid    ce_config.keyid
  56.  
  57. /*
  58.  * confentries is a pointer to the list of configuration entries
  59.  * we have left to do.
  60.  */
  61. struct conf_entry *confentries = NULL;
  62.  
  63. /*
  64.  * We take an interrupt every thirty seconds, at which time we decrement
  65.  * config_timer and resolve_timer.  The former is set to 2, so we retry
  66.  * unsucessful reconfigurations every minute.  The latter is set to
  67.  * an exponentially increasing value which starts at 2 and increases to
  68.  * 32.  When this expires we retry failed name resolutions.
  69.  *
  70.  * We sleep SLEEPTIME seconds before doing anything, to give the server
  71.  * time to arrange itself.
  72.  */
  73. #define    MINRESOLVE    2
  74. #define    MAXRESOLVE    32
  75. #define    CONFIG_TIME    2
  76. #define    ALARM_TIME    30
  77.  
  78. #define    SLEEPTIME    2
  79.  
  80. int config_timer = 0;
  81. int resolve_timer = 0;
  82.  
  83. int resolve_value;    /* next value of resolve timer */
  84.  
  85. /*
  86.  * Big hack attack
  87.  */
  88. #define    LOCALHOST    0x7f000001    /* 127.0.0.1, in hex, of course */
  89. #define    SKEWTIME    0x08000000    /* 0.03125 seconds as a l_fp fraction */
  90.  
  91. /*
  92.  * Select time out.  Set to 2 seconds.  The server is on the local machine,
  93.  * after all.
  94.  */
  95. #define    TIMEOUT_SEC    2
  96. #define    TIMEOUT_USEC    0
  97.  
  98.  
  99. /*
  100.  * Input processing.  The data on each line in the configuration file
  101.  * is supposed to consist of entries in the following order
  102.  */
  103. #define    TOK_HOSTNAME    0
  104. #define    TOK_HMODE    1
  105. #define    TOK_VERSION    2
  106. #define    TOK_FLAGS    3
  107. #define    TOK_KEYID    4
  108. #define    NUMTOK        5
  109.  
  110. #define    MAXLINESIZE    512
  111.  
  112.  
  113. /*
  114.  * File descriptor for ntp request code.
  115.  */
  116. int sockfd = -1;
  117.  
  118. /*
  119.  * Misc. data from argument processing
  120.  */
  121. int removefile = 0;    /* remove configuration file when done */
  122.  
  123. u_long req_keyid;    /* request keyid */
  124. char *keyfile;        /* file where keys are kept */
  125. char *conffile;        /* name of the file with configuration info */
  126.  
  127. char *progname;
  128. int debug = 0;
  129. extern char *Version;
  130. extern int errno;
  131.  
  132. /*
  133.  * main - parse arguments and handle options
  134.  */
  135. main(argc, argv)
  136.     int argc;
  137.     char *argv[];
  138. {
  139.     int c;
  140.     int errflg = 0;
  141.     char *cp;
  142.     FILE *in;
  143.     extern int optind;
  144.     extern char *optarg;
  145.     extern char *rindex();
  146.     void bong();
  147.     void readconf();
  148.     void doconfigure();
  149.     void checkparent();
  150.  
  151.     progname = argv[0];
  152.  
  153.     /*
  154.      * Better get syslog open early since stderr messages are likely
  155.      * ending up in the twilight zone
  156.      */
  157.     cp = rindex(argv[0], '/');
  158.     if (cp == 0)
  159.         cp = argv[0];
  160.     else
  161.         cp++;
  162.  
  163. #ifndef    LOG_DAEMON
  164.     openlog(cp, LOG_PID);
  165. #else
  166.  
  167. #ifndef    LOG_NTP
  168. #define    LOG_NTP    LOG_DAEMON
  169. #endif
  170.     openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
  171. #ifdef    DEBUG
  172.     if (debug)
  173.         setlogmask(LOG_UPTO(LOG_DEBUG));
  174.     else
  175. #endif    /* DEBUG */
  176.         setlogmask(LOG_UPTO(LOG_INFO));
  177. #endif    /* LOG_DAEMON */
  178.  
  179.     syslog(LOG_INFO, Version);
  180.  
  181.     while ((c = getopt(argc, argv, "dr")) != EOF)
  182.         switch (c) {
  183.         case 'd':
  184.             ++debug;
  185.             break;
  186.         case 'r':
  187.             ++removefile;
  188.             break;
  189.         default:
  190.             errflg++;
  191.             break;
  192.         }
  193.     if (errflg || (optind + 3) != argc) {
  194.         (void) fprintf(stderr,
  195.             "usage: %s [-d] [-r] keyid keyfile conffile\n", progname);
  196.         syslog(LOG_ERR, "exiting due to usage error");
  197.         exit(2);
  198.     }
  199.  
  200.     if (!atouint(argv[optind], &req_keyid)) {
  201.         syslog(LOG_ERR, "undecodeable keyid %s", argv[optind]);
  202.         exit(1);
  203.     }
  204.  
  205.     keyfile = argv[optind+1];
  206.     conffile = argv[optind+2];
  207.  
  208.     /*
  209.      * Make sure we have the key we need
  210.      */
  211.     if (!authreadkeys(keyfile))
  212.         exit(1);
  213.     if (!authhavekey(req_keyid)) {
  214.         syslog(LOG_ERR, "request keyid %lu not found in %s",
  215.             req_keyid, keyfile);
  216.         exit(1);
  217.     }
  218.  
  219.     /*
  220.      * Read the configuration info
  221.      */
  222.     if ((in = fopen(conffile, "r")) == NULL) {
  223.         syslog(LOG_ERR, "can't open configuration file %s: %m",
  224.             conffile);
  225.         exit(1);
  226.     }
  227.     readconf(in, conffile);
  228.     (void) fclose(in);
  229.     if (removefile)
  230.         (void) unlink(conffile);
  231.  
  232.     /*
  233.      * Sleep a little to make sure the server is completely up
  234.      */
  235.     sleep(SLEEPTIME);
  236.  
  237.     /*
  238.      * Make a first cut at resolving the bunch
  239.      */
  240.     doconfigure(1);
  241.     if (confentries == NULL)
  242.         exit(0);        /* done that quick */
  243.     
  244.     /*
  245.      * Here we've got some problem children.  Set up the timer
  246.      * and wait for it.
  247.      */
  248.     resolve_value = resolve_timer = MINRESOLVE;
  249.     config_timer = CONFIG_TIME;
  250.     (void) signal(SIGALRM, bong);
  251.     alarm(ALARM_TIME);
  252.  
  253.     for (;;) {
  254.         if (confentries == NULL)
  255.             exit(0);
  256.         checkparent();
  257.         if (resolve_timer == 0) {
  258.             if (resolve_value < MAXRESOLVE)
  259.                 resolve_value <<= 1;
  260.             resolve_timer = resolve_value;
  261.             config_timer = CONFIG_TIME;
  262.             doconfigure(1);
  263.             continue;
  264.         } else if (config_timer == 0) {
  265.             config_timer = CONFIG_TIME;
  266.             doconfigure(0);
  267.             continue;
  268.         }
  269.         /*
  270.          * There is a race in here.  Is okay, though, since
  271.          * all it does is delay things by 30 seconds.
  272.          */
  273.         (void) pause();
  274.     }
  275. }
  276.  
  277.  
  278. /*
  279.  * bong - service and reschedule an alarm() interrupt
  280.  */
  281. void
  282. bong()
  283. {
  284.     if (config_timer > 0)
  285.         config_timer--;
  286.     if (resolve_timer > 0)
  287.         resolve_timer--;
  288.     alarm(ALARM_TIME);
  289. }
  290.  
  291.  
  292. /*
  293.  * checkparent - see if our parent process is still running
  294.  */
  295. void
  296. checkparent()
  297. {
  298.     /*
  299.      * If our parent (the server) has died we will have been
  300.      * inherited by init.  If so, exit.
  301.      */
  302.     if (getppid() == 1) {
  303.         syslog(LOG_INFO, "parent died before we finished, exiting");
  304.         exit(0);
  305.     }
  306. }
  307.  
  308.  
  309. /*
  310.  * removeentry - we are done with an entry, remove it from the list
  311.  */
  312. void
  313. removeentry(entry)
  314.     struct conf_entry *entry;
  315. {
  316.     register struct conf_entry *ce;
  317.  
  318.     ce = confentries;
  319.     if (ce == entry) {
  320.         confentries = ce->ce_next;
  321.         return;
  322.     }
  323.  
  324.     while (ce != NULL) {
  325.         if (ce->ce_next == entry) {
  326.             ce->ce_next = entry->ce_next;
  327.             return;
  328.         }
  329.         ce = ce->ce_next;
  330.     }
  331. }
  332.  
  333.  
  334. /*
  335.  * addentry - add an entry to the configuration list
  336.  */
  337. void
  338. addentry(name, mode, version, flags, keyid)
  339.     char *name;
  340.     int mode;
  341.     int version;
  342.     int flags;
  343.     u_long keyid;
  344. {
  345.     register char *cp;
  346.     register struct conf_entry *ce;
  347.     int len;
  348.     extern char *emalloc();
  349.  
  350.     len = strlen(name) + 1;
  351.     cp = emalloc((unsigned)len);
  352.     bcopy(name, cp, len);
  353.  
  354.     ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
  355.     ce->ce_name = cp;
  356.     ce->ce_peeraddr = 0;
  357.     ce->ce_hmode = (u_char)mode;
  358.     ce->ce_version = (u_char)version;
  359.     ce->ce_flags = (u_char)flags;
  360.     ce->ce_keyid = htonl(keyid);
  361.     ce->ce_next = NULL;
  362.  
  363.     if (confentries == NULL) {
  364.         confentries = ce;
  365.     } else {
  366.         register struct conf_entry *cep;
  367.  
  368.         for (cep = confentries; cep->ce_next != NULL;
  369.             cep = cep->ce_next)
  370.             /* nothing */;
  371.         cep->ce_next = ce;
  372.     }
  373. }
  374.  
  375.  
  376. /*
  377.  * findhostaddr - resolve a host name into an address
  378.  *
  379.  * The routine sticks the address into the entry's ce_peeraddr if it
  380.  * gets one.  It returns 1 for "success" and 0 for an uncorrectable
  381.  * failure.  Note that "success" includes try again errors.  You can
  382.  * tell that you got a try again since ce_peeraddr will still be zero.
  383.  */
  384. int
  385. findhostaddr(entry)
  386.     struct conf_entry *entry;
  387. {
  388.     struct hostent *hp;
  389.  
  390.     checkparent();        /* make sure our guy is still running */
  391.  
  392.     hp = gethostbyname(entry->ce_name);
  393.  
  394.     if (hp == NULL) {
  395. #ifndef NODNS
  396.         /*
  397.          * If the resolver is in use, see if the failure is
  398.          * temporary.  If so, return success.
  399.          */
  400.         extern int h_errno;
  401.  
  402.         if (h_errno == TRY_AGAIN)
  403.             return 1;
  404. #endif
  405.         return 0;
  406.     }
  407.  
  408.     /*
  409.      * Use the first address.  We don't have any way to
  410.      * tell preferences and older gethostbyname() implementations
  411.      * only return one.
  412.      */
  413.     (void) bcopy(hp->h_addr, (char *)&(entry->ce_peeraddr),
  414.         sizeof(struct in_addr));
  415.     return 1;
  416. }
  417.  
  418.  
  419. /*
  420.  * openntp - open a socket to the ntp server
  421.  */
  422. void
  423. openntp()
  424. {
  425.     struct sockaddr_in saddr;
  426.  
  427.     if (sockfd >= 0)
  428.         return;
  429.     
  430.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  431.     if (sockfd == -1) {
  432.         syslog(LOG_ERR, "socket() failed: %m");
  433.         exit(1);
  434.     }
  435.  
  436.     bzero((char *)&saddr, sizeof(saddr));
  437.     saddr.sin_family = AF_INET;
  438.     saddr.sin_port = htons(NTP_PORT);        /* trash */
  439.     saddr.sin_addr.s_addr = htonl(LOCALHOST);    /* garbage */
  440.  
  441.  
  442.     /*
  443.      * Make the socket non-blocking.  We'll wait with select()
  444.      */
  445.     if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
  446.         syslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
  447.         exit(1);
  448.     }
  449.  
  450.     if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
  451.         syslog(LOG_ERR, "connect() failed: %m");
  452.         exit(1);
  453.     }
  454. }
  455.  
  456.  
  457. /*
  458.  * request - send a configuration request to the server, wait for a response
  459.  */
  460. int
  461. request(conf)
  462.     struct conf_peer *conf;
  463. {
  464.     fd_set fdset;
  465.     struct timeval tvout;
  466.     struct req_pkt reqpkt;
  467.     l_fp ts;
  468.     int n;
  469.  
  470.     checkparent();        /* make sure our guy is still running */
  471.  
  472.     if (sockfd < 0)
  473.         openntp();
  474.     
  475.     /*
  476.      * Try to clear out any previously received traffic so it
  477.      * doesn't fool us.  Note the socket is nonblocking.
  478.      */
  479.     while (read(sockfd, (char *)&reqpkt, REQ_LEN_MAC) > 0)
  480.         /* nothing */;
  481.  
  482.     /*
  483.      * Make up a request packet with the configuration info
  484.      */
  485.     bzero((char *)&reqpkt, sizeof(reqpkt));
  486.  
  487.     reqpkt.rm_vn_mode = RM_VN_MODE(0, 0);
  488.     reqpkt.auth_seq = AUTH_SEQ(1, 0);    /* authenticated, no seq */
  489.     reqpkt.implementation = IMPL_XNTPD;    /* local implementation */
  490.     reqpkt.request = REQ_CONFIG;        /* configure a new peer */
  491.     reqpkt.err_nitems = ERR_NITEMS(0, 1);    /* one item */
  492.     reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer));
  493.     bcopy((char *)conf, reqpkt.data, sizeof(struct conf_peer));
  494.     reqpkt.keyid = htonl(req_keyid);
  495.  
  496.     auth1crypt(req_keyid, (u_long *)&reqpkt, REQ_LEN_NOMAC);
  497.     gettstamp(&ts);
  498.     M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME);
  499.     HTONL_FP(&ts, &reqpkt.tstamp);
  500.     n = auth2crypt(req_keyid, (u_long *)&reqpkt, REQ_LEN_NOMAC);
  501.  
  502.     /*
  503.      * Done.  Send it.
  504.      */
  505.     n = write(sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n);
  506.     if (n < 0) {
  507.         syslog(LOG_ERR, "send to NTP server failed: %m");
  508.         return 0;    /* maybe should exit */
  509.     }
  510.  
  511.     /*
  512.      * Wait for a response.  A weakness of the mode 7 protocol used
  513.      * is that there is no way to associate a response with a
  514.      * particular request, i.e. the response to this configuration
  515.      * request is indistinguishable from that to any other.  I should
  516.      * fix this some day.  In any event, the time out is fairly
  517.      * pessimistic to make sure that if an answer is coming back
  518.      * at all, we get it.
  519.      */
  520.     for (;;) {
  521.         FD_ZERO(&fdset);
  522.         FD_SET(sockfd, &fdset);
  523.         tvout.tv_sec = TIMEOUT_SEC;
  524.         tvout.tv_usec = TIMEOUT_USEC;
  525.  
  526.         n = select(sockfd + 1, &fdset, (fd_set *)0,
  527.             (fd_set *)0, &tvout);
  528.  
  529.         if (n <= 0) {
  530.             if (n < 0)
  531.                 syslog(LOG_ERR, "select() fails: %m");
  532.             return 0;
  533.         }
  534.  
  535.         n = read(sockfd, (char *)&reqpkt, REQ_LEN_MAC);
  536.         if (n <= 0) {
  537.             if (n < 0) {
  538.                 syslog(LOG_ERR, "read() fails: %m");
  539.                 return 0;
  540.             }
  541.             continue;
  542.         }
  543.  
  544.         /*
  545.          * Got one.  Check through to make sure it is what
  546.          * we expect.
  547.          */
  548.         if (n < RESP_HEADER_SIZE) {
  549.             syslog(LOG_ERR, "received runt response (%d octets)",
  550.                 n);
  551.             continue;
  552.         }
  553.  
  554.         if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
  555. #ifdef DEBUG
  556.             if (debug > 1)
  557.                 printf("received non-response packet\n");
  558. #endif
  559.             continue;
  560.         }
  561.  
  562.         if (ISMORE(reqpkt.rm_vn_mode)) {
  563. #ifdef DEBUG
  564.             if (debug > 1)
  565.                 printf("received fragmented packet\n");
  566. #endif
  567.             continue;
  568.         }
  569.  
  570.         if (INFO_VERSION(reqpkt.rm_vn_mode) != NTP_VERSION
  571.             || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
  572. #ifdef DEBUG
  573.             if (debug > 1)
  574.                 printf("version (%d) or mode (%d) incorrect\n",
  575.                     INFO_VERSION(reqpkt.rm_vn_mode),
  576.                     INFO_MODE(reqpkt.rm_vn_mode));
  577. #endif
  578.             continue;
  579.         }
  580.  
  581.         if (INFO_SEQ(reqpkt.auth_seq) != 0) {
  582. #ifdef DEBUG
  583.             if (debug > 1)
  584.                 printf("nonzero sequence number (%d)\n",
  585.                     INFO_SEQ(reqpkt.auth_seq));
  586. #endif
  587.             continue;
  588.         }
  589.  
  590.         if (reqpkt.implementation != IMPL_XNTPD ||
  591.             reqpkt.request != REQ_CONFIG) {
  592. #ifdef DEBUG
  593.             if (debug > 1)
  594.                 printf(
  595.                 "implementation (%d) or request (%d) incorrect\n",
  596.                     reqpkt.implementation, reqpkt.request);
  597. #endif
  598.             continue;
  599.         }
  600.  
  601.         if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
  602.             INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
  603.             INFO_ITEMSIZE(reqpkt.mbz_itemsize != 0)) {
  604. #ifdef DEBUG
  605.             if (debug > 1)
  606.                 printf(
  607.                 "nitems (%d) mbz (%d) or itemsize (%d) nonzero\n",
  608.                     INFO_NITEMS(reqpkt.err_nitems),
  609.                     INFO_MBZ(reqpkt.mbz_itemsize),
  610.                     INFO_ITEMSIZE(reqpkt.mbz_itemsize));
  611. #endif
  612.             continue;
  613.         }
  614.  
  615.         n = INFO_ERR(reqpkt.err_nitems);
  616.         switch (n) {
  617.         case INFO_OKAY:
  618.             /* success */
  619.             return 1;
  620.         
  621.         case INFO_ERR_IMPL:
  622.             syslog(LOG_ERR,
  623.                 "server reports implementation mismatch!!");
  624.             return 0;
  625.         
  626.         case INFO_ERR_REQ:
  627.             syslog(LOG_ERR,
  628.                 "server claims configuration request is unknown");
  629.             return 0;
  630.         
  631.         case INFO_ERR_FMT:
  632.             syslog(LOG_ERR,
  633.                 "server indicates a format error occured(!!)");
  634.             return 0;
  635.  
  636.         case INFO_ERR_NODATA:
  637.             syslog(LOG_ERR,
  638.         "server indicates no data available (shouldn't happen)");
  639.             return 0;
  640.         
  641.         case INFO_ERR_AUTH:
  642.             syslog(LOG_ERR,
  643.                 "server returns a permission denied error");
  644.             return 0;
  645.  
  646.         default:
  647.             syslog(LOG_ERR,
  648.                 "server returns unknown error code %d", n);
  649.             return 0;
  650.         }
  651.     }
  652. }
  653.  
  654.  
  655. /*
  656.  * nexttoken - return the next token from a line
  657.  */
  658. char *
  659. nexttoken(lptr)
  660.     char **lptr;
  661. {
  662.     register char *cp;
  663.     register char *tstart;
  664.  
  665.     cp = *lptr;
  666.  
  667.     /*
  668.      * Skip leading white space
  669.      */
  670.     while (*cp == ' ' || *cp == '\t')
  671.         cp++;
  672.     
  673.     /*
  674.      * If this is the end of the line, return nothing.
  675.      */
  676.     if (*cp == '\n' || *cp == '\0') {
  677.         *lptr = cp;
  678.         return NULL;
  679.     }
  680.     
  681.     /*
  682.      * Must be the start of a token.  Record the pointer and look
  683.      * for the end.
  684.      */
  685.     tstart = cp++;
  686.     while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
  687.         cp++;
  688.     
  689.     /*
  690.      * Terminate the token with a \0.  If this isn't the end of the
  691.      * line, space to the next character.
  692.      */
  693.     if (*cp == '\n' || *cp == '\0')
  694.         *cp = '\0';
  695.     else
  696.         *cp++ = '\0';
  697.  
  698.     *lptr = cp;
  699.     return tstart;
  700. }
  701.  
  702.  
  703. /*
  704.  * readconf - read the configuration information out of the file we
  705.  *          were passed.  Note that since the file is supposed to be
  706.  *          machine generated, we bail out at the first sign of trouble.
  707.  */
  708. void
  709. readconf(fp, name)
  710.     FILE *fp;
  711.     char *name;
  712. {
  713.     register int i;
  714.     char *token[NUMTOK];
  715.     u_long intval[NUMTOK];
  716.     int flags;
  717.     char buf[MAXLINESIZE];
  718.     char *bp;
  719.  
  720.     while (fgets(buf, MAXLINESIZE, fp) != NULL) {
  721.  
  722.         bp = buf;
  723.         for (i = 0; i < NUMTOK; i++) {
  724.             if ((token[i] = nexttoken(&bp)) == NULL) {
  725.                 syslog(LOG_ERR,
  726.                     "tokenizing error in file `%s', quitting",
  727.                     name);
  728.                 exit(1);
  729.             }
  730.         }
  731.  
  732.         for (i = 1; i < NUMTOK; i++) {
  733.             if (!atouint(token[i], &intval[i])) {
  734.                 syslog(LOG_ERR,
  735.          "format error for integer token `%s', file `%s', quitting",
  736.                     token[i], name);
  737.                 exit(1);
  738.             }
  739.         }
  740.  
  741.         if (intval[TOK_HMODE] != MODE_ACTIVE &&
  742.             intval[TOK_HMODE] != MODE_CLIENT &&
  743.             intval[TOK_HMODE] != MODE_BROADCAST) {
  744.             syslog(LOG_ERR, "invalid mode (%d) in file %s",
  745.                 intval[TOK_HMODE], name);
  746.             exit(1);
  747.         }
  748.  
  749.         if (intval[TOK_VERSION] > NTP_VERSION ||
  750.             intval[TOK_VERSION] < NTP_OLDVERSION) {
  751.             syslog(LOG_ERR, "invalid version (%d) in file %s",
  752.                 intval[TOK_VERSION], name);
  753.             exit(1);
  754.         }
  755.  
  756.         if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE|FLAG_MINPOLL))
  757.             != 0) {
  758.             syslog(LOG_ERR, "invalid flags (%d) in file %s",
  759.                 intval[TOK_FLAGS], name);
  760.             exit(1);
  761.         }
  762.  
  763.         flags = 0;
  764.         if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
  765.             flags |= CONF_FLAG_AUTHENABLE;
  766.         if (intval[TOK_FLAGS] & FLAG_MINPOLL)
  767.             flags |= CONF_FLAG_MINPOLL;
  768.         
  769.         /*
  770.          * This is as good as we can check it.  Add it in.
  771.          */
  772.         addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
  773.             (int)intval[TOK_VERSION], flags, intval[TOK_KEYID]);
  774.     }
  775. }
  776.  
  777.  
  778. /*
  779.  * doconfigure - attempt to resolve names and configure the server
  780.  */
  781. void
  782. doconfigure(dores)
  783.     int dores;
  784. {
  785.     register struct conf_entry *ce;
  786.     register struct conf_entry *ceremove;
  787.  
  788.     ce = confentries;
  789.     while (ce != NULL) {
  790.         if (dores && ce->ce_peeraddr == 0) {
  791.             if (!findhostaddr(ce)) {
  792.                 syslog(LOG_ERR,
  793.                     "couldn't resolve `%s', giving up on it",
  794.                     ce->ce_name);
  795.                 ceremove = ce;
  796.                 ce = ceremove->ce_next;
  797.                 removeentry(ceremove);
  798.                 continue;
  799.             }
  800.         }
  801.  
  802.         if (ce->ce_peeraddr != 0) {
  803.             if (request(&ce->ce_config)) {
  804.                 ceremove = ce;
  805.                 ce = ceremove->ce_next;
  806.                 removeentry(ceremove);
  807.                 continue;
  808.             }
  809.         }
  810.         ce = ce->ce_next;
  811.     }
  812. }
  813.