/contrib/ntp/ntpd/ntp_intres.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1185 lines · 819 code · 155 blank · 211 comment · 200 complexity · b9bdfd06a4e027139907039db0bc5926 MD5 · raw file

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