4 * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92
5 * routine callable from ntpd, rather than separate program
6 * also, key info passed in via a global, so no key file needed.
10 * ntpres - process configuration entries which require use of the resolver
12 * This is meant to be run by ntpd on the fly. It is not guaranteed
13 * to work properly if run by hand. This is actually a quick hack to
14 * stave off violence from people who hate using numbers in the
15 * configuration file (at least I hope the rest of the daemon is
16 * better than this). Also might provide some ideas about how one
17 * might go about autoconfiguring an NTP distribution network.
25 #include "ntp_machine.h"
28 #include "ntp_request.h"
29 #include "ntp_stdlib.h"
30 #include "ntp_syslog.h"
31 #include "ntp_config.h"
33 #ifndef NO_INTRES /* from ntp_config.h */
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 #ifdef HAVE_SYS_PARAM_H
46 # include <sys/param.h> /* MAXHOSTNAMELEN (often) */
49 #if defined(HAVE_RES_INIT) || defined(HAVE___RES_INIT)
54 #include <isc/result.h>
56 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
59 * Each item we are to resolve and configure gets one of these
60 * structures defined for it.
63 struct conf_entry
*ce_next
;
64 char *ce_name
; /* name to resolve */
65 struct conf_peer ce_config
; /* config info for peer */
66 int no_needed
; /* number of addresses needed (pool) */
67 /* no_needed isn't used yet: It's needed to fix bug-975 */
68 int type
; /* -4 and -6 flags */
69 sockaddr_u peer_store
; /* address info for both fams */
71 #define ce_peeraddr ce_config.peeraddr
72 #define ce_peeraddr6 ce_config.peeraddr6
73 #define ce_hmode ce_config.hmode
74 #define ce_version ce_config.version
75 #define ce_minpoll ce_config.minpoll
76 #define ce_maxpoll ce_config.maxpoll
77 #define ce_flags ce_config.flags
78 #define ce_ttl ce_config.ttl
79 #define ce_keyid ce_config.keyid
80 #define ce_keystr ce_config.keystr
83 * confentries is a pointer to the list of configuration entries
86 static struct conf_entry
*confentries
= NULL
;
89 * We take an interrupt every thirty seconds, at which time we decrement
90 * config_timer and resolve_timer. The former is set to 2, so we retry
91 * unsucessful reconfigurations every minute. The latter is set to
92 * an exponentially increasing value which starts at 2 and increases to
93 * 32. When this expires we retry failed name resolutions.
95 * We sleep SLEEPTIME seconds before doing anything, to give the server
96 * time to arrange itself.
100 #define CONFIG_TIME 2
101 #define ALARM_TIME 30
104 static volatile int config_timer
= 0;
105 static volatile int resolve_timer
= 0;
107 static int resolve_value
; /* next value of resolve timer */
112 #define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
115 * Select time out. Set to 2 seconds. The server is on the local machine,
118 #define TIMEOUT_SEC 2
119 #define TIMEOUT_USEC 0
123 * Input processing. The data on each line in the configuration file
124 * is supposed to consist of entries in the following order
126 #define TOK_HOSTNAME 0
130 #define TOK_VERSION 4
131 #define TOK_MINPOLL 5
132 #define TOK_MAXPOLL 6
136 #define TOK_KEYSTR 10
139 #define MAXLINESIZE 512
143 * File descriptor for ntp request code.
145 static SOCKET sockfd
= INVALID_SOCKET
; /* NT uses SOCKET */
147 /* stuff to be filled in by caller */
149 keyid_t req_keyid
; /* request keyid */
150 int req_keytype
; /* OpenSSL NID such as NID_md5 */
151 size_t req_hashlen
; /* digest size for req_keytype */
152 char *req_file
; /* name of the file with configuration info */
154 /* end stuff to be filled in */
157 static void checkparent (void);
158 static struct conf_entry
*
159 removeentry (struct conf_entry
*);
160 static void addentry (char *, int, int, int, int, int, int, u_int
,
161 int, keyid_t
, char *);
162 static int findhostaddr (struct conf_entry
*);
163 static void openntp (void);
164 static int request (struct conf_peer
*);
165 static char * nexttoken (char **);
166 static void readconf (FILE *, char *);
167 static void doconfigure (int);
169 struct ntp_res_t_pkt
{ /* Tagged packet: */
170 void *tag
; /* For the caller */
171 u_int32 paddr
; /* IP to look up, or 0 */
172 char name
[MAXHOSTNAMELEN
]; /* Name to look up (if 1st byte is not 0) */
175 struct ntp_res_c_pkt
{ /* Control packet: */
176 char name
[MAXHOSTNAMELEN
];
185 u_char keystr
[MAXFILENAME
];
189 static void resolver_exit (int);
192 * Call here instead of just exiting
195 static void resolver_exit (int code
)
198 CloseHandle(ResolverEventHandle
);
199 ResolverEventHandle
= NULL
;
200 _endthreadex(code
); /* Just to kill the thread not the process */
202 exit(code
); /* kill the forked process */
207 * ntp_res_recv: Process an answer from the resolver
214 We have data ready on our descriptor.
215 It may be an EOF, meaning the resolver process went away.
216 Otherwise, it will be an "answer".
224 * req_key(???), req_keyid, req_file valid
243 msyslog(LOG_INFO
, "NTP_INTRES running");
247 /* check out auth stuff */
248 if (sys_authenticate
) {
249 if (!authistrusted(req_keyid
)) {
250 msyslog(LOG_ERR
, "invalid request keyid %08x",
257 * Read the configuration info
258 * {this is bogus, since we are forked, but it is easier
259 * to keep this code - gdt}
261 if ((in
= fopen(req_file
, "r")) == NULL
) {
262 msyslog(LOG_ERR
, "can't open configuration file %s: %m",
266 readconf(in
, req_file
);
272 if (unlink(req_file
))
274 "unable to remove intres request file %s, %m",
278 * Set up the timers to do first shot immediately.
281 resolve_value
= MINRESOLVE
;
282 config_timer
= CONFIG_TIME
;
287 if (resolve_timer
== 0) {
289 * Sleep a little to make sure the network is completely up
294 /* prepare retry, in case there's more work to do */
295 resolve_timer
= resolve_value
;
298 msyslog(LOG_INFO
, "resolve_timer: 0->%d", resolve_timer
);
300 if (resolve_value
< MAXRESOLVE
)
303 config_timer
= CONFIG_TIME
;
304 } else if (config_timer
== 0) { /* MB: in which case would this be required ? */
306 /* MB: should we check now if we could exit, similar to the code above? */
307 config_timer
= CONFIG_TIME
;
310 msyslog(LOG_INFO
, "config_timer: 0->%d", config_timer
);
314 if (confentries
== NULL
)
315 resolver_exit(0); /* done */
318 rc
= WaitForSingleObject(ResolverEventHandle
, 1000 * ALARM_TIME
); /* in milliseconds */
320 if ( rc
== WAIT_OBJECT_0
) { /* signaled by the main thread */
321 resolve_timer
= 0; /* retry resolving immediately */
325 if ( rc
!= WAIT_TIMEOUT
) /* not timeout: error */
328 #else /* not SYS_WINNT */
329 /* Bug 1386: fork() in NetBSD leaves timers running. */
330 /* So we need to retry select on EINTR */
331 time_left
= ALARM_TIME
;
332 while (time_left
> 0) {
333 tv
.tv_sec
= time_left
;
336 FD_SET(resolver_pipe_fd
[0], &fdset
);
337 rc
= select(resolver_pipe_fd
[0] + 1, &fdset
, (fd_set
*)0, (fd_set
*)0, &tv
);
339 if (rc
== 0) /* normal timeout */
342 if (rc
> 0) { /* parent process has written to the pipe */
343 read(resolver_pipe_fd
[0], (char *)&rc
, sizeof(rc
)); /* make pipe empty */
344 resolve_timer
= 0; /* retry resolving immediately */
348 if ( rc
< 0 ) { /* select() returned error */
349 if (errno
== EINTR
) { /* Timer went off */
350 time_left
-= (1<<EVENT_TIMEOUT
);
351 continue; /* try again */
353 msyslog(LOG_ERR
, "ntp_intres: Error from select: %s",
360 /* normal timeout, keep on waiting */
361 if (config_timer
> 0)
363 if (resolve_timer
> 0)
371 * ntp_intres_thread wraps the slightly different interface of Windows
372 * thread functions and ntp_intres
375 ntp_intres_thread(void *UnusedThreadArg
)
377 UNUSED_ARG(UnusedThreadArg
);
382 #endif /* SYS_WINNT */
386 * checkparent - see if our parent process is still running
388 * No need to worry in the Windows NT environment whether the
389 * main thread is still running, because if it goes
390 * down it takes the whole process down with it (in
391 * which case we won't be running this thread either)
392 * Turn function into NOP;
398 #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
401 * If our parent (the server) has died we will have been
402 * inherited by init. If so, exit.
404 if (getppid() == 1) {
405 msyslog(LOG_INFO
, "parent died before we finished, exiting");
408 #endif /* SYS_WINNT && SYS_VXWORKS*/
414 * removeentry - we are done with an entry, remove it from the list
416 static struct conf_entry
*
418 struct conf_entry
*entry
421 register struct conf_entry
*ce
;
422 struct conf_entry
*next_ce
;
426 confentries
= ce
->ce_next
;
429 if (ce
->ce_next
== entry
) {
430 ce
->ce_next
= entry
->ce_next
;
436 next_ce
= entry
->ce_next
;
437 if (entry
->ce_name
!= NULL
)
438 free(entry
->ce_name
);
446 * addentry - add an entry to the configuration list
463 register struct conf_entry
*ce
;
468 "intres: <%s> %d %d %d %d %d %d %x %d %x %s",
469 name
, no_needed
, type
, mode
, version
,
470 minpoll
, maxpoll
, flags
, ttl
, keyid
, keystr
);
472 ce
= emalloc(sizeof(*ce
));
473 ce
->ce_name
= estrdup(name
);
475 #ifdef ISC_PLATFORM_HAVEIPV6
476 ce
->ce_peeraddr6
= in6addr_any
;
478 ZERO_SOCK(&ce
->peer_store
);
479 ce
->ce_hmode
= (u_char
)mode
;
480 ce
->ce_version
= (u_char
)version
;
481 ce
->ce_minpoll
= (u_char
)minpoll
;
482 ce
->ce_maxpoll
= (u_char
)maxpoll
;
483 ce
->no_needed
= no_needed
; /* Not used after here. */
484 /* Start of fixing bug-975 */
486 ce
->ce_flags
= (u_char
)flags
;
487 ce
->ce_ttl
= (u_char
)ttl
;
488 ce
->ce_keyid
= keyid
;
489 strncpy(ce
->ce_keystr
, keystr
, sizeof(ce
->ce_keystr
) - 1);
490 ce
->ce_keystr
[sizeof(ce
->ce_keystr
) - 1] = 0;
493 if (confentries
== NULL
) {
496 register struct conf_entry
*cep
;
498 for (cep
= confentries
; cep
->ce_next
!= NULL
;
507 * findhostaddr - resolve a host name into an address (Or vice-versa)
509 * Given one of {ce_peeraddr,ce_name}, find the other one.
510 * It returns 1 for "success" and 0 for an uncorrectable failure.
511 * Note that "success" includes try again errors. You can tell that you
512 * got a "try again" since {ce_peeraddr,ce_name} will still be zero.
516 struct conf_entry
*entry
519 static int eai_again_seen
= 0;
520 struct addrinfo
*addr
;
521 struct addrinfo hints
;
525 checkparent(); /* make sure our guy is still running */
527 if (entry
->ce_name
!= NULL
&& !SOCK_UNSPEC(&entry
->peer_store
)) {
529 msyslog(LOG_ERR
, "findhostaddr: both ce_name and ce_peeraddr are defined...");
533 if (entry
->ce_name
== NULL
&& SOCK_UNSPEC(&entry
->peer_store
)) {
534 msyslog(LOG_ERR
, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
538 if (entry
->ce_name
) {
539 DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
542 memset(&hints
, 0, sizeof(hints
));
543 hints
.ai_family
= entry
->type
;
544 hints
.ai_socktype
= SOCK_DGRAM
;
545 hints
.ai_protocol
= IPPROTO_UDP
;
547 * If IPv6 is not available look only for v4 addresses
550 hints
.ai_family
= AF_INET
;
551 error
= getaddrinfo(entry
->ce_name
, NULL
, &hints
, &addr
);
553 entry
->peer_store
= *((sockaddr_u
*)(addr
->ai_addr
));
554 if (IS_IPV4(&entry
->peer_store
)) {
556 NSRCADR(&entry
->peer_store
);
557 entry
->ce_config
.v6_flag
= 0;
559 entry
->ce_peeraddr6
=
560 SOCK_ADDR6(&entry
->peer_store
);
561 entry
->ce_config
.v6_flag
= 1;
566 DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
567 stoa(&entry
->peer_store
)));
569 entry
->ce_name
= emalloc(MAXHOSTNAMELEN
);
570 error
= getnameinfo((const struct sockaddr
*)&entry
->peer_store
,
571 SOCKLEN(&entry
->peer_store
),
572 (char *)&entry
->ce_name
, MAXHOSTNAMELEN
,
578 /* again is our return value, for success it is 1 */
581 DPRINTF(2, ("findhostaddr: %s resolved.\n",
582 (entry
->ce_name
) ? "name" : "address"));
585 * If the resolver failed, see if the failure is
586 * temporary. If so, return success.
602 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
605 msyslog(LOG_ERR
, "host name not found%s%s: %s",
606 (EAI_NONAME
== error
) ? "" : " EAI_NODATA",
607 (eai_again_seen
) ? " (permanent)" : "",
609 again
= !eai_again_seen
;
615 * EAI_SYSTEM means the real error is in errno. We should be more
616 * discriminating about which errno values require retrying, but
617 * this matches existing behavior.
620 DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
621 errno
, strerror(errno
)));
626 /* do this here to avoid perturbing errno earlier */
627 DPRINTF(2, ("intres: got error status of: %d\n", error
));
635 * openntp - open a socket to the ntp server
640 const char *localhost
= "127.0.0.1"; /* Use IPv4 loopback */
641 struct addrinfo hints
;
642 struct addrinfo
*addr
;
646 if (sockfd
!= INVALID_SOCKET
)
649 memset(&hints
, 0, sizeof(hints
));
652 * For now only bother with IPv4
654 hints
.ai_family
= AF_INET
;
655 hints
.ai_socktype
= SOCK_DGRAM
;
657 err
= getaddrinfo(localhost
, "ntp", &hints
, &addr
);
661 if (EAI_SYSTEM
== err
)
662 msyslog(LOG_ERR
, "getaddrinfo(%s) failed: %m",
666 msyslog(LOG_ERR
, "getaddrinfo(%s) failed: %s",
667 localhost
, gai_strerror(err
));
671 sockfd
= socket(addr
->ai_family
, addr
->ai_socktype
, 0);
673 if (INVALID_SOCKET
== sockfd
) {
674 msyslog(LOG_ERR
, "socket() failed: %m");
680 * On Windows only the count of sockets must be less than
681 * FD_SETSIZE. On Unix each descriptor's value must be less
682 * than FD_SETSIZE, as fd_set is a bit array.
684 if (sockfd
>= FD_SETSIZE
) {
685 msyslog(LOG_ERR
, "socket fd %d too large, FD_SETSIZE %d",
686 (int)sockfd
, FD_SETSIZE
);
691 * Make the socket non-blocking. We'll wait with select()
692 * Unix: fcntl(O_NONBLOCK) or fcntl(FNDELAY)
695 if (fcntl(sockfd
, F_SETFL
, O_NONBLOCK
) == -1) {
696 msyslog(LOG_ERR
, "fcntl(O_NONBLOCK) failed: %m");
701 if (fcntl(sockfd
, F_SETFL
, FNDELAY
) == -1) {
702 msyslog(LOG_ERR
, "fcntl(FNDELAY) failed: %m");
706 # include "Bletch: NEED NON BLOCKING IO"
707 # endif /* FNDDELAY */
708 # endif /* O_NONBLOCK */
709 (void)on
; /* quiet unused warning */
710 #else /* !SYS_WINNT above */
712 * Make the socket non-blocking. We'll wait with select()
713 * Windows: ioctlsocket(FIONBIO)
716 err
= ioctlsocket(sockfd
, FIONBIO
, &on
);
717 if (SOCKET_ERROR
== err
) {
718 msyslog(LOG_ERR
, "ioctlsocket(FIONBIO) fails: %m");
721 #endif /* SYS_WINNT */
723 err
= connect(sockfd
, addr
->ai_addr
, addr
->ai_addrlen
);
724 if (SOCKET_ERROR
== err
) {
725 msyslog(LOG_ERR
, "openntp: connect() failed: %m");
734 * request - send a configuration request to the server, wait for a response
738 struct conf_peer
*conf
741 struct sock_timeval tvout
;
742 struct req_pkt reqpkt
;
744 size_t total_len
; /* req_len plus keyid & digest */
753 HANDLE hReadWriteEvent
= NULL
;
755 DWORD NumberOfBytesWritten
, NumberOfBytesRead
, dwWait
;
757 #endif /* SYS_WINNT */
759 checkparent(); /* make sure our guy is still running */
761 if (sockfd
== INVALID_SOCKET
)
765 hReadWriteEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
766 #endif /* SYS_WINNT */
769 * Try to clear out any previously received traffic so it
770 * doesn't fool us. Note the socket is nonblocking.
775 FD_SET(sockfd
, &fdset
);
776 while (select(sockfd
+ 1, &fdset
, (fd_set
*)0, (fd_set
*)0, &tvout
) >
778 recv(sockfd
, (char *)&reqpkt
, sizeof(reqpkt
), 0);
780 FD_SET(sockfd
, &fdset
);
784 * Make up a request packet with the configuration info
786 memset(&reqpkt
, 0, sizeof(reqpkt
));
788 reqpkt
.rm_vn_mode
= RM_VN_MODE(0, 0, 0);
789 reqpkt
.auth_seq
= AUTH_SEQ(1, 0); /* authenticated, no seq */
790 reqpkt
.implementation
= IMPL_XNTPD
; /* local implementation */
791 reqpkt
.request
= REQ_CONFIG
; /* configure a new peer */
792 reqpkt
.err_nitems
= ERR_NITEMS(0, 1); /* one item */
793 reqpkt
.mbz_itemsize
= MBZ_ITEMSIZE(sizeof(*conf
));
794 /* Make sure mbz_itemsize <= sizeof reqpkt.data */
795 if (sizeof(*conf
) > sizeof(reqpkt
.data
)) {
797 "Bletch: conf_peer is too big for reqpkt.data!");
800 memcpy(reqpkt
.data
, conf
, sizeof(*conf
));
802 if (sys_authenticate
&& req_hashlen
> 16) {
804 /* 32-bit alignment */
805 pch
+= (sizeof(*conf
) + 3) & ~3;
807 pkeyid
= (void *)(pts
+ 1);
808 pchEnd
= (void *)pkeyid
;
809 req_len
= pchEnd
- (char *)&reqpkt
;
810 pchEnd
= (void *)(pkeyid
+ 1);
811 pchEnd
+= req_hashlen
;
812 total_len
= pchEnd
- (char *)&reqpkt
;
813 if (total_len
> sizeof(reqpkt
)) {
815 "intres total_len %u limit is %u (%u octet digest)\n",
816 total_len
, sizeof(reqpkt
),
821 pts
= &reqpkt
.tstamp
;
822 pkeyid
= &reqpkt
.keyid
;
823 req_len
= REQ_LEN_NOMAC
;
826 *pkeyid
= htonl(req_keyid
);
828 L_ADDUF(&ts
, SKEWTIME
);
830 if (sys_authenticate
) {
831 n
= authencrypt(req_keyid
, (void *)&reqpkt
, req_len
);
832 if ((size_t)n
!= req_hashlen
+ sizeof(reqpkt
.keyid
)) {
834 "intres maclen %d expected %u\n",
835 n
, req_hashlen
+ sizeof(reqpkt
.keyid
));
845 n
= send(sockfd
, (char *)&reqpkt
, req_len
, 0);
847 msyslog(LOG_ERR
, "send to NTP server failed: %m");
848 return 0; /* maybe should exit */
851 /* In the NT world, documentation seems to indicate that there
852 * exist _write and _read routines that can be used to do blocking
853 * I/O on sockets. Problem is these routines require a socket
854 * handle obtained through the _open_osf_handle C run-time API
855 * of which there is no explanation in the documentation. We need
856 * nonblocking write's and read's anyway for our purpose here.
857 * We're therefore forced to deviate a little bit from the Unix
858 * model here and use the ReadFile and WriteFile Win32 I/O API's
861 overlap
.Offset
= overlap
.OffsetHigh
= (DWORD
)0;
862 overlap
.hEvent
= hReadWriteEvent
;
863 ret
= WriteFile((HANDLE
)sockfd
, (char *)&reqpkt
, req_len
,
864 NULL
, (LPOVERLAPPED
)&overlap
);
865 if ((ret
== FALSE
) && (GetLastError() != ERROR_IO_PENDING
)) {
866 msyslog(LOG_ERR
, "send to NTP server failed: %m");
869 dwWait
= WaitForSingleObject(hReadWriteEvent
, (DWORD
) TIMEOUT_SEC
* 1000);
870 if ((dwWait
== WAIT_FAILED
) || (dwWait
== WAIT_TIMEOUT
)) {
871 if (dwWait
== WAIT_FAILED
)
872 msyslog(LOG_ERR
, "WaitForSingleObject failed: %m");
875 if (!GetOverlappedResult((HANDLE
)sockfd
, (LPOVERLAPPED
)&overlap
,
876 (LPDWORD
)&NumberOfBytesWritten
, FALSE
)) {
877 msyslog(LOG_ERR
, "GetOverlappedResult for WriteFile fails: %m");
880 #endif /* SYS_WINNT */
884 * Wait for a response. A weakness of the mode 7 protocol used
885 * is that there is no way to associate a response with a
886 * particular request, i.e. the response to this configuration
887 * request is indistinguishable from that to any other. I should
888 * fix this some day. In any event, the time out is fairly
889 * pessimistic to make sure that if an answer is coming back
894 FD_SET(sockfd
, &fdset
);
895 tvout
.tv_sec
= TIMEOUT_SEC
;
896 tvout
.tv_usec
= TIMEOUT_USEC
;
898 n
= select(sockfd
+ 1, &fdset
, (fd_set
*)0,
899 (fd_set
*)0, &tvout
);
903 msyslog(LOG_ERR
, "select() fails: %m");
908 msyslog(LOG_INFO
, "ntp_intres select() returned 0.");
914 n
= recv(sockfd
, (char *)&reqpkt
, sizeof(reqpkt
), 0);
917 msyslog(LOG_ERR
, "recv() fails: %m");
922 #else /* Overlapped I/O used on non-blocking sockets on Windows NT */
923 ret
= ReadFile((HANDLE
)sockfd
, (char *)&reqpkt
, sizeof(reqpkt
),
924 NULL
, (LPOVERLAPPED
)&overlap
);
925 if ((ret
== FALSE
) && (GetLastError() != ERROR_IO_PENDING
)) {
926 msyslog(LOG_ERR
, "ReadFile() fails: %m");
929 dwWait
= WaitForSingleObject(hReadWriteEvent
, (DWORD
) TIMEOUT_SEC
* 1000);
930 if ((dwWait
== WAIT_FAILED
) || (dwWait
== WAIT_TIMEOUT
)) {
931 if (dwWait
== WAIT_FAILED
) {
932 msyslog(LOG_ERR
, "WaitForSingleObject for ReadFile fails: %m");
937 if (!GetOverlappedResult((HANDLE
)sockfd
, (LPOVERLAPPED
)&overlap
,
938 (LPDWORD
)&NumberOfBytesRead
, FALSE
)) {
939 msyslog(LOG_ERR
, "GetOverlappedResult fails: %m");
942 n
= NumberOfBytesRead
;
943 #endif /* SYS_WINNT */
946 * Got one. Check through to make sure it is what
949 if (n
< RESP_HEADER_SIZE
) {
950 msyslog(LOG_ERR
, "received runt response (%d octets)",
955 if (!ISRESPONSE(reqpkt
.rm_vn_mode
)) {
958 msyslog(LOG_INFO
, "received non-response packet");
963 if (ISMORE(reqpkt
.rm_vn_mode
)) {
966 msyslog(LOG_INFO
, "received fragmented packet");
971 if ( ( (INFO_VERSION(reqpkt
.rm_vn_mode
) < 2)
972 || (INFO_VERSION(reqpkt
.rm_vn_mode
) > NTP_VERSION
))
973 || INFO_MODE(reqpkt
.rm_vn_mode
) != MODE_PRIVATE
) {
977 "version (%d/%d) or mode (%d/%d) incorrect",
978 INFO_VERSION(reqpkt
.rm_vn_mode
),
980 INFO_MODE(reqpkt
.rm_vn_mode
),
986 if (INFO_SEQ(reqpkt
.auth_seq
) != 0) {
990 "nonzero sequence number (%d)",
991 INFO_SEQ(reqpkt
.auth_seq
));
996 if (reqpkt
.implementation
!= IMPL_XNTPD
||
997 reqpkt
.request
!= REQ_CONFIG
) {
1001 "implementation (%d) or request (%d) incorrect",
1002 reqpkt
.implementation
, reqpkt
.request
);
1007 if (INFO_NITEMS(reqpkt
.err_nitems
) != 0 ||
1008 INFO_MBZ(reqpkt
.mbz_itemsize
) != 0 ||
1009 INFO_ITEMSIZE(reqpkt
.mbz_itemsize
) != 0) {
1013 "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
1014 INFO_NITEMS(reqpkt
.err_nitems
),
1015 INFO_MBZ(reqpkt
.mbz_itemsize
),
1016 INFO_ITEMSIZE(reqpkt
.mbz_itemsize
));
1021 n
= INFO_ERR(reqpkt
.err_nitems
);
1027 case INFO_ERR_NODATA
:
1029 * newpeer() refused duplicate association, no
1030 * point in retrying so call it success.
1036 "ntp_intres.request: implementation mismatch");
1041 "ntp_intres.request: request unknown");
1046 "ntp_intres.request: format error");
1051 "ntp_intres.request: permission denied");
1056 "ntp_intres.request: unknown error code %d", n
);
1064 * nexttoken - return the next token from a line
1072 register char *tstart
;
1077 * Skip leading white space
1079 while (*cp
== ' ' || *cp
== '\t')
1083 * If this is the end of the line, return nothing.
1085 if (*cp
== '\n' || *cp
== '\0') {
1091 * Must be the start of a token. Record the pointer and look
1095 while (*cp
!= ' ' && *cp
!= '\t' && *cp
!= '\n' && *cp
!= '\0')
1099 * Terminate the token with a \0. If this isn't the end of the
1100 * line, space to the next character.
1102 if (*cp
== '\n' || *cp
== '\0')
1113 * readconf - read the configuration information out of the file we
1114 * were passed. Note that since the file is supposed to be
1115 * machine generated, we bail out at the first sign of trouble.
1124 char *token
[NUMTOK
];
1125 u_long intval
[NUMTOK
];
1127 char buf
[MAXLINESIZE
];
1130 while (fgets(buf
, MAXLINESIZE
, fp
) != NULL
) {
1133 for (i
= 0; i
< NUMTOK
; i
++) {
1134 if ((token
[i
] = nexttoken(&bp
)) == NULL
) {
1136 "tokenizing error in file `%s', quitting",
1142 for (i
= 1; i
< NUMTOK
- 1; i
++) {
1143 if (!atouint(token
[i
], &intval
[i
])) {
1145 "format error for integer token `%s', file `%s', quitting",
1151 #if 0 /* paranoid checking - these are done in newpeer() */
1152 if (intval
[TOK_HMODE
] != MODE_ACTIVE
&&
1153 intval
[TOK_HMODE
] != MODE_CLIENT
&&
1154 intval
[TOK_HMODE
] != MODE_BROADCAST
) {
1155 msyslog(LOG_ERR
, "invalid mode (%ld) in file %s",
1156 intval
[TOK_HMODE
], name
);
1160 if (intval
[TOK_VERSION
] > NTP_VERSION
||
1161 intval
[TOK_VERSION
] < NTP_OLDVERSION
) {
1162 msyslog(LOG_ERR
, "invalid version (%ld) in file %s",
1163 intval
[TOK_VERSION
], name
);
1166 if (intval
[TOK_MINPOLL
] < ntp_minpoll
||
1167 intval
[TOK_MINPOLL
] > NTP_MAXPOLL
) {
1169 msyslog(LOG_ERR
, "invalid MINPOLL value (%ld) in file %s",
1170 intval
[TOK_MINPOLL
], name
);
1174 if (intval
[TOK_MAXPOLL
] < ntp_minpoll
||
1175 intval
[TOK_MAXPOLL
] > NTP_MAXPOLL
) {
1176 msyslog(LOG_ERR
, "invalid MAXPOLL value (%ld) in file %s",
1177 intval
[TOK_MAXPOLL
], name
);
1181 if ((intval
[TOK_FLAGS
] & ~(FLAG_PREFER
| FLAG_NOSELECT
|
1182 FLAG_BURST
| FLAG_IBURST
| FLAG_SKEY
)) != 0) {
1183 msyslog(LOG_ERR
, "invalid flags (%ld) in file %s",
1184 intval
[TOK_FLAGS
], name
);
1187 #endif /* end paranoid checking */
1190 if (intval
[TOK_FLAGS
] & FLAG_PREFER
)
1191 flags
|= CONF_FLAG_PREFER
;
1192 if (intval
[TOK_FLAGS
] & FLAG_NOSELECT
)
1193 flags
|= CONF_FLAG_NOSELECT
;
1194 if (intval
[TOK_FLAGS
] & FLAG_BURST
)
1195 flags
|= CONF_FLAG_BURST
;
1196 if (intval
[TOK_FLAGS
] & FLAG_IBURST
)
1197 flags
|= CONF_FLAG_IBURST
;
1200 if (intval
[TOK_FLAGS
] & FLAG_SKEY
)
1201 flags
|= CONF_FLAG_SKEY
;
1202 #endif /* OPENSSL */
1205 * This is as good as we can check it. Add it in.
1207 addentry(token
[TOK_HOSTNAME
],
1208 (int)intval
[TOK_NEEDED
], (int)intval
[TOK_TYPE
],
1209 (int)intval
[TOK_HMODE
], (int)intval
[TOK_VERSION
],
1210 (int)intval
[TOK_MINPOLL
], (int)intval
[TOK_MAXPOLL
],
1211 flags
, (int)intval
[TOK_TTL
],
1212 intval
[TOK_KEYID
], token
[TOK_KEYSTR
]);
1218 * doconfigure - attempt to resolve names and configure the server
1225 register struct conf_entry
*ce
;
1229 msyslog(LOG_INFO
, "Running doconfigure %s DNS",
1230 dores
? "with" : "without" );
1233 #if defined(HAVE_RES_INIT) || defined(HAVE___RES_INIT)
1234 if (dores
) /* Reload /etc/resolv.conf - bug 1226 */
1238 while (ce
!= NULL
) {
1242 "doconfigure: <%s> has peeraddr %s",
1243 ce
->ce_name
, stoa(&ce
->peer_store
));
1245 if (dores
&& SOCK_UNSPEC(&ce
->peer_store
)) {
1246 if (!findhostaddr(ce
)) {
1247 #ifndef IGNORE_DNS_ERRORS
1249 "couldn't resolve `%s', giving up on it",
1251 ce
= removeentry(ce
);
1254 } else if (!SOCK_UNSPEC(&ce
->peer_store
))
1256 "DNS %s -> %s", ce
->ce_name
,
1257 stoa(&ce
->peer_store
));
1260 if (!SOCK_UNSPEC(&ce
->peer_store
)) {
1261 if (request(&ce
->ce_config
)) {
1262 ce
= removeentry(ce
);
1266 * Failed case. Should bump counter and give
1272 "doconfigure: request() FAILED, maybe next time.");
1280 #else /* NO_INTRES follows */
1281 int ntp_intres_nonempty_compilation_unit
;