turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / ntp / ntpd / ntp_intres.c
blob2a4b51fef7c92ad18d35f8c2aad2c6cd7fd85192
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 */
7 /*
8 * ntpres - process configuration entries which require use of the resolver
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.
19 * For special situations define the FORCE_DNSRETRY Macro
20 * to force retries even if it fails the lookup.
21 * Use with extreme caution since it will then retry forever.
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
28 #include "ntp_machine.h"
29 #include "ntpd.h"
30 #include "ntp_io.h"
31 #include "ntp_request.h"
32 #include "ntp_stdlib.h"
33 #include "ntp_syslog.h"
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <signal.h>
39 /**/
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 /**/
43 #ifdef HAVE_SYS_PARAM_H
44 # include <sys/param.h> /* MAXHOSTNAMELEN (often) */
45 #endif
47 #include <isc/net.h>
48 #include <isc/result.h>
50 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
53 * Each item we are to resolve and configure gets one of these
54 * structures defined for it.
56 struct conf_entry {
57 struct conf_entry *ce_next;
58 char *ce_name; /* name we are trying to resolve */
59 struct conf_peer ce_config; /* configuration info for peer */
60 struct sockaddr_storage peer_store; /* address info for both fams */
62 #define ce_peeraddr ce_config.peeraddr
63 #define ce_peeraddr6 ce_config.peeraddr6
64 #define ce_hmode ce_config.hmode
65 #define ce_version ce_config.version
66 #define ce_minpoll ce_config.minpoll
67 #define ce_maxpoll ce_config.maxpoll
68 #define ce_flags ce_config.flags
69 #define ce_ttl ce_config.ttl
70 #define ce_keyid ce_config.keyid
71 #define ce_keystr ce_config.keystr
74 * confentries is a pointer to the list of configuration entries
75 * we have left to do.
77 static struct conf_entry *confentries = NULL;
80 * We take an interrupt every thirty seconds, at which time we decrement
81 * config_timer and resolve_timer. The former is set to 2, so we retry
82 * unsucessful reconfigurations every minute. The latter is set to
83 * an exponentially increasing value which starts at 2 and increases to
84 * 32. When this expires we retry failed name resolutions.
86 * We sleep SLEEPTIME seconds before doing anything, to give the server
87 * time to arrange itself.
89 #define MINRESOLVE 2
90 #define MAXRESOLVE 32
91 #define CONFIG_TIME 2
92 #define ALARM_TIME 30
93 #define SLEEPTIME 2
95 static volatile int config_timer = 0;
96 static volatile int resolve_timer = 0;
98 static int resolve_value; /* next value of resolve timer */
101 * Big hack attack
103 #define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */
104 #define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
107 * Select time out. Set to 2 seconds. The server is on the local machine,
108 * after all.
110 #define TIMEOUT_SEC 2
111 #define TIMEOUT_USEC 0
115 * Input processing. The data on each line in the configuration file
116 * is supposed to consist of entries in the following order
118 #define TOK_HOSTNAME 0
119 #define TOK_HMODE 1
120 #define TOK_VERSION 2
121 #define TOK_MINPOLL 3
122 #define TOK_MAXPOLL 4
123 #define TOK_FLAGS 5
124 #define TOK_TTL 6
125 #define TOK_KEYID 7
126 #define TOK_KEYSTR 8
127 #define NUMTOK 9
129 #define MAXLINESIZE 512
133 * File descriptor for ntp request code.
135 static SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */
137 /* stuff to be filled in by caller */
139 keyid_t req_keyid; /* request keyid */
140 char *req_file; /* name of the file with configuration info */
142 /* end stuff to be filled in */
145 static void checkparent P((void));
146 static void removeentry P((struct conf_entry *));
147 static void addentry P((char *, int, int, int, int, u_int,
148 int, keyid_t, char *));
149 static int findhostaddr P((struct conf_entry *));
150 static void openntp P((void));
151 static int request P((struct conf_peer *));
152 static char * nexttoken P((char **));
153 static void readconf P((FILE *, char *));
154 static void doconfigure P((int));
156 struct ntp_res_t_pkt { /* Tagged packet: */
157 void *tag; /* For the caller */
158 u_int32 paddr; /* IP to look up, or 0 */
159 char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */
162 struct ntp_res_c_pkt { /* Control packet: */
163 char name[MAXHOSTNAMELEN];
164 u_int32 paddr;
165 int mode;
166 int version;
167 int minpoll;
168 int maxpoll;
169 u_int flags;
170 int ttl;
171 keyid_t keyid;
172 u_char keystr[MAXFILENAME];
176 static void resolver_exit P((int));
179 * Call here instead of just exiting
182 static void resolver_exit (int code)
184 #ifdef SYS_WINNT
185 CloseHandle(ResolverEventHandle);
186 ResolverEventHandle = NULL;
187 ExitThread(code); /* Just to kill the thread not the process */
188 #else
189 exit(code); /* kill the forked process */
190 #endif
194 * ntp_res_recv: Process an answer from the resolver
197 void
198 ntp_res_recv(void)
201 We have data ready on our descriptor.
202 It may be an EOF, meaning the resolver process went away.
203 Otherwise, it will be an "answer".
209 * ntp_intres needs;
211 * req_key(???), req_keyid, req_file valid
212 * syslog still open
215 void
216 ntp_intres(void)
218 FILE *in;
219 struct timeval tv;
220 fd_set fdset;
221 #ifdef SYS_WINNT
222 DWORD rc;
223 #else
224 int rc;
225 #endif
227 #ifdef DEBUG
228 if (debug > 1) {
229 msyslog(LOG_INFO, "NTP_INTRES running");
231 #endif
233 /* check out auth stuff */
234 if (sys_authenticate) {
235 if (!authistrusted(req_keyid)) {
236 msyslog(LOG_ERR, "invalid request keyid %08x",
237 req_keyid );
238 resolver_exit(1);
243 * Read the configuration info
244 * {this is bogus, since we are forked, but it is easier
245 * to keep this code - gdt}
247 if ((in = fopen(req_file, "r")) == NULL) {
248 msyslog(LOG_ERR, "can't open configuration file %s: %m",
249 req_file);
250 resolver_exit(1);
252 readconf(in, req_file);
253 (void) fclose(in);
255 #ifdef DEBUG
256 if (!debug )
257 #endif
258 (void) unlink(req_file);
261 * Set up the timers to do first shot immediately.
263 resolve_timer = 0;
264 resolve_value = MINRESOLVE;
265 config_timer = CONFIG_TIME;
267 for (;;) {
268 checkparent();
270 if (resolve_timer == 0) {
272 * Sleep a little to make sure the network is completely up
274 sleep(SLEEPTIME);
275 doconfigure(1);
277 /* prepare retry, in case there's more work to do */
278 resolve_timer = resolve_value;
279 #ifdef DEBUG
280 if (debug > 2)
281 msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
282 #endif
283 if (resolve_value < MAXRESOLVE)
284 resolve_value <<= 1;
286 config_timer = CONFIG_TIME;
287 } else if (config_timer == 0) { /* MB: in which case would this be required ? */
288 doconfigure(0);
289 /* MB: should we check now if we could exit, similar to the code above? */
290 config_timer = CONFIG_TIME;
291 #ifdef DEBUG
292 if (debug > 2)
293 msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
294 #endif
297 if (confentries == NULL)
298 resolver_exit(0); /* done */
300 #ifdef SYS_WINNT
301 rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME); /* in milliseconds */
303 if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */
304 resolve_timer = 0; /* retry resolving immediately */
305 continue;
308 if ( rc != WAIT_TIMEOUT ) /* not timeout: error */
309 resolver_exit(1);
311 #else /* not SYS_WINNT */
312 tv.tv_sec = ALARM_TIME;
313 tv.tv_usec = 0;
314 FD_ZERO(&fdset);
315 FD_SET(resolver_pipe_fd[0], &fdset);
316 rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv);
318 if (rc > 0) { /* parent process has written to the pipe */
319 read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc)); /* make pipe empty */
320 resolve_timer = 0; /* retry resolving immediately */
321 continue;
324 if ( rc < 0 ) /* select() returned error */
325 resolver_exit(1);
326 #endif
328 /* normal timeout, keep on waiting */
329 if (config_timer > 0)
330 config_timer--;
331 if (resolve_timer > 0)
332 resolve_timer--;
339 * checkparent - see if our parent process is still running
341 * No need to worry in the Windows NT environment whether the
342 * main thread is still running, because if it goes
343 * down it takes the whole process down with it (in
344 * which case we won't be running this thread either)
345 * Turn function into NOP;
348 static void
349 checkparent(void)
351 #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
354 * If our parent (the server) has died we will have been
355 * inherited by init. If so, exit.
357 if (getppid() == 1) {
358 msyslog(LOG_INFO, "parent died before we finished, exiting");
359 resolver_exit(0);
361 #endif /* SYS_WINNT && SYS_VXWORKS*/
367 * removeentry - we are done with an entry, remove it from the list
369 static void
370 removeentry(
371 struct conf_entry *entry
374 register struct conf_entry *ce;
376 ce = confentries;
377 if (ce == entry) {
378 confentries = ce->ce_next;
379 return;
382 while (ce != NULL) {
383 if (ce->ce_next == entry) {
384 ce->ce_next = entry->ce_next;
385 return;
387 ce = ce->ce_next;
393 * addentry - add an entry to the configuration list
395 static void
396 addentry(
397 char *name,
398 int mode,
399 int version,
400 int minpoll,
401 int maxpoll,
402 u_int flags,
403 int ttl,
404 keyid_t keyid,
405 char *keystr
408 register char *cp;
409 register struct conf_entry *ce;
410 unsigned int len;
412 #ifdef DEBUG
413 if (debug > 1)
414 msyslog(LOG_INFO,
415 "intres: <%s> %d %d %d %d %x %d %x %s\n", name,
416 mode, version, minpoll, maxpoll, flags, ttl, keyid,
417 keystr);
418 #endif
419 len = strlen(name) + 1;
420 cp = (char *)emalloc(len);
421 memmove(cp, name, len);
423 ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
424 ce->ce_name = cp;
425 ce->ce_peeraddr = 0;
426 #ifdef ISC_PLATFORM_HAVEIPV6
427 ce->ce_peeraddr6 = in6addr_any;
428 #endif
429 ANYSOCK(&ce->peer_store);
430 ce->ce_hmode = (u_char)mode;
431 ce->ce_version = (u_char)version;
432 ce->ce_minpoll = (u_char)minpoll;
433 ce->ce_maxpoll = (u_char)maxpoll;
434 ce->ce_flags = (u_char)flags;
435 ce->ce_ttl = (u_char)ttl;
436 ce->ce_keyid = keyid;
437 strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME);
438 ce->ce_next = NULL;
440 if (confentries == NULL) {
441 confentries = ce;
442 } else {
443 register struct conf_entry *cep;
445 for (cep = confentries; cep->ce_next != NULL;
446 cep = cep->ce_next)
447 /* nothing */;
448 cep->ce_next = ce;
454 * findhostaddr - resolve a host name into an address (Or vice-versa)
456 * Given one of {ce_peeraddr,ce_name}, find the other one.
457 * It returns 1 for "success" and 0 for an uncorrectable failure.
458 * Note that "success" includes try again errors. You can tell that you
459 * got a "try again" since {ce_peeraddr,ce_name} will still be zero.
461 static int
462 findhostaddr(
463 struct conf_entry *entry
466 struct addrinfo *addr;
467 struct addrinfo hints;
468 int error;
470 checkparent(); /* make sure our guy is still running */
472 if (entry->ce_name != NULL && !SOCKNUL(&entry->peer_store)) {
473 /* HMS: Squawk? */
474 msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
475 return 1;
478 if (entry->ce_name == NULL && SOCKNUL(&entry->peer_store)) {
479 msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
480 return 0;
483 if (entry->ce_name) {
484 #ifdef DEBUG
485 if (debug > 2)
486 msyslog(LOG_INFO, "findhostaddr: Resolving <%s>",
487 entry->ce_name);
488 #endif /* DEBUG */
490 memset(&hints, 0, sizeof(hints));
491 hints.ai_family = AF_UNSPEC;
493 * If the IPv6 stack is not available look only for IPv4 addresses
495 if (isc_net_probeipv6() != ISC_R_SUCCESS)
496 hints.ai_family = AF_INET;
498 error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
499 if (error == 0) {
500 entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr));
501 if (entry->peer_store.ss_family == AF_INET) {
502 entry->ce_peeraddr =
503 GET_INADDR(entry->peer_store);
504 entry->ce_config.v6_flag = 0;
505 } else {
506 entry->ce_peeraddr6 =
507 GET_INADDR6(entry->peer_store);
508 entry->ce_config.v6_flag = 1;
511 else if (error == EAI_NONAME)
513 msyslog(LOG_ERR, "host name not found: %s", entry->ce_name);
515 } else {
516 #ifdef DEBUG
517 if (debug > 2)
518 msyslog(LOG_INFO, "findhostaddr: Resolving %s>",
519 stoa(&entry->peer_store));
520 #endif
521 entry->ce_name = emalloc(MAXHOSTNAMELEN);
522 error = getnameinfo((const struct sockaddr *)&entry->peer_store,
523 SOCKLEN(&entry->peer_store),
524 (char *)&entry->ce_name, MAXHOSTNAMELEN,
525 NULL, 0, 0);
527 #ifdef DEBUG
528 if (debug > 2)
529 printf("intres: got error status of: %d\n", error);
530 #endif
533 * If the resolver failed, see if the failure is
534 * temporary. If so, return success.
536 if (error != 0) {
537 switch (error)
539 case EAI_AGAIN:
540 return (1);
541 case EAI_NONAME:
542 #ifndef FORCE_DNSRETRY
543 return (0);
544 #else
545 return (1);
546 #endif
547 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
548 case EAI_NODATA:
549 #endif
550 case EAI_FAIL:
551 #ifdef EAI_SYSTEM
552 case EAI_SYSTEM:
553 return (1);
554 #endif
555 default:
556 return (0);
560 if (entry->ce_name) {
561 #ifdef DEBUG
562 if (debug > 2)
563 msyslog(LOG_INFO, "findhostaddr: name resolved.");
564 #endif
566 #ifdef DEBUG
567 if (debug > 2)
568 msyslog(LOG_INFO, "findhostaddr: address resolved.");
569 #endif
572 return (1);
577 * openntp - open a socket to the ntp server
579 static void
580 openntp(void)
582 struct addrinfo hints;
583 struct addrinfo *addrResult;
584 const char *localhost = "127.0.0.1"; /* Use IPv6 loopback */
586 if (sockfd != INVALID_SOCKET)
587 return;
589 memset(&hints, 0, sizeof(hints));
592 * For now only bother with IPv4
594 hints.ai_family = AF_INET;
596 hints.ai_socktype = SOCK_DGRAM;
597 if (getaddrinfo(localhost, "ntp", &hints, &addrResult)!=0) {
598 msyslog(LOG_ERR, "getaddrinfo failed: %m");
599 resolver_exit(1);
601 sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0);
603 if (sockfd == -1) {
604 msyslog(LOG_ERR, "socket() failed: %m");
605 resolver_exit(1);
609 * Make the socket non-blocking. We'll wait with select()
611 #ifndef SYS_WINNT
612 #if defined(O_NONBLOCK)
613 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
614 msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
615 resolver_exit(1);
617 #else
618 #if defined(FNDELAY)
619 if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
620 msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
621 resolver_exit(1);
623 #else
624 # include "Bletch: NEED NON BLOCKING IO"
625 #endif /* FNDDELAY */
626 #endif /* O_NONBLOCK */
627 #else /* SYS_WINNT */
629 int on = 1;
630 if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) {
631 msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
632 resolver_exit(1); /* Windows NT - set socket in non-blocking mode */
635 #endif /* SYS_WINNT */
636 if (connect(sockfd, addrResult->ai_addr, addrResult->ai_addrlen) == -1) {
637 msyslog(LOG_ERR, "openntp: connect() failed: %m");
638 resolver_exit(1);
640 freeaddrinfo(addrResult);
645 * request - send a configuration request to the server, wait for a response
647 static int
648 request(
649 struct conf_peer *conf
652 fd_set fdset;
653 struct timeval tvout;
654 struct req_pkt reqpkt;
655 l_fp ts;
656 int n;
657 #ifdef SYS_WINNT
658 HANDLE hReadWriteEvent = NULL;
659 BOOL ret;
660 DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait;
661 OVERLAPPED overlap;
662 #endif /* SYS_WINNT */
664 checkparent(); /* make sure our guy is still running */
666 if (sockfd == INVALID_SOCKET)
667 openntp();
669 #ifdef SYS_WINNT
670 hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
671 #endif /* SYS_WINNT */
674 * Try to clear out any previously received traffic so it
675 * doesn't fool us. Note the socket is nonblocking.
677 tvout.tv_sec = 0;
678 tvout.tv_usec = 0;
679 FD_ZERO(&fdset);
680 FD_SET(sockfd, &fdset);
681 while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
682 0) {
683 recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
684 FD_ZERO(&fdset);
685 FD_SET(sockfd, &fdset);
689 * Make up a request packet with the configuration info
691 memset((char *)&reqpkt, 0, sizeof(reqpkt));
693 reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
694 reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */
695 reqpkt.implementation = IMPL_XNTPD; /* local implementation */
696 reqpkt.request = REQ_CONFIG; /* configure a new peer */
697 reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */
698 reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer));
699 /* Make sure mbz_itemsize <= sizeof reqpkt.data */
700 if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) {
701 msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!");
702 resolver_exit(1);
704 memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
705 reqpkt.keyid = htonl(req_keyid);
707 get_systime(&ts);
708 L_ADDUF(&ts, SKEWTIME);
709 HTONL_FP(&ts, &reqpkt.tstamp);
710 n = 0;
711 if (sys_authenticate)
712 n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC);
715 * Done. Send it.
717 #ifndef SYS_WINNT
718 n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0);
719 if (n < 0) {
720 msyslog(LOG_ERR, "send to NTP server failed: %m");
721 return 0; /* maybe should exit */
723 #else
724 /* In the NT world, documentation seems to indicate that there
725 * exist _write and _read routines that can be used to do blocking
726 * I/O on sockets. Problem is these routines require a socket
727 * handle obtained through the _open_osf_handle C run-time API
728 * of which there is no explanation in the documentation. We need
729 * nonblocking write's and read's anyway for our purpose here.
730 * We're therefore forced to deviate a little bit from the Unix
731 * model here and use the ReadFile and WriteFile Win32 I/O API's
732 * on the socket
734 overlap.Offset = overlap.OffsetHigh = (DWORD)0;
735 overlap.hEvent = hReadWriteEvent;
736 ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n,
737 NULL, (LPOVERLAPPED)&overlap);
738 if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
739 msyslog(LOG_ERR, "send to NTP server failed: %m");
740 return 0;
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 failed: %m");
746 return 0;
748 if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
749 (LPDWORD)&NumberOfBytesWritten, FALSE)) {
750 msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m");
751 return 0;
753 #endif /* SYS_WINNT */
757 * Wait for a response. A weakness of the mode 7 protocol used
758 * is that there is no way to associate a response with a
759 * particular request, i.e. the response to this configuration
760 * request is indistinguishable from that to any other. I should
761 * fix this some day. In any event, the time out is fairly
762 * pessimistic to make sure that if an answer is coming back
763 * at all, we get it.
765 for (;;) {
766 FD_ZERO(&fdset);
767 FD_SET(sockfd, &fdset);
768 tvout.tv_sec = TIMEOUT_SEC;
769 tvout.tv_usec = TIMEOUT_USEC;
771 n = select(sockfd + 1, &fdset, (fd_set *)0,
772 (fd_set *)0, &tvout);
774 if (n < 0)
776 if (errno != EINTR)
777 msyslog(LOG_ERR, "select() fails: %m");
778 return 0;
780 else if (n == 0)
782 #ifdef DEBUG
783 if (debug)
784 msyslog(LOG_INFO, "select() returned 0.");
785 #endif
786 return 0;
789 #ifndef SYS_WINNT
790 n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
791 if (n <= 0) {
792 if (n < 0) {
793 msyslog(LOG_ERR, "recv() fails: %m");
794 return 0;
796 continue;
798 #else /* Overlapped I/O used on non-blocking sockets on Windows NT */
799 ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC,
800 NULL, (LPOVERLAPPED)&overlap);
801 if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
802 msyslog(LOG_ERR, "ReadFile() fails: %m");
803 return 0;
805 dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
806 if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
807 if (dwWait == WAIT_FAILED) {
808 msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m");
809 return 0;
811 continue;
813 if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
814 (LPDWORD)&NumberOfBytesRead, FALSE)) {
815 msyslog(LOG_ERR, "GetOverlappedResult fails: %m");
816 return 0;
818 n = NumberOfBytesRead;
819 #endif /* SYS_WINNT */
822 * Got one. Check through to make sure it is what
823 * we expect.
825 if (n < RESP_HEADER_SIZE) {
826 msyslog(LOG_ERR, "received runt response (%d octets)",
828 continue;
831 if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
832 #ifdef DEBUG
833 if (debug > 1)
834 msyslog(LOG_INFO, "received non-response packet");
835 #endif
836 continue;
839 if (ISMORE(reqpkt.rm_vn_mode)) {
840 #ifdef DEBUG
841 if (debug > 1)
842 msyslog(LOG_INFO, "received fragmented packet");
843 #endif
844 continue;
847 if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2)
848 || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION))
849 || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
850 #ifdef DEBUG
851 if (debug > 1)
852 msyslog(LOG_INFO,
853 "version (%d/%d) or mode (%d/%d) incorrect",
854 INFO_VERSION(reqpkt.rm_vn_mode),
855 NTP_VERSION,
856 INFO_MODE(reqpkt.rm_vn_mode),
857 MODE_PRIVATE);
858 #endif
859 continue;
862 if (INFO_SEQ(reqpkt.auth_seq) != 0) {
863 #ifdef DEBUG
864 if (debug > 1)
865 msyslog(LOG_INFO,
866 "nonzero sequence number (%d)",
867 INFO_SEQ(reqpkt.auth_seq));
868 #endif
869 continue;
872 if (reqpkt.implementation != IMPL_XNTPD ||
873 reqpkt.request != REQ_CONFIG) {
874 #ifdef DEBUG
875 if (debug > 1)
876 msyslog(LOG_INFO,
877 "implementation (%d) or request (%d) incorrect",
878 reqpkt.implementation, reqpkt.request);
879 #endif
880 continue;
883 if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
884 INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
885 INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {
886 #ifdef DEBUG
887 if (debug > 1)
888 msyslog(LOG_INFO,
889 "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
890 INFO_NITEMS(reqpkt.err_nitems),
891 INFO_MBZ(reqpkt.mbz_itemsize),
892 INFO_ITEMSIZE(reqpkt.mbz_itemsize));
893 #endif
894 continue;
897 n = INFO_ERR(reqpkt.err_nitems);
898 switch (n) {
899 case INFO_OKAY:
900 /* success */
901 return 1;
903 case INFO_ERR_IMPL:
904 msyslog(LOG_ERR,
905 "ntpd reports implementation mismatch!");
906 return 0;
908 case INFO_ERR_REQ:
909 msyslog(LOG_ERR,
910 "ntpd says configuration request is unknown!");
911 return 0;
913 case INFO_ERR_FMT:
914 msyslog(LOG_ERR,
915 "ntpd indicates a format error occurred!");
916 return 0;
918 case INFO_ERR_NODATA:
919 msyslog(LOG_ERR,
920 "ntpd indicates no data available!");
921 return 0;
923 case INFO_ERR_AUTH:
924 msyslog(LOG_ERR,
925 "ntpd returns a permission denied error!");
926 return 0;
928 default:
929 msyslog(LOG_ERR,
930 "ntpd returns unknown error code %d!", n);
931 return 0;
938 * nexttoken - return the next token from a line
940 static char *
941 nexttoken(
942 char **lptr
945 register char *cp;
946 register char *tstart;
948 cp = *lptr;
951 * Skip leading white space
953 while (*cp == ' ' || *cp == '\t')
954 cp++;
957 * If this is the end of the line, return nothing.
959 if (*cp == '\n' || *cp == '\0') {
960 *lptr = cp;
961 return NULL;
965 * Must be the start of a token. Record the pointer and look
966 * for the end.
968 tstart = cp++;
969 while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0')
970 cp++;
973 * Terminate the token with a \0. If this isn't the end of the
974 * line, space to the next character.
976 if (*cp == '\n' || *cp == '\0')
977 *cp = '\0';
978 else
979 *cp++ = '\0';
981 *lptr = cp;
982 return tstart;
987 * readconf - read the configuration information out of the file we
988 * were passed. Note that since the file is supposed to be
989 * machine generated, we bail out at the first sign of trouble.
991 static void
992 readconf(
993 FILE *fp,
994 char *name
997 register int i;
998 char *token[NUMTOK];
999 u_long intval[NUMTOK];
1000 u_int flags;
1001 char buf[MAXLINESIZE];
1002 char *bp;
1004 while (fgets(buf, MAXLINESIZE, fp) != NULL) {
1006 bp = buf;
1007 for (i = 0; i < NUMTOK; i++) {
1008 if ((token[i] = nexttoken(&bp)) == NULL) {
1009 msyslog(LOG_ERR,
1010 "tokenizing error in file `%s', quitting",
1011 name);
1012 resolver_exit(1);
1016 for (i = 1; i < NUMTOK - 1; i++) {
1017 if (!atouint(token[i], &intval[i])) {
1018 msyslog(LOG_ERR,
1019 "format error for integer token `%s', file `%s', quitting",
1020 token[i], name);
1021 resolver_exit(1);
1025 if (intval[TOK_HMODE] != MODE_ACTIVE &&
1026 intval[TOK_HMODE] != MODE_CLIENT &&
1027 intval[TOK_HMODE] != MODE_BROADCAST) {
1028 msyslog(LOG_ERR, "invalid mode (%ld) in file %s",
1029 intval[TOK_HMODE], name);
1030 resolver_exit(1);
1033 if (intval[TOK_VERSION] > NTP_VERSION ||
1034 intval[TOK_VERSION] < NTP_OLDVERSION) {
1035 msyslog(LOG_ERR, "invalid version (%ld) in file %s",
1036 intval[TOK_VERSION], name);
1037 resolver_exit(1);
1039 if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
1040 intval[TOK_MINPOLL] > NTP_MAXPOLL) {
1041 msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
1042 intval[TOK_MINPOLL], name);
1043 resolver_exit(1);
1046 if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
1047 intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
1048 msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
1049 intval[TOK_MAXPOLL], name);
1050 resolver_exit(1);
1053 if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER |
1054 FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY))
1055 != 0) {
1056 msyslog(LOG_ERR, "invalid flags (%ld) in file %s",
1057 intval[TOK_FLAGS], name);
1058 resolver_exit(1);
1061 flags = 0;
1062 if (intval[TOK_FLAGS] & FLAG_AUTHENABLE)
1063 flags |= CONF_FLAG_AUTHENABLE;
1064 if (intval[TOK_FLAGS] & FLAG_PREFER)
1065 flags |= CONF_FLAG_PREFER;
1066 if (intval[TOK_FLAGS] & FLAG_NOSELECT)
1067 flags |= CONF_FLAG_NOSELECT;
1068 if (intval[TOK_FLAGS] & FLAG_BURST)
1069 flags |= CONF_FLAG_BURST;
1070 if (intval[TOK_FLAGS] & FLAG_IBURST)
1071 flags |= CONF_FLAG_IBURST;
1072 if (intval[TOK_FLAGS] & FLAG_SKEY)
1073 flags |= CONF_FLAG_SKEY;
1076 * This is as good as we can check it. Add it in.
1078 addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE],
1079 (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL],
1080 (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL],
1081 intval[TOK_KEYID], token[TOK_KEYSTR]);
1087 * doconfigure - attempt to resolve names and configure the server
1089 static void
1090 doconfigure(
1091 int dores
1094 register struct conf_entry *ce;
1095 register struct conf_entry *ceremove;
1097 #ifdef DEBUG
1098 if (debug > 1)
1099 msyslog(LOG_INFO, "Running doconfigure %s DNS",
1100 dores ? "with" : "without" );
1101 #endif
1103 ce = confentries;
1104 while (ce != NULL) {
1105 #ifdef DEBUG
1106 if (debug > 1)
1107 msyslog(LOG_INFO,
1108 "doconfigure: <%s> has peeraddr %s",
1109 ce->ce_name, stoa(&ce->peer_store));
1110 #endif
1111 if (dores && SOCKNUL(&(ce->peer_store))) {
1112 if (!findhostaddr(ce)) {
1113 msyslog(LOG_ERR,
1114 "couldn't resolve `%s', giving up on it",
1115 ce->ce_name);
1116 ceremove = ce;
1117 ce = ceremove->ce_next;
1118 removeentry(ceremove);
1119 continue;
1123 if (!SOCKNUL(&ce->peer_store)) {
1124 if (request(&ce->ce_config)) {
1125 ceremove = ce;
1126 ce = ceremove->ce_next;
1127 removeentry(ceremove);
1128 continue;
1130 #ifdef DEBUG
1131 if (debug > 1) {
1132 msyslog(LOG_INFO,
1133 "doconfigure: request() FAILED, maybe next time.");
1135 #endif
1137 ce = ce->ce_next;