1 /* $NetBSD: ntp_intres.c,v 1.9 2008/08/23 09:10:31 kardel Exp $ */
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"
32 /* Don't include ISC's version of IPv6 variables and structures */
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
44 #ifdef HAVE_SYS_PARAM_H
45 # include <sys/param.h> /* MAXHOSTNAMELEN (often) */
49 #include <isc/result.h>
51 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
54 * Each item we are to resolve and configure gets one of these
55 * structures defined for it.
58 struct conf_entry
*ce_next
;
59 char *ce_name
; /* name we are trying to resolve */
60 struct conf_peer ce_config
; /* configuration info for peer */
61 struct sockaddr_storage peer_store
; /* address info for both fams */
63 #define ce_peeraddr ce_config.peeraddr
64 #define ce_peeraddr6 ce_config.peeraddr6
65 #define ce_hmode ce_config.hmode
66 #define ce_version ce_config.version
67 #define ce_minpoll ce_config.minpoll
68 #define ce_maxpoll ce_config.maxpoll
69 #define ce_flags ce_config.flags
70 #define ce_ttl ce_config.ttl
71 #define ce_keyid ce_config.keyid
72 #define ce_keystr ce_config.keystr
75 * confentries is a pointer to the list of configuration entries
78 static struct conf_entry
*confentries
= NULL
;
81 * We take an interrupt every thirty seconds, at which time we decrement
82 * config_timer and resolve_timer. The former is set to 2, so we retry
83 * unsucessful reconfigurations every minute. The latter is set to
84 * an exponentially increasing value which starts at 2 and increases to
85 * 32. When this expires we retry failed name resolutions.
87 * We sleep SLEEPTIME seconds before doing anything, to give the server
88 * time to arrange itself.
96 static volatile int config_timer
= 0;
97 static volatile int resolve_timer
= 0;
99 static int resolve_value
; /* next value of resolve timer */
104 #define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */
105 #define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
108 * Select time out. Set to 2 seconds. The server is on the local machine,
111 #define TIMEOUT_SEC 2
112 #define TIMEOUT_USEC 0
116 * Input processing. The data on each line in the configuration file
117 * is supposed to consist of entries in the following order
119 #define TOK_HOSTNAME 0
121 #define TOK_VERSION 2
122 #define TOK_MINPOLL 3
123 #define TOK_MAXPOLL 4
130 #define MAXLINESIZE 512
134 * File descriptor for ntp request code.
136 static SOCKET sockfd
= INVALID_SOCKET
; /* NT uses SOCKET */
138 /* stuff to be filled in by caller */
140 keyid_t req_keyid
; /* request keyid */
141 char *req_file
; /* name of the file with configuration info */
143 /* end stuff to be filled in */
146 static void checkparent
P((void));
147 static void removeentry
P((struct conf_entry
*));
148 static void addentry
P((char *, int, int, int, int, u_int
,
149 int, keyid_t
, char *));
150 static int findhostaddr
P((struct conf_entry
*));
151 static void openntp
P((void));
152 static int request
P((struct conf_peer
*));
153 static char * nexttoken
P((char **));
154 static void readconf
P((FILE *, char *));
155 static void doconfigure
P((int));
157 struct ntp_res_t_pkt
{ /* Tagged packet: */
158 void *tag
; /* For the caller */
159 u_int32 paddr
; /* IP to look up, or 0 */
160 char name
[MAXHOSTNAMELEN
]; /* Name to look up (if 1st byte is not 0) */
163 struct ntp_res_c_pkt
{ /* Control packet: */
164 char name
[MAXHOSTNAMELEN
];
173 u_char keystr
[MAXFILENAME
];
177 static void resolver_exit
P((int));
180 * Call here instead of just exiting
183 static void resolver_exit (int code
)
186 CloseHandle(ResolverEventHandle
);
187 ResolverEventHandle
= NULL
;
188 ExitThread(code
); /* Just to kill the thread not the process */
190 exit(code
); /* kill the forked process */
195 * ntp_res_recv: Process an answer from the resolver
202 We have data ready on our descriptor.
203 It may be an EOF, meaning the resolver process went away.
204 Otherwise, it will be an "answer".
212 * req_key(???), req_keyid, req_file valid
230 msyslog(LOG_INFO
, "NTP_INTRES running");
234 /* check out auth stuff */
235 if (sys_authenticate
) {
236 if (!authistrusted(req_keyid
)) {
237 msyslog(LOG_ERR
, "invalid request keyid %08x",
244 * Read the configuration info
245 * {this is bogus, since we are forked, but it is easier
246 * to keep this code - gdt}
248 if ((in
= fopen(req_file
, "r")) == NULL
) {
249 msyslog(LOG_ERR
, "can't open configuration file %s: %m",
253 readconf(in
, req_file
);
259 (void) unlink(req_file
);
262 * Set up the timers to do first shot immediately.
265 resolve_value
= MINRESOLVE
;
266 config_timer
= CONFIG_TIME
;
271 if (resolve_timer
== 0) {
273 * Sleep a little to make sure the network is completely up
278 /* prepare retry, in case there's more work to do */
279 resolve_timer
= resolve_value
;
282 msyslog(LOG_INFO
, "resolve_timer: 0->%d", resolve_timer
);
284 if (resolve_value
< MAXRESOLVE
)
287 config_timer
= CONFIG_TIME
;
288 } else if (config_timer
== 0) { /* MB: in which case would this be required ? */
290 /* MB: should we check now if we could exit, similar to the code above? */
291 config_timer
= CONFIG_TIME
;
294 msyslog(LOG_INFO
, "config_timer: 0->%d", config_timer
);
298 if (confentries
== NULL
)
299 resolver_exit(0); /* done */
302 rc
= WaitForSingleObject(ResolverEventHandle
, 1000 * ALARM_TIME
); /* in milliseconds */
304 if ( rc
== WAIT_OBJECT_0
) { /* signaled by the main thread */
305 resolve_timer
= 0; /* retry resolving immediately */
309 if ( rc
!= WAIT_TIMEOUT
) /* not timeout: error */
312 #else /* not SYS_WINNT */
313 tv
.tv_sec
= ALARM_TIME
;
316 FD_SET(resolver_pipe_fd
[0], &fdset
);
317 rc
= select(resolver_pipe_fd
[0] + 1, &fdset
, (fd_set
*)0, (fd_set
*)0, &tv
);
319 if (rc
> 0) { /* parent process has written to the pipe */
320 read(resolver_pipe_fd
[0], (char *)&rc
, sizeof(rc
)); /* make pipe empty */
321 resolve_timer
= 0; /* retry resolving immediately */
325 if ( rc
< 0 ) /* select() returned error */
329 /* normal timeout, keep on waiting */
330 if (config_timer
> 0)
332 if (resolve_timer
> 0)
340 * checkparent - see if our parent process is still running
342 * No need to worry in the Windows NT environment whether the
343 * main thread is still running, because if it goes
344 * down it takes the whole process down with it (in
345 * which case we won't be running this thread either)
346 * Turn function into NOP;
352 #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
355 * If our parent (the server) has died we will have been
356 * inherited by init. If so, exit.
358 if (getppid() == 1) {
359 msyslog(LOG_INFO
, "parent died before we finished, exiting");
362 #endif /* SYS_WINNT && SYS_VXWORKS*/
368 * removeentry - we are done with an entry, remove it from the list
372 struct conf_entry
*entry
375 register struct conf_entry
*ce
;
379 confentries
= ce
->ce_next
;
384 if (ce
->ce_next
== entry
) {
385 ce
->ce_next
= entry
->ce_next
;
394 * addentry - add an entry to the configuration list
410 register struct conf_entry
*ce
;
416 "intres: <%s> %d %d %d %d %x %d %x %s\n", name
,
417 mode
, version
, minpoll
, maxpoll
, flags
, ttl
, keyid
,
420 len
= strlen(name
) + 1;
421 cp
= (char *)emalloc(len
);
422 memmove(cp
, name
, len
);
424 ce
= (struct conf_entry
*)emalloc(sizeof(struct conf_entry
));
427 #ifdef ISC_PLATFORM_HAVEIPV6
428 ce
->ce_peeraddr6
= in6addr_any
;
430 ANYSOCK(&ce
->peer_store
);
431 ce
->ce_hmode
= (u_char
)mode
;
432 ce
->ce_version
= (u_char
)version
;
433 ce
->ce_minpoll
= (u_char
)minpoll
;
434 ce
->ce_maxpoll
= (u_char
)maxpoll
;
435 ce
->ce_flags
= (u_char
)flags
;
436 ce
->ce_ttl
= (u_char
)ttl
;
437 ce
->ce_keyid
= keyid
;
438 strncpy((char *)ce
->ce_keystr
, keystr
, MAXFILENAME
);
441 if (confentries
== NULL
) {
444 register struct conf_entry
*cep
;
446 for (cep
= confentries
; cep
->ce_next
!= NULL
;
455 * findhostaddr - resolve a host name into an address (Or vice-versa)
457 * Given one of {ce_peeraddr,ce_name}, find the other one.
458 * It returns 1 for "success" and 0 for an uncorrectable failure.
459 * Note that "success" includes try again errors. You can tell that you
460 * got a "try again" since {ce_peeraddr,ce_name} will still be zero.
464 struct conf_entry
*entry
467 static int eai_again_seen
= 0;
468 struct addrinfo
*addr
;
469 struct addrinfo hints
;
473 checkparent(); /* make sure our guy is still running */
475 if (entry
->ce_name
!= NULL
&& !SOCKNUL(&entry
->peer_store
)) {
477 msyslog(LOG_ERR
, "findhostaddr: both ce_name and ce_peeraddr are defined...");
481 if (entry
->ce_name
== NULL
&& SOCKNUL(&entry
->peer_store
)) {
482 msyslog(LOG_ERR
, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
486 if (entry
->ce_name
) {
487 DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
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
);
500 entry
->peer_store
= *((struct sockaddr_storage
*)(addr
->ai_addr
));
501 if (entry
->peer_store
.ss_family
== AF_INET
) {
503 GET_INADDR(entry
->peer_store
);
504 entry
->ce_config
.v6_flag
= 0;
506 entry
->ce_peeraddr6
=
507 GET_INADDR6(entry
->peer_store
);
508 entry
->ce_config
.v6_flag
= 1;
512 DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
513 stoa(&entry
->peer_store
)));
515 entry
->ce_name
= emalloc(MAXHOSTNAMELEN
);
516 error
= getnameinfo((const struct sockaddr
*)&entry
->peer_store
,
517 SOCKLEN(&entry
->peer_store
),
518 (char *)&entry
->ce_name
, MAXHOSTNAMELEN
,
524 /* again is our return value, for success it is 1 */
527 DPRINTF(2, ("findhostaddr: %s resolved.\n",
528 (entry
->ce_name
) ? "name" : "address"));
531 * If the resolver failed, see if the failure is
532 * temporary. If so, return success.
548 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
551 msyslog(LOG_ERR
, "host name not found%s%s: %s",
552 (EAI_NONAME
== error
) ? "" : " EAI_NODATA",
553 (eai_again_seen
) ? " (permanent)" : "",
555 again
= !eai_again_seen
;
561 * EAI_SYSTEM means the real error is in errno. We should be more
562 * discriminating about which errno values require retrying, but
563 * this matches existing behavior.
566 DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
567 errno
, strerror(errno
)));
572 /* do this here to avoid perturbing errno earlier */
573 DPRINTF(2, ("intres: got error status of: %d\n", error
));
581 * openntp - open a socket to the ntp server
586 const char *localhost
= "127.0.0.1"; /* Use IPv4 loopback */
587 struct addrinfo hints
;
588 struct addrinfo
*addr
;
592 if (sockfd
!= INVALID_SOCKET
)
595 memset(&hints
, 0, sizeof(hints
));
598 * For now only bother with IPv4
600 hints
.ai_family
= AF_INET
;
601 hints
.ai_socktype
= SOCK_DGRAM
;
603 err
= getaddrinfo(localhost
, "ntp", &hints
, &addr
);
607 if (EAI_SYSTEM
== err
)
608 msyslog(LOG_ERR
, "getaddrinfo(%s) failed: %m",
612 msyslog(LOG_ERR
, "getaddrinfo(%s) failed: %s",
613 localhost
, gai_strerror(err
));
617 sockfd
= socket(addr
->ai_family
, addr
->ai_socktype
, 0);
619 if (INVALID_SOCKET
== sockfd
) {
620 msyslog(LOG_ERR
, "socket() failed: %m");
626 * On Windows only the count of sockets must be less than
627 * FD_SETSIZE. On Unix each descriptor's value must be less
628 * than FD_SETSIZE, as fd_set is a bit array.
630 if (sockfd
>= FD_SETSIZE
) {
631 msyslog(LOG_ERR
, "socket fd %d too large, FD_SETSIZE %d",
632 (int)sockfd
, FD_SETSIZE
);
637 * Make the socket non-blocking. We'll wait with select()
638 * Unix: fcntl(O_NONBLOCK) or fcntl(FNDELAY)
641 if (fcntl(sockfd
, F_SETFL
, O_NONBLOCK
) == -1) {
642 msyslog(LOG_ERR
, "fcntl(O_NONBLOCK) failed: %m");
647 if (fcntl(sockfd
, F_SETFL
, FNDELAY
) == -1) {
648 msyslog(LOG_ERR
, "fcntl(FNDELAY) failed: %m");
652 # include "Bletch: NEED NON BLOCKING IO"
653 # endif /* FNDDELAY */
654 # endif /* O_NONBLOCK */
655 (void)on
; /* quiet unused warning */
656 #else /* !SYS_WINNT above */
658 * Make the socket non-blocking. We'll wait with select()
659 * Windows: ioctlsocket(FIONBIO)
662 err
= ioctlsocket(sockfd
, FIONBIO
, &on
);
663 if (SOCKET_ERROR
== err
) {
664 msyslog(LOG_ERR
, "ioctlsocket(FIONBIO) fails: %m");
667 #endif /* SYS_WINNT */
669 err
= connect(sockfd
, addr
->ai_addr
, addr
->ai_addrlen
);
670 if (SOCKET_ERROR
== err
) {
671 msyslog(LOG_ERR
, "openntp: connect() failed: %m");
680 * request - send a configuration request to the server, wait for a response
684 struct conf_peer
*conf
688 struct timeval tvout
;
689 struct req_pkt reqpkt
;
693 HANDLE hReadWriteEvent
= NULL
;
695 DWORD NumberOfBytesWritten
, NumberOfBytesRead
, dwWait
;
697 #endif /* SYS_WINNT */
699 checkparent(); /* make sure our guy is still running */
701 if (sockfd
== INVALID_SOCKET
)
705 hReadWriteEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
706 #endif /* SYS_WINNT */
709 * Try to clear out any previously received traffic so it
710 * doesn't fool us. Note the socket is nonblocking.
715 FD_SET(sockfd
, &fdset
);
716 while (select(sockfd
+ 1, &fdset
, (fd_set
*)0, (fd_set
*)0, &tvout
) >
718 recv(sockfd
, (char *)&reqpkt
, REQ_LEN_MAC
, 0);
720 FD_SET(sockfd
, &fdset
);
724 * Make up a request packet with the configuration info
726 memset((char *)&reqpkt
, 0, sizeof(reqpkt
));
728 reqpkt
.rm_vn_mode
= RM_VN_MODE(0, 0, 0);
729 reqpkt
.auth_seq
= AUTH_SEQ(1, 0); /* authenticated, no seq */
730 reqpkt
.implementation
= IMPL_XNTPD
; /* local implementation */
731 reqpkt
.request
= REQ_CONFIG
; /* configure a new peer */
732 reqpkt
.err_nitems
= ERR_NITEMS(0, 1); /* one item */
733 reqpkt
.mbz_itemsize
= MBZ_ITEMSIZE(sizeof(struct conf_peer
));
734 /* Make sure mbz_itemsize <= sizeof reqpkt.data */
735 if (sizeof(struct conf_peer
) > sizeof (reqpkt
.data
)) {
736 msyslog(LOG_ERR
, "Bletch: conf_peer is too big for reqpkt.data!");
739 memmove(reqpkt
.data
, (char *)conf
, sizeof(struct conf_peer
));
740 reqpkt
.keyid
= htonl(req_keyid
);
743 L_ADDUF(&ts
, SKEWTIME
);
744 HTONL_FP(&ts
, &reqpkt
.tstamp
);
746 if (sys_authenticate
)
747 n
= authencrypt(req_keyid
, (u_int32
*)&reqpkt
, REQ_LEN_NOMAC
);
753 n
= send(sockfd
, (char *)&reqpkt
, (unsigned)(REQ_LEN_NOMAC
+ n
), 0);
755 msyslog(LOG_ERR
, "send to NTP server failed: %m");
756 return 0; /* maybe should exit */
759 /* In the NT world, documentation seems to indicate that there
760 * exist _write and _read routines that can be used to do blocking
761 * I/O on sockets. Problem is these routines require a socket
762 * handle obtained through the _open_osf_handle C run-time API
763 * of which there is no explanation in the documentation. We need
764 * nonblocking write's and read's anyway for our purpose here.
765 * We're therefore forced to deviate a little bit from the Unix
766 * model here and use the ReadFile and WriteFile Win32 I/O API's
769 overlap
.Offset
= overlap
.OffsetHigh
= (DWORD
)0;
770 overlap
.hEvent
= hReadWriteEvent
;
771 ret
= WriteFile((HANDLE
)sockfd
, (char *)&reqpkt
, REQ_LEN_NOMAC
+ n
,
772 NULL
, (LPOVERLAPPED
)&overlap
);
773 if ((ret
== FALSE
) && (GetLastError() != ERROR_IO_PENDING
)) {
774 msyslog(LOG_ERR
, "send to NTP server failed: %m");
777 dwWait
= WaitForSingleObject(hReadWriteEvent
, (DWORD
) TIMEOUT_SEC
* 1000);
778 if ((dwWait
== WAIT_FAILED
) || (dwWait
== WAIT_TIMEOUT
)) {
779 if (dwWait
== WAIT_FAILED
)
780 msyslog(LOG_ERR
, "WaitForSingleObject failed: %m");
783 if (!GetOverlappedResult((HANDLE
)sockfd
, (LPOVERLAPPED
)&overlap
,
784 (LPDWORD
)&NumberOfBytesWritten
, FALSE
)) {
785 msyslog(LOG_ERR
, "GetOverlappedResult for WriteFile fails: %m");
788 #endif /* SYS_WINNT */
792 * Wait for a response. A weakness of the mode 7 protocol used
793 * is that there is no way to associate a response with a
794 * particular request, i.e. the response to this configuration
795 * request is indistinguishable from that to any other. I should
796 * fix this some day. In any event, the time out is fairly
797 * pessimistic to make sure that if an answer is coming back
802 FD_SET(sockfd
, &fdset
);
803 tvout
.tv_sec
= TIMEOUT_SEC
;
804 tvout
.tv_usec
= TIMEOUT_USEC
;
806 n
= select(sockfd
+ 1, &fdset
, (fd_set
*)0,
807 (fd_set
*)0, &tvout
);
812 msyslog(LOG_ERR
, "select() fails: %m");
819 msyslog(LOG_INFO
, "select() returned 0.");
825 n
= recv(sockfd
, (char *)&reqpkt
, REQ_LEN_MAC
, 0);
828 msyslog(LOG_ERR
, "recv() fails: %m");
833 #else /* Overlapped I/O used on non-blocking sockets on Windows NT */
834 ret
= ReadFile((HANDLE
)sockfd
, (char *)&reqpkt
, (DWORD
)REQ_LEN_MAC
,
835 NULL
, (LPOVERLAPPED
)&overlap
);
836 if ((ret
== FALSE
) && (GetLastError() != ERROR_IO_PENDING
)) {
837 msyslog(LOG_ERR
, "ReadFile() fails: %m");
840 dwWait
= WaitForSingleObject(hReadWriteEvent
, (DWORD
) TIMEOUT_SEC
* 1000);
841 if ((dwWait
== WAIT_FAILED
) || (dwWait
== WAIT_TIMEOUT
)) {
842 if (dwWait
== WAIT_FAILED
) {
843 msyslog(LOG_ERR
, "WaitForSingleObject for ReadFile fails: %m");
848 if (!GetOverlappedResult((HANDLE
)sockfd
, (LPOVERLAPPED
)&overlap
,
849 (LPDWORD
)&NumberOfBytesRead
, FALSE
)) {
850 msyslog(LOG_ERR
, "GetOverlappedResult fails: %m");
853 n
= NumberOfBytesRead
;
854 #endif /* SYS_WINNT */
857 * Got one. Check through to make sure it is what
860 if (n
< RESP_HEADER_SIZE
) {
861 msyslog(LOG_ERR
, "received runt response (%d octets)",
866 if (!ISRESPONSE(reqpkt
.rm_vn_mode
)) {
869 msyslog(LOG_INFO
, "received non-response packet");
874 if (ISMORE(reqpkt
.rm_vn_mode
)) {
877 msyslog(LOG_INFO
, "received fragmented packet");
882 if ( ( (INFO_VERSION(reqpkt
.rm_vn_mode
) < 2)
883 || (INFO_VERSION(reqpkt
.rm_vn_mode
) > NTP_VERSION
))
884 || INFO_MODE(reqpkt
.rm_vn_mode
) != MODE_PRIVATE
) {
888 "version (%d/%d) or mode (%d/%d) incorrect",
889 INFO_VERSION(reqpkt
.rm_vn_mode
),
891 INFO_MODE(reqpkt
.rm_vn_mode
),
897 if (INFO_SEQ(reqpkt
.auth_seq
) != 0) {
901 "nonzero sequence number (%d)",
902 INFO_SEQ(reqpkt
.auth_seq
));
907 if (reqpkt
.implementation
!= IMPL_XNTPD
||
908 reqpkt
.request
!= REQ_CONFIG
) {
912 "implementation (%d) or request (%d) incorrect",
913 reqpkt
.implementation
, reqpkt
.request
);
918 if (INFO_NITEMS(reqpkt
.err_nitems
) != 0 ||
919 INFO_MBZ(reqpkt
.mbz_itemsize
) != 0 ||
920 INFO_ITEMSIZE(reqpkt
.mbz_itemsize
) != 0) {
924 "nitems (%d) mbz (%d) or itemsize (%d) nonzero",
925 INFO_NITEMS(reqpkt
.err_nitems
),
926 INFO_MBZ(reqpkt
.mbz_itemsize
),
927 INFO_ITEMSIZE(reqpkt
.mbz_itemsize
));
932 n
= INFO_ERR(reqpkt
.err_nitems
);
940 "ntpd reports implementation mismatch!");
945 "ntpd says configuration request is unknown!");
950 "ntpd indicates a format error occurred!");
953 case INFO_ERR_NODATA
:
955 "ntpd indicates no data available!");
960 "ntpd returns a permission denied error!");
965 "ntpd returns unknown error code %d!", n
);
973 * nexttoken - return the next token from a line
981 register char *tstart
;
986 * Skip leading white space
988 while (*cp
== ' ' || *cp
== '\t')
992 * If this is the end of the line, return nothing.
994 if (*cp
== '\n' || *cp
== '\0') {
1000 * Must be the start of a token. Record the pointer and look
1004 while (*cp
!= ' ' && *cp
!= '\t' && *cp
!= '\n' && *cp
!= '\0')
1008 * Terminate the token with a \0. If this isn't the end of the
1009 * line, space to the next character.
1011 if (*cp
== '\n' || *cp
== '\0')
1022 * readconf - read the configuration information out of the file we
1023 * were passed. Note that since the file is supposed to be
1024 * machine generated, we bail out at the first sign of trouble.
1033 char *token
[NUMTOK
];
1034 u_long intval
[NUMTOK
];
1036 char buf
[MAXLINESIZE
];
1039 while (fgets(buf
, MAXLINESIZE
, fp
) != NULL
) {
1042 for (i
= 0; i
< NUMTOK
; i
++) {
1043 if ((token
[i
] = nexttoken(&bp
)) == NULL
) {
1045 "tokenizing error in file `%s', quitting",
1051 for (i
= 1; i
< NUMTOK
- 1; i
++) {
1052 if (!atouint(token
[i
], &intval
[i
])) {
1054 "format error for integer token `%s', file `%s', quitting",
1060 if (intval
[TOK_HMODE
] != MODE_ACTIVE
&&
1061 intval
[TOK_HMODE
] != MODE_CLIENT
&&
1062 intval
[TOK_HMODE
] != MODE_BROADCAST
) {
1063 msyslog(LOG_ERR
, "invalid mode (%ld) in file %s",
1064 intval
[TOK_HMODE
], name
);
1068 if (intval
[TOK_VERSION
] > NTP_VERSION
||
1069 intval
[TOK_VERSION
] < NTP_OLDVERSION
) {
1070 msyslog(LOG_ERR
, "invalid version (%ld) in file %s",
1071 intval
[TOK_VERSION
], name
);
1074 if (intval
[TOK_MINPOLL
] < NTP_MINPOLL
||
1075 intval
[TOK_MINPOLL
] > NTP_MAXPOLL
) {
1076 msyslog(LOG_ERR
, "invalid MINPOLL value (%ld) in file %s",
1077 intval
[TOK_MINPOLL
], name
);
1081 if (intval
[TOK_MAXPOLL
] < NTP_MINPOLL
||
1082 intval
[TOK_MAXPOLL
] > NTP_MAXPOLL
) {
1083 msyslog(LOG_ERR
, "invalid MAXPOLL value (%ld) in file %s",
1084 intval
[TOK_MAXPOLL
], name
);
1088 if ((intval
[TOK_FLAGS
] & ~(FLAG_AUTHENABLE
| FLAG_PREFER
|
1089 FLAG_NOSELECT
| FLAG_BURST
| FLAG_IBURST
| FLAG_SKEY
))
1091 msyslog(LOG_ERR
, "invalid flags (%ld) in file %s",
1092 intval
[TOK_FLAGS
], name
);
1097 if (intval
[TOK_FLAGS
] & FLAG_AUTHENABLE
)
1098 flags
|= CONF_FLAG_AUTHENABLE
;
1099 if (intval
[TOK_FLAGS
] & FLAG_PREFER
)
1100 flags
|= CONF_FLAG_PREFER
;
1101 if (intval
[TOK_FLAGS
] & FLAG_NOSELECT
)
1102 flags
|= CONF_FLAG_NOSELECT
;
1103 if (intval
[TOK_FLAGS
] & FLAG_BURST
)
1104 flags
|= CONF_FLAG_BURST
;
1105 if (intval
[TOK_FLAGS
] & FLAG_IBURST
)
1106 flags
|= CONF_FLAG_IBURST
;
1107 if (intval
[TOK_FLAGS
] & FLAG_SKEY
)
1108 flags
|= CONF_FLAG_SKEY
;
1111 * This is as good as we can check it. Add it in.
1113 addentry(token
[TOK_HOSTNAME
], (int)intval
[TOK_HMODE
],
1114 (int)intval
[TOK_VERSION
], (int)intval
[TOK_MINPOLL
],
1115 (int)intval
[TOK_MAXPOLL
], flags
, (int)intval
[TOK_TTL
],
1116 intval
[TOK_KEYID
], token
[TOK_KEYSTR
]);
1122 * doconfigure - attempt to resolve names and configure the server
1129 register struct conf_entry
*ce
;
1130 register struct conf_entry
*ceremove
;
1134 msyslog(LOG_INFO
, "Running doconfigure %s DNS",
1135 dores
? "with" : "without" );
1139 while (ce
!= NULL
) {
1143 "doconfigure: <%s> has peeraddr %s",
1144 ce
->ce_name
, stoa(&ce
->peer_store
));
1146 if (dores
&& SOCKNUL(&(ce
->peer_store
))) {
1147 if (!findhostaddr(ce
)) {
1148 #ifndef IGNORE_DNS_ERRORS
1150 "couldn't resolve `%s', giving up on it",
1153 ce
= ceremove
->ce_next
;
1154 removeentry(ceremove
);
1160 if (!SOCKNUL(&ce
->peer_store
)) {
1161 if (request(&ce
->ce_config
)) {
1163 ce
= ceremove
->ce_next
;
1164 removeentry(ceremove
);
1170 "doconfigure: request() FAILED, maybe next time.");