]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/ntp_intres.c
This commit was generated by cvs2svn to compensate for changes in r172668,
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / ntp_intres.c
1 /*
2  * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92
3  * routine callable from ntpd, rather than separate program
4  * also, key info passed in via a global, so no key file needed.
5  */
6
7 /*
8  * ntpres - process configuration entries which require use of the resolver
9  *
10  * This is meant to be run by ntpd on the fly.  It is not guaranteed
11  * to work properly if run by hand.  This is actually a quick hack to
12  * stave off violence from people who hate using numbers in the
13  * configuration file (at least I hope the rest of the daemon is
14  * better than this).  Also might provide some ideas about how one
15  * might go about autoconfiguring an NTP distribution network.
16  *
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "ntp_machine.h"
24 #include "ntpd.h"
25 #include "ntp_io.h"
26 #include "ntp_request.h"
27 #include "ntp_stdlib.h"
28 #include "ntp_syslog.h"
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <netdb.h>
33 #include <signal.h>
34
35 /**/
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 /**/
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>         /* MAXHOSTNAMELEN (often) */
41 #endif
42
43 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
44
45 /*
46  * Each item we are to resolve and configure gets one of these
47  * structures defined for it.
48  */
49 struct conf_entry {
50         struct conf_entry *ce_next;
51         char *ce_name;                  /* name we are trying to resolve */
52         struct conf_peer ce_config;     /* configuration info for peer */
53         struct sockaddr_storage peer_store; /* address info for both fams */
54 };
55 #define ce_peeraddr     ce_config.peeraddr
56 #define ce_peeraddr6    ce_config.peeraddr6
57 #define ce_hmode        ce_config.hmode
58 #define ce_version      ce_config.version
59 #define ce_minpoll      ce_config.minpoll
60 #define ce_maxpoll      ce_config.maxpoll
61 #define ce_flags        ce_config.flags
62 #define ce_ttl          ce_config.ttl
63 #define ce_keyid        ce_config.keyid
64 #define ce_keystr       ce_config.keystr
65
66 /*
67  * confentries is a pointer to the list of configuration entries
68  * we have left to do.
69  */
70 static struct conf_entry *confentries = NULL;
71
72 /*
73  * We take an interrupt every thirty seconds, at which time we decrement
74  * config_timer and resolve_timer.  The former is set to 2, so we retry
75  * unsucessful reconfigurations every minute.  The latter is set to
76  * an exponentially increasing value which starts at 2 and increases to
77  * 32.  When this expires we retry failed name resolutions.
78  *
79  * We sleep SLEEPTIME seconds before doing anything, to give the server
80  * time to arrange itself.
81  */
82 #define MINRESOLVE      2
83 #define MAXRESOLVE      32
84 #define CONFIG_TIME     2
85 #define ALARM_TIME      30
86 #define SLEEPTIME       2
87
88 static  volatile int config_timer = 0;
89 static  volatile int resolve_timer = 0;
90
91 static  int resolve_value;      /* next value of resolve timer */
92
93 /*
94  * Big hack attack
95  */
96 #define LOCALHOST       0x7f000001      /* 127.0.0.1, in hex, of course */
97 #define SKEWTIME        0x08000000      /* 0.03125 seconds as a l_fp fraction */
98
99 /*
100  * Select time out.  Set to 2 seconds.  The server is on the local machine,
101  * after all.
102  */
103 #define TIMEOUT_SEC     2
104 #define TIMEOUT_USEC    0
105
106
107 /*
108  * Input processing.  The data on each line in the configuration file
109  * is supposed to consist of entries in the following order
110  */
111 #define TOK_HOSTNAME    0
112 #define TOK_HMODE       1
113 #define TOK_VERSION     2
114 #define TOK_MINPOLL     3
115 #define TOK_MAXPOLL     4
116 #define TOK_FLAGS       5
117 #define TOK_TTL         6
118 #define TOK_KEYID       7
119 #define TOK_KEYSTR      8
120 #define NUMTOK          9
121
122 #define MAXLINESIZE     512
123
124
125 /*
126  * File descriptor for ntp request code.
127  */
128 static  SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */
129
130 /* stuff to be filled in by caller */
131
132 keyid_t req_keyid;      /* request keyid */
133 char *req_file;         /* name of the file with configuration info */
134
135 /* end stuff to be filled in */
136
137
138 static  RETSIGTYPE bong         P((int));
139 static  void    checkparent     P((void));
140 static  void    removeentry     P((struct conf_entry *));
141 static  void    addentry        P((char *, int, int, int, int, u_int,
142                                    int, keyid_t, char *));
143 static  int     findhostaddr    P((struct conf_entry *));
144 static  void    openntp         P((void));
145 static  int     request         P((struct conf_peer *));
146 static  char *  nexttoken       P((char **));
147 static  void    readconf        P((FILE *, char *));
148 static  void    doconfigure     P((int));
149
150 struct ntp_res_t_pkt {          /* Tagged packet: */
151         void *tag;              /* For the caller */
152         u_int32 paddr;          /* IP to look up, or 0 */
153         char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */
154 };
155
156 struct ntp_res_c_pkt {          /* Control packet: */
157         char name[MAXHOSTNAMELEN];
158         u_int32 paddr;
159         int mode;
160         int version;
161         int minpoll;
162         int maxpoll;
163         u_int flags;
164         int ttl;
165         keyid_t keyid;
166         u_char keystr[MAXFILENAME];
167 };
168
169
170 /*
171  * ntp_res_recv: Process an answer from the resolver
172  */
173
174 void
175 ntp_res_recv(void)
176 {
177         /*
178           We have data ready on our descriptor.
179           It may be an EOF, meaning the resolver process went away.
180           Otherwise, it will be an "answer".
181         */
182 }
183
184
185 /*
186  * ntp_intres needs;
187  *
188  *      req_key(???), req_keyid, req_file valid
189  *      syslog still open
190  */
191
192 void
193 ntp_intres(void)
194 {
195         FILE *in;
196 #ifdef HAVE_SIGSUSPEND
197         sigset_t set;
198
199         sigemptyset(&set);
200 #endif /* HAVE_SIGSUSPEND */
201
202 #ifdef DEBUG
203         if (debug > 1) {
204                 msyslog(LOG_INFO, "NTP_INTRES running");
205         }
206 #endif
207
208         /* check out auth stuff */
209         if (sys_authenticate) {
210                 if (!authistrusted(req_keyid)) {
211                         msyslog(LOG_ERR, "invalid request keyid %08x",
212                             req_keyid );
213                         exit(1);
214                 }
215         }
216
217         /*
218          * Read the configuration info
219          * {this is bogus, since we are forked, but it is easier
220          * to keep this code - gdt}
221          */
222         if ((in = fopen(req_file, "r")) == NULL) {
223                 msyslog(LOG_ERR, "can't open configuration file %s: %m",
224                         req_file);
225                 exit(1);
226         }
227         readconf(in, req_file);
228         (void) fclose(in);
229
230         if (!debug )
231                 (void) unlink(req_file);
232
233         /*
234          * Sleep a little to make sure the server is completely up
235          */
236
237         sleep(SLEEPTIME);
238
239         /*
240          * Make a first cut at resolving the bunch
241          */
242         doconfigure(1);
243         if (confentries == NULL) {
244 #if defined SYS_WINNT
245                 ExitThread(0);  /* Don't want to kill whole NT process */
246 #else
247                 exit(0);        /* done that quick */
248 #endif
249         }
250         
251         /*
252          * Here we've got some problem children.  Set up the timer
253          * and wait for it.
254          */
255         resolve_value = resolve_timer = MINRESOLVE;
256         config_timer = CONFIG_TIME;
257 #ifndef SYS_WINNT
258         (void) signal_no_reset(SIGALRM, bong);
259         alarm(ALARM_TIME);
260 #endif /* SYS_WINNT */
261
262         for (;;) {
263                 if (confentries == NULL)
264                     exit(0);
265
266                 checkparent();
267
268                 if (resolve_timer == 0) {
269                         if (resolve_value < MAXRESOLVE)
270                             resolve_value <<= 1;
271                         resolve_timer = resolve_value;
272 #ifdef DEBUG
273                         if (debug > 2)
274                                 msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
275 #endif
276                         config_timer = CONFIG_TIME;
277                         doconfigure(1);
278                         continue;
279                 } else if (config_timer == 0) {
280                         config_timer = CONFIG_TIME;
281 #ifdef DEBUG
282                         if (debug > 2)
283                                 msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
284 #endif
285                         doconfigure(0);
286                         continue;
287                 }
288 #ifndef SYS_WINNT
289                 /*
290                  * There is a race in here.  Is okay, though, since
291                  * all it does is delay things by 30 seconds.
292                  */
293 # ifdef HAVE_SIGSUSPEND
294                 sigsuspend(&set);
295 # else
296                 sigpause(0);
297 # endif /* HAVE_SIGSUSPEND */
298 #else
299                 if (config_timer > 0)
300                     config_timer--;
301                 if (resolve_timer > 0)
302                     resolve_timer--;
303                 sleep(ALARM_TIME);
304 #endif /* SYS_WINNT */
305         }
306 }
307
308
309 #ifndef SYS_WINNT
310 /*
311  * bong - service and reschedule an alarm() interrupt
312  */
313 static RETSIGTYPE
314 bong(
315         int sig
316         )
317 {
318         if (config_timer > 0)
319             config_timer--;
320         if (resolve_timer > 0)
321             resolve_timer--;
322         alarm(ALARM_TIME);
323 }
324 #endif /* SYS_WINNT */
325
326 /*
327  * checkparent - see if our parent process is still running
328  *
329  * No need to worry in the Windows NT environment whether the
330  * main thread is still running, because if it goes
331  * down it takes the whole process down with it (in
332  * which case we won't be running this thread either)
333  * Turn function into NOP;
334  */
335
336 static void
337 checkparent(void)
338 {
339 #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
340
341         /*
342          * If our parent (the server) has died we will have been
343          * inherited by init.  If so, exit.
344          */
345         if (getppid() == 1) {
346                 msyslog(LOG_INFO, "parent died before we finished, exiting");
347                 exit(0);
348         }
349 #endif /* SYS_WINNT && SYS_VXWORKS*/
350 }
351
352
353
354 /*
355  * removeentry - we are done with an entry, remove it from the list
356  */
357 static void
358 removeentry(
359         struct conf_entry *entry
360         )
361 {
362         register struct conf_entry *ce;
363
364         ce = confentries;
365         if (ce == entry) {
366                 confentries = ce->ce_next;
367                 return;
368         }
369
370         while (ce != NULL) {
371                 if (ce->ce_next == entry) {
372                         ce->ce_next = entry->ce_next;
373                         return;
374                 }
375                 ce = ce->ce_next;
376         }
377 }
378
379
380 /*
381  * addentry - add an entry to the configuration list
382  */
383 static void
384 addentry(
385         char *name,
386         int mode,
387         int version,
388         int minpoll,
389         int maxpoll,
390         u_int flags,
391         int ttl,
392         keyid_t keyid,
393         char *keystr
394         )
395 {
396         register char *cp;
397         register struct conf_entry *ce;
398         unsigned int len;
399
400 #ifdef DEBUG
401         if (debug > 1)
402                 msyslog(LOG_INFO, 
403                     "intres: <%s> %d %d %d %d %x %d %x %s\n", name,
404                     mode, version, minpoll, maxpoll, flags, ttl, keyid,
405                     keystr);
406 #endif
407         len = strlen(name) + 1;
408         cp = (char *)emalloc(len);
409         memmove(cp, name, len);
410
411         ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
412         ce->ce_name = cp;
413         ce->ce_peeraddr = 0;
414         ce->ce_peeraddr6 = in6addr_any;
415         ANYSOCK(&ce->peer_store);
416         ce->ce_hmode = (u_char)mode;
417         ce->ce_version = (u_char)version;
418         ce->ce_minpoll = (u_char)minpoll;
419         ce->ce_maxpoll = (u_char)maxpoll;
420         ce->ce_flags = (u_char)flags;
421         ce->ce_ttl = (u_char)ttl;
422         ce->ce_keyid = keyid;
423         strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME);
424         ce->ce_next = NULL;
425
426         if (confentries == NULL) {
427                 confentries = ce;
428         } else {
429                 register struct conf_entry *cep;
430
431                 for (cep = confentries; cep->ce_next != NULL;
432                      cep = cep->ce_next)
433                     /* nothing */;
434                 cep->ce_next = ce;
435         }
436 }
437
438
439 /*
440  * findhostaddr - resolve a host name into an address (Or vice-versa)
441  *
442  * Given one of {ce_peeraddr,ce_name}, find the other one.
443  * It returns 1 for "success" and 0 for an uncorrectable failure.
444  * Note that "success" includes try again errors.  You can tell that you
445  *  got a "try again" since {ce_peeraddr,ce_name} will still be zero.
446  */
447 static int
448 findhostaddr(
449         struct conf_entry *entry
450         )
451 {
452         struct addrinfo *addr;
453         int error;
454
455         checkparent();          /* make sure our guy is still running */
456
457         if (entry->ce_name != NULL && SOCKNUL(&entry->peer_store)) {
458                 /* HMS: Squawk? */
459                 msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
460                 return 1;
461         }
462
463         if (entry->ce_name == NULL && !SOCKNUL(&entry->peer_store)) {
464                 msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
465                 return 0;
466         }
467
468         if (entry->ce_name) {
469 #ifdef DEBUG
470                 if (debug > 2)
471                         msyslog(LOG_INFO, "findhostaddr: Resolving <%s>",
472                                 entry->ce_name);
473 #endif /* DEBUG */
474                 error = getaddrinfo(entry->ce_name, NULL, NULL, &addr);
475                 if (error == 0) {
476                         entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr));
477                         if (entry->peer_store.ss_family == AF_INET) {
478                                 entry->ce_peeraddr =
479                                     GET_INADDR(entry->peer_store);
480                                 entry->ce_config.v6_flag = 0;
481                         } else {
482                                 entry->ce_peeraddr6 =
483                                     GET_INADDR6(entry->peer_store);
484                                 entry->ce_config.v6_flag = 1;
485                         }
486                 }
487         } else {
488 #ifdef DEBUG
489                 if (debug > 2)
490                         msyslog(LOG_INFO, "findhostaddr: Resolving %s>",
491                                 stoa(&entry->peer_store));
492 #endif
493                 entry->ce_name = emalloc(MAXHOSTNAMELEN);
494                 error = getnameinfo((const struct sockaddr *)&entry->peer_store,
495                                    SOCKLEN(&entry->peer_store),
496                                    (char *)&entry->ce_name, MAXHOSTNAMELEN,
497                                    NULL, 0, 0);
498         }
499
500         if (error != 0) {
501                 /*
502                  * If the resolver is in use, see if the failure is
503                  * temporary.  If so, return success.
504                  */
505                 if (h_errno == TRY_AGAIN)
506                     return (1);
507                 return (0);
508         }
509
510         if (entry->ce_name) {
511 #ifdef DEBUG
512                 if (debug > 2)
513                         msyslog(LOG_INFO, "findhostaddr: name resolved.");
514 #endif
515
516 #ifdef DEBUG
517                 if (debug > 2)
518                         msyslog(LOG_INFO, "findhostaddr: address resolved.");
519 #endif
520         }
521                    
522         return (1);
523 }
524
525
526 /*
527  * openntp - open a socket to the ntp server
528  */
529 static void
530 openntp(void)
531 {
532         struct addrinfo hints;
533         struct addrinfo *addrResult;
534
535         if (sockfd >= 0)
536             return;
537
538         memset(&hints, 0, sizeof(hints));
539         hints.ai_family = AF_UNSPEC;
540         hints.ai_socktype = SOCK_DGRAM;
541         if (getaddrinfo(NULL, "ntp", &hints, &addrResult)!=0) {
542                 msyslog(LOG_ERR, "getaddrinfo failed: %m");
543                 exit(1);
544         }
545         sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0);
546
547         if (sockfd == -1) {
548                 msyslog(LOG_ERR, "socket() failed: %m");
549                 exit(1);
550         }
551
552         /*
553          * Make the socket non-blocking.  We'll wait with select()
554          */
555 #ifndef SYS_WINNT
556 #if defined(O_NONBLOCK)
557         if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
558                 msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
559                 exit(1);
560         }
561 #else
562 #if defined(FNDELAY)
563         if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
564                 msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
565                 exit(1);
566         }
567 #else
568 # include "Bletch: NEED NON BLOCKING IO"
569 #endif /* FNDDELAY */
570 #endif /* O_NONBLOCK */
571 #else  /* SYS_WINNT */
572         {
573                 int on = 1;
574                 if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) {
575                         msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
576                         exit(1); /* Windows NT - set socket in non-blocking mode */
577                 }
578         }
579 #endif /* SYS_WINNT */
580         if (connect(sockfd, addrResult->ai_addr, addrResult->ai_addrlen) == -1) {
581                 msyslog(LOG_ERR, "openntp: connect() failed: %m");
582                 exit(1);
583         }
584         freeaddrinfo(addrResult);
585 }
586
587
588 /*
589  * request - send a configuration request to the server, wait for a response
590  */
591 static int
592 request(
593         struct conf_peer *conf
594         )
595 {
596         fd_set fdset;
597         struct timeval tvout;
598         struct req_pkt reqpkt;
599         l_fp ts;
600         int n;
601 #ifdef SYS_WINNT
602         HANDLE hReadWriteEvent = NULL;
603         BOOL ret;
604         DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait;
605         OVERLAPPED overlap;
606 #endif /* SYS_WINNT */
607
608         checkparent();          /* make sure our guy is still running */
609
610         if (sockfd < 0)
611             openntp();
612         
613 #ifdef SYS_WINNT
614         hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
615 #endif /* SYS_WINNT */
616
617         /*
618          * Try to clear out any previously received traffic so it
619          * doesn't fool us.  Note the socket is nonblocking.
620          */
621         tvout.tv_sec =  0;
622         tvout.tv_usec = 0;
623         FD_ZERO(&fdset);
624         FD_SET(sockfd, &fdset);
625         while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
626                0) {
627                 recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
628                 FD_ZERO(&fdset);
629                 FD_SET(sockfd, &fdset);
630         }
631
632         /*
633          * Make up a request packet with the configuration info
634          */
635         memset((char *)&reqpkt, 0, sizeof(reqpkt));
636
637         reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
638         reqpkt.auth_seq = AUTH_SEQ(1, 0);       /* authenticated, no seq */
639         reqpkt.implementation = IMPL_XNTPD;     /* local implementation */
640         reqpkt.request = REQ_CONFIG;            /* configure a new peer */
641         reqpkt.err_nitems = ERR_NITEMS(0, 1);   /* one item */
642         reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer));
643         /* Make sure mbz_itemsize <= sizeof reqpkt.data */
644         if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) {
645                 msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!");
646                 exit(1);
647         }
648         memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
649         reqpkt.keyid = htonl(req_keyid);
650
651         get_systime(&ts);
652         L_ADDUF(&ts, SKEWTIME);
653         HTONL_FP(&ts, &reqpkt.tstamp);
654         n = 0;
655         if (sys_authenticate)
656                 n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC);
657
658         /*
659          * Done.  Send it.
660          */
661 #ifndef SYS_WINNT
662         n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0);
663         if (n < 0) {
664                 msyslog(LOG_ERR, "send to NTP server failed: %m");
665                 return 0;       /* maybe should exit */
666         }
667 #else
668         /* In the NT world, documentation seems to indicate that there
669          * exist _write and _read routines that can be used to do blocking
670          * I/O on sockets. Problem is these routines require a socket
671          * handle obtained through the _open_osf_handle C run-time API
672          * of which there is no explanation in the documentation. We need
673          * nonblocking write's and read's anyway for our purpose here.
674          * We're therefore forced to deviate a little bit from the Unix
675          * model here and use the ReadFile and WriteFile Win32 I/O API's
676          * on the socket
677          */
678         overlap.Offset = overlap.OffsetHigh = (DWORD)0;
679         overlap.hEvent = hReadWriteEvent;
680         ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n,
681                         (LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap);
682         if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
683                 msyslog(LOG_ERR, "send to NTP server failed: %m");
684                 return 0;
685         }
686         dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
687         if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
688                 if (dwWait == WAIT_FAILED)
689                     msyslog(LOG_ERR, "WaitForSingleObject failed: %m");
690                 return 0;
691         }
692 #endif /* SYS_WINNT */
693     
694
695         /*
696          * Wait for a response.  A weakness of the mode 7 protocol used
697          * is that there is no way to associate a response with a
698          * particular request, i.e. the response to this configuration
699          * request is indistinguishable from that to any other.  I should
700          * fix this some day.  In any event, the time out is fairly
701          * pessimistic to make sure that if an answer is coming back
702          * at all, we get it.
703          */
704         for (;;) {
705                 FD_ZERO(&fdset);
706                 FD_SET(sockfd, &fdset);
707                 tvout.tv_sec = TIMEOUT_SEC;
708                 tvout.tv_usec = TIMEOUT_USEC;
709
710                 n = select(sockfd + 1, &fdset, (fd_set *)0,
711                            (fd_set *)0, &tvout);
712
713                 if (n < 0)
714                 {
715                         if (errno != EINTR)
716                             msyslog(LOG_ERR, "select() fails: %m");
717                         return 0;
718                 }
719                 else if (n == 0)
720                 {
721                         if (debug)
722                             msyslog(LOG_INFO, "select() returned 0.");
723                         return 0;
724                 }
725
726 #ifndef SYS_WINNT
727                 n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
728                 if (n <= 0) {
729                         if (n < 0) {
730                                 msyslog(LOG_ERR, "recv() fails: %m");
731                                 return 0;
732                         }
733                         continue;
734                 }
735 #else /* Overlapped I/O used on non-blocking sockets on Windows NT */
736                 ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC,
737                                (LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap);
738                 if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
739                         msyslog(LOG_ERR, "ReadFile() fails: %m");
740                         return 0;
741                 }
742                 dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
743                 if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
744                         if (dwWait == WAIT_FAILED) {
745                                 msyslog(LOG_ERR, "WaitForSingleObject fails: %m");
746                                 return 0;
747                         }
748                         continue;
749                 }
750                 n = NumberOfBytesRead;
751 #endif /* SYS_WINNT */
752
753                 /*
754                  * Got one.  Check through to make sure it is what
755                  * we expect.
756                  */
757                 if (n < RESP_HEADER_SIZE) {
758                         msyslog(LOG_ERR, "received runt response (%d octets)",
759                                 n);
760                         continue;
761                 }
762
763                 if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
764 #ifdef DEBUG
765                         if (debug > 1)
766                             msyslog(LOG_INFO, "received non-response packet");
767 #endif
768                         continue;
769                 }
770
771                 if (ISMORE(reqpkt.rm_vn_mode)) {
772 #ifdef DEBUG
773                         if (debug > 1)
774                             msyslog(LOG_INFO, "received fragmented packet");
775 #endif
776                         continue;
777                 }
778
779                 if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2)
780                        || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION))
781                      || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
782 #ifdef DEBUG
783                         if (debug > 1)
784                             msyslog(LOG_INFO,
785                                     "version (%d/%d) or mode (%d/%d) incorrect",
786                                     INFO_VERSION(reqpkt.rm_vn_mode),
787                                     NTP_VERSION,
788                                     INFO_MODE(reqpkt.rm_vn_mode),
789                                     MODE_PRIVATE);
790 #endif
791                         continue;
792                 }
793
794                 if (INFO_SEQ(reqpkt.auth_seq) != 0) {
795 #ifdef DEBUG
796                         if (debug > 1)
797                             msyslog(LOG_INFO,
798                                     "nonzero sequence number (%d)",
799                                     INFO_SEQ(reqpkt.auth_seq));
800 #endif
801                         continue;
802                 }
803
804                 if (reqpkt.implementation != IMPL_XNTPD ||
805                     reqpkt.request != REQ_CONFIG) {
806 #ifdef DEBUG
807                         if (debug > 1)
808                             msyslog(LOG_INFO,
809                                     "implementation (%d) or request (%d) incorrect",
810                                     reqpkt.implementation, reqpkt.request);
811 #endif
812                         continue;
813                 }
814
815                 if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
816                     INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
817                     INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {
818 #ifdef DEBUG
819                         if (debug > 1)
820                             msyslog(LOG_INFO,
821                                     "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
822                                     INFO_NITEMS(reqpkt.err_nitems),
823                                     INFO_MBZ(reqpkt.mbz_itemsize),
824                                     INFO_ITEMSIZE(reqpkt.mbz_itemsize));
825 #endif
826                         continue;
827                 }
828
829                 n = INFO_ERR(reqpkt.err_nitems);
830                 switch (n) {
831                     case INFO_OKAY:
832                         /* success */
833                         return 1;
834                 
835                     case INFO_ERR_IMPL:
836                         msyslog(LOG_ERR,
837                                 "ntpd reports implementation mismatch!");
838                         return 0;
839                 
840                     case INFO_ERR_REQ:
841                         msyslog(LOG_ERR,
842                                 "ntpd says configuration request is unknown!");
843                         return 0;
844                 
845                     case INFO_ERR_FMT:
846                         msyslog(LOG_ERR,
847                                 "ntpd indicates a format error occurred!");
848                         return 0;
849
850                     case INFO_ERR_NODATA:
851                         msyslog(LOG_ERR,
852                                 "ntpd indicates no data available!");
853                         return 0;
854                 
855                     case INFO_ERR_AUTH:
856                         msyslog(LOG_ERR,
857                                 "ntpd returns a permission denied error!");
858                         return 0;
859
860                     default:
861                         msyslog(LOG_ERR,
862                                 "ntpd returns unknown error code %d!", n);
863                         return 0;
864                 }
865         }
866 }
867
868
869 /*
870  * nexttoken - return the next token from a line
871  */
872 static char *
873 nexttoken(
874         char **lptr
875         )
876 {
877         register char *cp;
878         register char *tstart;
879
880         cp = *lptr;
881
882         /*
883          * Skip leading white space
884          */
885         while (*cp == ' ' || *cp == '\t')
886             cp++;
887         
888         /*
889          * If this is the end of the line, return nothing.
890          */
891         if (*cp == '\n' || *cp == '\0') {
892                 *lptr = cp;
893                 return NULL;
894         }
895         
896         /*
897          * Must be the start of a token.  Record the pointer and look
898          * for the end.
899          */
900         tstart = cp++;
901         while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
902             cp++;
903         
904         /*
905          * Terminate the token with a \0.  If this isn't the end of the
906          * line, space to the next character.
907          */
908         if (*cp == '\n' || *cp == '\0')
909             *cp = '\0';
910         else
911             *cp++ = '\0';
912
913         *lptr = cp;
914         return tstart;
915 }
916
917
918 /*
919  * readconf - read the configuration information out of the file we
920  *            were passed.  Note that since the file is supposed to be
921  *            machine generated, we bail out at the first sign of trouble.
922  */
923 static void
924 readconf(
925         FILE *fp,
926         char *name
927         )
928 {
929         register int i;
930         char *token[NUMTOK];
931         u_long intval[NUMTOK];
932         u_int flags;
933         char buf[MAXLINESIZE];
934         char *bp;
935
936         while (fgets(buf, MAXLINESIZE, fp) != NULL) {
937
938                 bp = buf;
939                 for (i = 0; i < NUMTOK; i++) {
940                         if ((token[i] = nexttoken(&bp)) == NULL) {
941                                 msyslog(LOG_ERR,
942                                         "tokenizing error in file `%s', quitting",
943                                         name);
944                                 exit(1);
945                         }
946                 }
947
948                 for (i = 1; i < NUMTOK - 1; i++) {
949                         if (!atouint(token[i], &intval[i])) {
950                                 msyslog(LOG_ERR,
951                                         "format error for integer token `%s', file `%s', quitting",
952                                         token[i], name);
953                                 exit(1);
954                         }
955                 }
956
957                 if (intval[TOK_HMODE] != MODE_ACTIVE &&
958                     intval[TOK_HMODE] != MODE_CLIENT &&
959                     intval[TOK_HMODE] != MODE_BROADCAST) {
960                         msyslog(LOG_ERR, "invalid mode (%ld) in file %s",
961                                 intval[TOK_HMODE], name);
962                         exit(1);
963                 }
964
965                 if (intval[TOK_VERSION] > NTP_VERSION ||
966                     intval[TOK_VERSION] < NTP_OLDVERSION) {
967                         msyslog(LOG_ERR, "invalid version (%ld) in file %s",
968                                 intval[TOK_VERSION], name);
969                         exit(1);
970                 }
971                 if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
972                     intval[TOK_MINPOLL] > NTP_MAXPOLL) {
973                         msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
974                                 intval[TOK_MINPOLL], name);
975                         exit(1);
976                 }
977
978                 if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
979                     intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
980                         msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
981                                 intval[TOK_MAXPOLL], name);
982                         exit(1);
983                 }
984
985                 if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER |
986                     FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY))
987                     != 0) {
988                         msyslog(LOG_ERR, "invalid flags (%ld) in file %s",
989                                 intval[TOK_FLAGS], name);
990                         exit(1);
991                 }
992
993                 flags = 0;
994                 if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
995                     flags |= CONF_FLAG_AUTHENABLE;
996                 if (intval[TOK_FLAGS] & FLAG_PREFER)
997                     flags |= CONF_FLAG_PREFER;
998                 if (intval[TOK_FLAGS] & FLAG_NOSELECT)
999                     flags |= CONF_FLAG_NOSELECT;
1000                 if (intval[TOK_FLAGS] & FLAG_BURST)
1001                     flags |= CONF_FLAG_BURST;
1002                 if (intval[TOK_FLAGS] & FLAG_IBURST)
1003                     flags |= CONF_FLAG_IBURST;
1004                 if (intval[TOK_FLAGS] & FLAG_SKEY)
1005                     flags |= CONF_FLAG_SKEY;
1006
1007                 /*
1008                  * This is as good as we can check it.  Add it in.
1009                  */
1010                 addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
1011                          (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
1012                          (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
1013                          intval[TOK_KEYID], token[TOK_KEYSTR]);
1014         }
1015 }
1016
1017
1018 /*
1019  * doconfigure - attempt to resolve names and configure the server
1020  */
1021 static void
1022 doconfigure(
1023         int dores
1024         )
1025 {
1026         register struct conf_entry *ce;
1027         register struct conf_entry *ceremove;
1028
1029         ce = confentries;
1030         while (ce != NULL) {
1031 #ifdef DEBUG
1032                 if (debug > 1)
1033                         msyslog(LOG_INFO,
1034                             "doconfigure: <%s> has peeraddr %s",
1035                             ce->ce_name, stoa(&ce->peer_store));
1036 #endif
1037                 if (dores && !SOCKNUL(&(ce->peer_store))) {
1038                         if (!findhostaddr(ce)) {
1039                                 msyslog(LOG_ERR,
1040                                         "couldn't resolve `%s', giving up on it",
1041                                         ce->ce_name);
1042                                 ceremove = ce;
1043                                 ce = ceremove->ce_next;
1044                                 removeentry(ceremove);
1045                                 continue;
1046                         }
1047                 }
1048
1049                 if (!SOCKNUL(&ce->peer_store)) {
1050                         if (request(&ce->ce_config)) {
1051                                 ceremove = ce;
1052                                 ce = ceremove->ce_next;
1053                                 removeentry(ceremove);
1054                                 continue;
1055                         }
1056 #ifdef DEBUG
1057                         if (debug > 1) {
1058                                 msyslog(LOG_INFO,
1059                                     "doconfigure: request() FAILED, maybe next time.");
1060                         }
1061 #endif
1062                 }
1063                 ce = ce->ce_next;
1064         }
1065 }