154359Sroberto/* 254359Sroberto * ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92 354359Sroberto * routine callable from ntpd, rather than separate program 454359Sroberto * also, key info passed in via a global, so no key file needed. 554359Sroberto */ 654359Sroberto 754359Sroberto/* 854359Sroberto * ntpres - process configuration entries which require use of the resolver 954359Sroberto * 1054359Sroberto * This is meant to be run by ntpd on the fly. It is not guaranteed 1154359Sroberto * to work properly if run by hand. This is actually a quick hack to 1254359Sroberto * stave off violence from people who hate using numbers in the 1354359Sroberto * configuration file (at least I hope the rest of the daemon is 1454359Sroberto * better than this). Also might provide some ideas about how one 1554359Sroberto * might go about autoconfiguring an NTP distribution network. 1654359Sroberto * 1754359Sroberto */ 1854359Sroberto 1954359Sroberto#ifdef HAVE_CONFIG_H 2054359Sroberto# include <config.h> 2154359Sroberto#endif 2254359Sroberto 23106163Sroberto#include "ntp_machine.h" 2454359Sroberto#include "ntpd.h" 2554359Sroberto#include "ntp_io.h" 2654359Sroberto#include "ntp_request.h" 2754359Sroberto#include "ntp_stdlib.h" 2854359Sroberto#include "ntp_syslog.h" 2954359Sroberto 3082498Sroberto#include <stdio.h> 3182498Sroberto#include <ctype.h> 32223667Sbz#include <resolv.h> 3382498Sroberto#include <signal.h> 3482498Sroberto 3582498Sroberto/**/ 3682498Sroberto#include <netinet/in.h> 3782498Sroberto#include <arpa/inet.h> 3882498Sroberto/**/ 3982498Sroberto#ifdef HAVE_SYS_PARAM_H 4082498Sroberto# include <sys/param.h> /* MAXHOSTNAMELEN (often) */ 4182498Sroberto#endif 4282498Sroberto 43182007Sroberto#include <isc/net.h> 44182007Sroberto#include <isc/result.h> 45182007Sroberto 4654359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 4754359Sroberto 4854359Sroberto/* 4954359Sroberto * Each item we are to resolve and configure gets one of these 5054359Sroberto * structures defined for it. 5154359Sroberto */ 5254359Srobertostruct conf_entry { 5354359Sroberto struct conf_entry *ce_next; 5454359Sroberto char *ce_name; /* name we are trying to resolve */ 5554359Sroberto struct conf_peer ce_config; /* configuration info for peer */ 56132451Sroberto struct sockaddr_storage peer_store; /* address info for both fams */ 5754359Sroberto}; 5854359Sroberto#define ce_peeraddr ce_config.peeraddr 59132451Sroberto#define ce_peeraddr6 ce_config.peeraddr6 6054359Sroberto#define ce_hmode ce_config.hmode 6154359Sroberto#define ce_version ce_config.version 6254359Sroberto#define ce_minpoll ce_config.minpoll 6354359Sroberto#define ce_maxpoll ce_config.maxpoll 6454359Sroberto#define ce_flags ce_config.flags 6554359Sroberto#define ce_ttl ce_config.ttl 6654359Sroberto#define ce_keyid ce_config.keyid 6782498Sroberto#define ce_keystr ce_config.keystr 6854359Sroberto 6954359Sroberto/* 7054359Sroberto * confentries is a pointer to the list of configuration entries 7154359Sroberto * we have left to do. 7254359Sroberto */ 7354359Srobertostatic struct conf_entry *confentries = NULL; 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * We take an interrupt every thirty seconds, at which time we decrement 7754359Sroberto * config_timer and resolve_timer. The former is set to 2, so we retry 7854359Sroberto * unsucessful reconfigurations every minute. The latter is set to 7954359Sroberto * an exponentially increasing value which starts at 2 and increases to 8054359Sroberto * 32. When this expires we retry failed name resolutions. 8154359Sroberto * 8254359Sroberto * We sleep SLEEPTIME seconds before doing anything, to give the server 8354359Sroberto * time to arrange itself. 8454359Sroberto */ 8554359Sroberto#define MINRESOLVE 2 8654359Sroberto#define MAXRESOLVE 32 8754359Sroberto#define CONFIG_TIME 2 8854359Sroberto#define ALARM_TIME 30 8954359Sroberto#define SLEEPTIME 2 9054359Sroberto 9154359Srobertostatic volatile int config_timer = 0; 9254359Srobertostatic volatile int resolve_timer = 0; 9354359Sroberto 9454359Srobertostatic int resolve_value; /* next value of resolve timer */ 9554359Sroberto 9654359Sroberto/* 9754359Sroberto * Big hack attack 9854359Sroberto */ 9954359Sroberto#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */ 10054359Sroberto#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */ 10154359Sroberto 10254359Sroberto/* 10354359Sroberto * Select time out. Set to 2 seconds. The server is on the local machine, 10454359Sroberto * after all. 10554359Sroberto */ 10654359Sroberto#define TIMEOUT_SEC 2 10754359Sroberto#define TIMEOUT_USEC 0 10854359Sroberto 10954359Sroberto 11054359Sroberto/* 11154359Sroberto * Input processing. The data on each line in the configuration file 11254359Sroberto * is supposed to consist of entries in the following order 11354359Sroberto */ 11454359Sroberto#define TOK_HOSTNAME 0 115223667Sbz#define TOK_PEERAF 1 116223667Sbz#define TOK_HMODE 2 117223667Sbz#define TOK_VERSION 3 118223667Sbz#define TOK_MINPOLL 4 119223667Sbz#define TOK_MAXPOLL 5 120223667Sbz#define TOK_FLAGS 6 121223667Sbz#define TOK_TTL 7 122223667Sbz#define TOK_KEYID 8 123223667Sbz#define TOK_KEYSTR 9 124223667Sbz#define NUMTOK 10 12554359Sroberto 12654359Sroberto#define MAXLINESIZE 512 12754359Sroberto 12854359Sroberto 12954359Sroberto/* 13054359Sroberto * File descriptor for ntp request code. 13154359Sroberto */ 132132451Srobertostatic SOCKET sockfd = INVALID_SOCKET; /* NT uses SOCKET */ 13354359Sroberto 13454359Sroberto/* stuff to be filled in by caller */ 13554359Sroberto 13682498Srobertokeyid_t req_keyid; /* request keyid */ 13754359Srobertochar *req_file; /* name of the file with configuration info */ 13854359Sroberto 13954359Sroberto/* end stuff to be filled in */ 14054359Sroberto 14154359Sroberto 14254359Srobertostatic void checkparent P((void)); 14354359Srobertostatic void removeentry P((struct conf_entry *)); 14482498Srobertostatic void addentry P((char *, int, int, int, int, u_int, 145223667Sbz int, keyid_t, char *, u_char)); 14654359Srobertostatic int findhostaddr P((struct conf_entry *)); 14754359Srobertostatic void openntp P((void)); 14854359Srobertostatic int request P((struct conf_peer *)); 14954359Srobertostatic char * nexttoken P((char **)); 15054359Srobertostatic void readconf P((FILE *, char *)); 15154359Srobertostatic void doconfigure P((int)); 15254359Sroberto 15382498Srobertostruct ntp_res_t_pkt { /* Tagged packet: */ 15482498Sroberto void *tag; /* For the caller */ 15582498Sroberto u_int32 paddr; /* IP to look up, or 0 */ 15682498Sroberto char name[MAXHOSTNAMELEN]; /* Name to look up (if 1st byte is not 0) */ 15782498Sroberto}; 15882498Sroberto 15982498Srobertostruct ntp_res_c_pkt { /* Control packet: */ 16082498Sroberto char name[MAXHOSTNAMELEN]; 16182498Sroberto u_int32 paddr; 16282498Sroberto int mode; 16382498Sroberto int version; 16482498Sroberto int minpoll; 16582498Sroberto int maxpoll; 16682498Sroberto u_int flags; 16782498Sroberto int ttl; 16882498Sroberto keyid_t keyid; 16982498Sroberto u_char keystr[MAXFILENAME]; 17082498Sroberto}; 17182498Sroberto 17282498Sroberto 173182007Srobertostatic void resolver_exit P((int)); 174182007Sroberto 17554359Sroberto/* 176182007Sroberto * Call here instead of just exiting 177182007Sroberto */ 178182007Sroberto 179182007Srobertostatic void resolver_exit (int code) 180182007Sroberto{ 181182007Sroberto#ifdef SYS_WINNT 182182007Sroberto CloseHandle(ResolverEventHandle); 183182007Sroberto ResolverEventHandle = NULL; 184182007Sroberto ExitThread(code); /* Just to kill the thread not the process */ 185182007Sroberto#else 186182007Sroberto exit(code); /* kill the forked process */ 187182007Sroberto#endif 188182007Sroberto} 189182007Sroberto 190182007Sroberto/* 19182498Sroberto * ntp_res_recv: Process an answer from the resolver 19254359Sroberto */ 19382498Sroberto 19454359Srobertovoid 19582498Srobertontp_res_recv(void) 19682498Sroberto{ 19782498Sroberto /* 19882498Sroberto We have data ready on our descriptor. 19982498Sroberto It may be an EOF, meaning the resolver process went away. 20082498Sroberto Otherwise, it will be an "answer". 20182498Sroberto */ 20282498Sroberto} 20382498Sroberto 20482498Sroberto 20582498Sroberto/* 20682498Sroberto * ntp_intres needs; 20782498Sroberto * 20882498Sroberto * req_key(???), req_keyid, req_file valid 20982498Sroberto * syslog still open 21082498Sroberto */ 21182498Sroberto 21282498Srobertovoid 21354359Srobertontp_intres(void) 21454359Sroberto{ 21554359Sroberto FILE *in; 216182007Sroberto struct timeval tv; 217182007Sroberto fd_set fdset; 218182007Sroberto#ifdef SYS_WINNT 219182007Sroberto DWORD rc; 220182007Sroberto#else 221182007Sroberto int rc; 222182007Sroberto#endif 22354359Sroberto 22454359Sroberto#ifdef DEBUG 22556746Sroberto if (debug > 1) { 22654359Sroberto msyslog(LOG_INFO, "NTP_INTRES running"); 22754359Sroberto } 22854359Sroberto#endif 22954359Sroberto 23054359Sroberto /* check out auth stuff */ 23154359Sroberto if (sys_authenticate) { 23254359Sroberto if (!authistrusted(req_keyid)) { 23382498Sroberto msyslog(LOG_ERR, "invalid request keyid %08x", 23454359Sroberto req_keyid ); 235182007Sroberto resolver_exit(1); 23654359Sroberto } 23754359Sroberto } 23854359Sroberto 23954359Sroberto /* 24054359Sroberto * Read the configuration info 24154359Sroberto * {this is bogus, since we are forked, but it is easier 24254359Sroberto * to keep this code - gdt} 24354359Sroberto */ 24454359Sroberto if ((in = fopen(req_file, "r")) == NULL) { 24554359Sroberto msyslog(LOG_ERR, "can't open configuration file %s: %m", 24654359Sroberto req_file); 247182007Sroberto resolver_exit(1); 24854359Sroberto } 24954359Sroberto readconf(in, req_file); 25054359Sroberto (void) fclose(in); 25154359Sroberto 252182007Sroberto#ifdef DEBUG 25354359Sroberto if (!debug ) 254182007Sroberto#endif 25582498Sroberto (void) unlink(req_file); 25654359Sroberto 25754359Sroberto /* 258182007Sroberto * Set up the timers to do first shot immediately. 25954359Sroberto */ 260182007Sroberto resolve_timer = 0; 261182007Sroberto resolve_value = MINRESOLVE; 26254359Sroberto config_timer = CONFIG_TIME; 26354359Sroberto 26454359Sroberto for (;;) { 26554359Sroberto checkparent(); 26654359Sroberto 26754359Sroberto if (resolve_timer == 0) { 268182007Sroberto /* 269182007Sroberto * Sleep a little to make sure the network is completely up 270182007Sroberto */ 271182007Sroberto sleep(SLEEPTIME); 272182007Sroberto doconfigure(1); 273182007Sroberto 274182007Sroberto /* prepare retry, in case there's more work to do */ 27554359Sroberto resolve_timer = resolve_value; 27654359Sroberto#ifdef DEBUG 27782498Sroberto if (debug > 2) 27882498Sroberto msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer); 27954359Sroberto#endif 280182007Sroberto if (resolve_value < MAXRESOLVE) 281182007Sroberto resolve_value <<= 1; 282182007Sroberto 28354359Sroberto config_timer = CONFIG_TIME; 284182007Sroberto } else if (config_timer == 0) { /* MB: in which case would this be required ? */ 285182007Sroberto doconfigure(0); 286182007Sroberto /* MB: should we check now if we could exit, similar to the code above? */ 28754359Sroberto config_timer = CONFIG_TIME; 28854359Sroberto#ifdef DEBUG 28982498Sroberto if (debug > 2) 29082498Sroberto msyslog(LOG_INFO, "config_timer: 0->%d", config_timer); 29154359Sroberto#endif 292182007Sroberto } 293182007Sroberto 294182007Sroberto if (confentries == NULL) 295182007Sroberto resolver_exit(0); /* done */ 296182007Sroberto 297182007Sroberto#ifdef SYS_WINNT 298182007Sroberto rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME); /* in milliseconds */ 299182007Sroberto 300182007Sroberto if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */ 301182007Sroberto resolve_timer = 0; /* retry resolving immediately */ 30254359Sroberto continue; 30354359Sroberto } 304182007Sroberto 305182007Sroberto if ( rc != WAIT_TIMEOUT ) /* not timeout: error */ 306182007Sroberto resolver_exit(1); 307182007Sroberto 308182007Sroberto#else /* not SYS_WINNT */ 309182007Sroberto tv.tv_sec = ALARM_TIME; 310182007Sroberto tv.tv_usec = 0; 311182007Sroberto FD_ZERO(&fdset); 312182007Sroberto FD_SET(resolver_pipe_fd[0], &fdset); 313182007Sroberto rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv); 314182007Sroberto 315182007Sroberto if (rc > 0) { /* parent process has written to the pipe */ 316182007Sroberto read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc)); /* make pipe empty */ 317182007Sroberto resolve_timer = 0; /* retry resolving immediately */ 318182007Sroberto continue; 319182007Sroberto } 320182007Sroberto 321182007Sroberto if ( rc < 0 ) /* select() returned error */ 322182007Sroberto resolver_exit(1); 323182007Sroberto#endif 324182007Sroberto 325182007Sroberto /* normal timeout, keep on waiting */ 32654359Sroberto if (config_timer > 0) 327182007Sroberto config_timer--; 32854359Sroberto if (resolve_timer > 0) 329182007Sroberto resolve_timer--; 33054359Sroberto } 33154359Sroberto} 33254359Sroberto 33354359Sroberto 33454359Sroberto 33554359Sroberto/* 33654359Sroberto * checkparent - see if our parent process is still running 33754359Sroberto * 33854359Sroberto * No need to worry in the Windows NT environment whether the 33954359Sroberto * main thread is still running, because if it goes 34054359Sroberto * down it takes the whole process down with it (in 34154359Sroberto * which case we won't be running this thread either) 34254359Sroberto * Turn function into NOP; 34354359Sroberto */ 34454359Sroberto 34554359Srobertostatic void 34654359Srobertocheckparent(void) 34754359Sroberto{ 34854359Sroberto#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) 34954359Sroberto 35054359Sroberto /* 35154359Sroberto * If our parent (the server) has died we will have been 35254359Sroberto * inherited by init. If so, exit. 35354359Sroberto */ 35454359Sroberto if (getppid() == 1) { 35554359Sroberto msyslog(LOG_INFO, "parent died before we finished, exiting"); 356182007Sroberto resolver_exit(0); 35754359Sroberto } 35854359Sroberto#endif /* SYS_WINNT && SYS_VXWORKS*/ 35954359Sroberto} 36054359Sroberto 36154359Sroberto 36254359Sroberto 36354359Sroberto/* 36454359Sroberto * removeentry - we are done with an entry, remove it from the list 36554359Sroberto */ 36654359Srobertostatic void 36754359Srobertoremoveentry( 36854359Sroberto struct conf_entry *entry 36954359Sroberto ) 37054359Sroberto{ 37154359Sroberto register struct conf_entry *ce; 37254359Sroberto 37354359Sroberto ce = confentries; 37454359Sroberto if (ce == entry) { 37554359Sroberto confentries = ce->ce_next; 37654359Sroberto return; 37754359Sroberto } 37854359Sroberto 37954359Sroberto while (ce != NULL) { 38054359Sroberto if (ce->ce_next == entry) { 38154359Sroberto ce->ce_next = entry->ce_next; 38254359Sroberto return; 38354359Sroberto } 38454359Sroberto ce = ce->ce_next; 38554359Sroberto } 38654359Sroberto} 38754359Sroberto 38854359Sroberto 38954359Sroberto/* 39054359Sroberto * addentry - add an entry to the configuration list 39154359Sroberto */ 39254359Srobertostatic void 39354359Srobertoaddentry( 39454359Sroberto char *name, 39554359Sroberto int mode, 39654359Sroberto int version, 39754359Sroberto int minpoll, 39854359Sroberto int maxpoll, 39982498Sroberto u_int flags, 40054359Sroberto int ttl, 40182498Sroberto keyid_t keyid, 402223667Sbz char *keystr, 403223667Sbz u_char peeraf 40454359Sroberto ) 40554359Sroberto{ 40654359Sroberto register char *cp; 40754359Sroberto register struct conf_entry *ce; 40854359Sroberto unsigned int len; 40954359Sroberto 41082498Sroberto#ifdef DEBUG 41182498Sroberto if (debug > 1) 41282498Sroberto msyslog(LOG_INFO, 413223667Sbz "intres: <%s> %u %d %d %d %d %x %d %x %s\n", name, peeraf, 41482498Sroberto mode, version, minpoll, maxpoll, flags, ttl, keyid, 41582498Sroberto keystr); 41682498Sroberto#endif 41754359Sroberto len = strlen(name) + 1; 41882498Sroberto cp = (char *)emalloc(len); 41954359Sroberto memmove(cp, name, len); 42054359Sroberto 42154359Sroberto ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry)); 42254359Sroberto ce->ce_name = cp; 42354359Sroberto ce->ce_peeraddr = 0; 424182007Sroberto#ifdef ISC_PLATFORM_HAVEIPV6 425132451Sroberto ce->ce_peeraddr6 = in6addr_any; 426182007Sroberto#endif 427132451Sroberto ANYSOCK(&ce->peer_store); 428223667Sbz ce->peer_store.ss_family = peeraf; /* Save AF for getaddrinfo hints. */ 42954359Sroberto ce->ce_hmode = (u_char)mode; 43054359Sroberto ce->ce_version = (u_char)version; 43154359Sroberto ce->ce_minpoll = (u_char)minpoll; 43254359Sroberto ce->ce_maxpoll = (u_char)maxpoll; 43354359Sroberto ce->ce_flags = (u_char)flags; 43454359Sroberto ce->ce_ttl = (u_char)ttl; 43554359Sroberto ce->ce_keyid = keyid; 43682498Sroberto strncpy((char *)ce->ce_keystr, keystr, MAXFILENAME); 43754359Sroberto ce->ce_next = NULL; 43854359Sroberto 43954359Sroberto if (confentries == NULL) { 44054359Sroberto confentries = ce; 44154359Sroberto } else { 44254359Sroberto register struct conf_entry *cep; 44354359Sroberto 44454359Sroberto for (cep = confentries; cep->ce_next != NULL; 44554359Sroberto cep = cep->ce_next) 44654359Sroberto /* nothing */; 44754359Sroberto cep->ce_next = ce; 44854359Sroberto } 44954359Sroberto} 45054359Sroberto 45154359Sroberto 45254359Sroberto/* 45382498Sroberto * findhostaddr - resolve a host name into an address (Or vice-versa) 45454359Sroberto * 45582498Sroberto * Given one of {ce_peeraddr,ce_name}, find the other one. 45682498Sroberto * It returns 1 for "success" and 0 for an uncorrectable failure. 45782498Sroberto * Note that "success" includes try again errors. You can tell that you 45882498Sroberto * got a "try again" since {ce_peeraddr,ce_name} will still be zero. 45954359Sroberto */ 46054359Srobertostatic int 46154359Srobertofindhostaddr( 46254359Sroberto struct conf_entry *entry 46354359Sroberto ) 46454359Sroberto{ 465200576Sroberto static int eai_again_seen = 0; 466132451Sroberto struct addrinfo *addr; 467182007Sroberto struct addrinfo hints; 468200576Sroberto int again; 469132451Sroberto int error; 47054359Sroberto 47154359Sroberto checkparent(); /* make sure our guy is still running */ 47254359Sroberto 473182007Sroberto if (entry->ce_name != NULL && !SOCKNUL(&entry->peer_store)) { 47482498Sroberto /* HMS: Squawk? */ 47582498Sroberto msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined..."); 47682498Sroberto return 1; 47782498Sroberto } 47854359Sroberto 479200576Sroberto if (entry->ce_name == NULL && SOCKNUL(&entry->peer_store)) { 48082498Sroberto msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); 48182498Sroberto return 0; 48282498Sroberto } 48382498Sroberto 48482498Sroberto if (entry->ce_name) { 485200576Sroberto DPRINTF(2, ("findhostaddr: Resolving <%s>\n", 486200576Sroberto entry->ce_name)); 487182007Sroberto 488182007Sroberto memset(&hints, 0, sizeof(hints)); 489223667Sbz hints.ai_family = entry->peer_store.ss_family; 490223667Sbz hints.ai_socktype = SOCK_DGRAM; 491182007Sroberto /* 492182007Sroberto * If the IPv6 stack is not available look only for IPv4 addresses 493182007Sroberto */ 494182007Sroberto if (isc_net_probeipv6() != ISC_R_SUCCESS) 495182007Sroberto hints.ai_family = AF_INET; 496182007Sroberto 497182007Sroberto error = getaddrinfo(entry->ce_name, NULL, &hints, &addr); 498132451Sroberto if (error == 0) { 499132451Sroberto entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr)); 500132451Sroberto if (entry->peer_store.ss_family == AF_INET) { 501132451Sroberto entry->ce_peeraddr = 502132451Sroberto GET_INADDR(entry->peer_store); 503132451Sroberto entry->ce_config.v6_flag = 0; 504132451Sroberto } else { 505132451Sroberto entry->ce_peeraddr6 = 506132451Sroberto GET_INADDR6(entry->peer_store); 507132451Sroberto entry->ce_config.v6_flag = 1; 508132451Sroberto } 509132451Sroberto } 51082498Sroberto } else { 511200576Sroberto DPRINTF(2, ("findhostaddr: Resolving <%s>\n", 512200576Sroberto stoa(&entry->peer_store))); 513200576Sroberto 514132451Sroberto entry->ce_name = emalloc(MAXHOSTNAMELEN); 515132451Sroberto error = getnameinfo((const struct sockaddr *)&entry->peer_store, 516132451Sroberto SOCKLEN(&entry->peer_store), 517132451Sroberto (char *)&entry->ce_name, MAXHOSTNAMELEN, 518132451Sroberto NULL, 0, 0); 51982498Sroberto } 52082498Sroberto 521200576Sroberto if (0 == error) { 522200576Sroberto 523200576Sroberto /* again is our return value, for success it is 1 */ 524200576Sroberto again = 1; 525200576Sroberto 526200576Sroberto DPRINTF(2, ("findhostaddr: %s resolved.\n", 527200576Sroberto (entry->ce_name) ? "name" : "address")); 528200576Sroberto } else { 529200576Sroberto /* 530200576Sroberto * If the resolver failed, see if the failure is 531200576Sroberto * temporary. If so, return success. 532200576Sroberto */ 533200576Sroberto again = 0; 534200576Sroberto 535200576Sroberto switch (error) { 536200576Sroberto 537200576Sroberto case EAI_FAIL: 538200576Sroberto again = 1; 539200576Sroberto break; 540200576Sroberto 541182007Sroberto case EAI_AGAIN: 542200576Sroberto again = 1; 543200576Sroberto eai_again_seen = 1; 544200576Sroberto break; 545200576Sroberto 546182007Sroberto case EAI_NONAME: 547182007Sroberto#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 548182007Sroberto case EAI_NODATA: 549182007Sroberto#endif 550200576Sroberto msyslog(LOG_ERR, "host name not found%s%s: %s", 551200576Sroberto (EAI_NONAME == error) ? "" : " EAI_NODATA", 552200576Sroberto (eai_again_seen) ? " (permanent)" : "", 553200576Sroberto entry->ce_name); 554200576Sroberto again = !eai_again_seen; 555200576Sroberto break; 556200576Sroberto 557182007Sroberto#ifdef EAI_SYSTEM 558182007Sroberto case EAI_SYSTEM: 559200576Sroberto /* 560200576Sroberto * EAI_SYSTEM means the real error is in errno. We should be more 561200576Sroberto * discriminating about which errno values require retrying, but 562200576Sroberto * this matches existing behavior. 563200576Sroberto */ 564200576Sroberto again = 1; 565200576Sroberto DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n", 566200576Sroberto errno, strerror(errno))); 567200576Sroberto break; 568182007Sroberto#endif 569182007Sroberto } 570200576Sroberto 571200576Sroberto /* do this here to avoid perturbing errno earlier */ 572200576Sroberto DPRINTF(2, ("intres: got error status of: %d\n", error)); 57354359Sroberto } 57454359Sroberto 575200576Sroberto return again; 57654359Sroberto} 57754359Sroberto 57854359Sroberto 57954359Sroberto/* 58054359Sroberto * openntp - open a socket to the ntp server 58154359Sroberto */ 58254359Srobertostatic void 58354359Srobertoopenntp(void) 58454359Sroberto{ 585200576Sroberto const char *localhost = "127.0.0.1"; /* Use IPv4 loopback */ 586200576Sroberto struct addrinfo hints; 587200576Sroberto struct addrinfo *addr; 588200576Sroberto u_long on; 589200576Sroberto int err; 59054359Sroberto 591182007Sroberto if (sockfd != INVALID_SOCKET) 592200576Sroberto return; 593132451Sroberto 594132451Sroberto memset(&hints, 0, sizeof(hints)); 595182007Sroberto 596182007Sroberto /* 597182007Sroberto * For now only bother with IPv4 598182007Sroberto */ 599182007Sroberto hints.ai_family = AF_INET; 600200576Sroberto hints.ai_socktype = SOCK_DGRAM; 601182007Sroberto 602200576Sroberto err = getaddrinfo(localhost, "ntp", &hints, &addr); 603200576Sroberto 604200576Sroberto if (err) { 605200576Sroberto#ifdef EAI_SYSTEM 606200576Sroberto if (EAI_SYSTEM == err) 607200576Sroberto msyslog(LOG_ERR, "getaddrinfo(%s) failed: %m", 608200576Sroberto localhost); 609200576Sroberto else 610200576Sroberto#endif 611200576Sroberto msyslog(LOG_ERR, "getaddrinfo(%s) failed: %s", 612200576Sroberto localhost, gai_strerror(err)); 613182007Sroberto resolver_exit(1); 614132451Sroberto } 615132451Sroberto 616200576Sroberto sockfd = socket(addr->ai_family, addr->ai_socktype, 0); 617200576Sroberto 618200576Sroberto if (INVALID_SOCKET == sockfd) { 61954359Sroberto msyslog(LOG_ERR, "socket() failed: %m"); 620182007Sroberto resolver_exit(1); 62154359Sroberto } 62254359Sroberto 623200576Sroberto#ifndef SYS_WINNT 62454359Sroberto /* 625200576Sroberto * On Windows only the count of sockets must be less than 626200576Sroberto * FD_SETSIZE. On Unix each descriptor's value must be less 627200576Sroberto * than FD_SETSIZE, as fd_set is a bit array. 628200576Sroberto */ 629200576Sroberto if (sockfd >= FD_SETSIZE) { 630200576Sroberto msyslog(LOG_ERR, "socket fd %d too large, FD_SETSIZE %d", 631200576Sroberto (int)sockfd, FD_SETSIZE); 632200576Sroberto resolver_exit(1); 633200576Sroberto } 634200576Sroberto 635200576Sroberto /* 63654359Sroberto * Make the socket non-blocking. We'll wait with select() 637200576Sroberto * Unix: fcntl(O_NONBLOCK) or fcntl(FNDELAY) 63854359Sroberto */ 639200576Sroberto# ifdef O_NONBLOCK 64054359Sroberto if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { 64154359Sroberto msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); 642182007Sroberto resolver_exit(1); 64354359Sroberto } 644200576Sroberto# else 645200576Sroberto# ifdef FNDELAY 64654359Sroberto if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { 64754359Sroberto msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); 648182007Sroberto resolver_exit(1); 64954359Sroberto } 650200576Sroberto# else 651200576Sroberto# include "Bletch: NEED NON BLOCKING IO" 652200576Sroberto# endif /* FNDDELAY */ 653200576Sroberto# endif /* O_NONBLOCK */ 654200576Sroberto (void)on; /* quiet unused warning */ 655200576Sroberto#else /* !SYS_WINNT above */ 656200576Sroberto /* 657200576Sroberto * Make the socket non-blocking. We'll wait with select() 658200576Sroberto * Windows: ioctlsocket(FIONBIO) 659200576Sroberto */ 660200576Sroberto on = 1; 661200576Sroberto err = ioctlsocket(sockfd, FIONBIO, &on); 662200576Sroberto if (SOCKET_ERROR == err) { 663200576Sroberto msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); 664200576Sroberto resolver_exit(1); 66554359Sroberto } 66654359Sroberto#endif /* SYS_WINNT */ 667200576Sroberto 668200576Sroberto err = connect(sockfd, addr->ai_addr, addr->ai_addrlen); 669200576Sroberto if (SOCKET_ERROR == err) { 67082498Sroberto msyslog(LOG_ERR, "openntp: connect() failed: %m"); 671182007Sroberto resolver_exit(1); 67254359Sroberto } 673200576Sroberto 674200576Sroberto freeaddrinfo(addr); 67554359Sroberto} 67654359Sroberto 67754359Sroberto 67854359Sroberto/* 67954359Sroberto * request - send a configuration request to the server, wait for a response 68054359Sroberto */ 68154359Srobertostatic int 68254359Srobertorequest( 68354359Sroberto struct conf_peer *conf 68454359Sroberto ) 68554359Sroberto{ 68654359Sroberto fd_set fdset; 68754359Sroberto struct timeval tvout; 68854359Sroberto struct req_pkt reqpkt; 68954359Sroberto l_fp ts; 69054359Sroberto int n; 69154359Sroberto#ifdef SYS_WINNT 69254359Sroberto HANDLE hReadWriteEvent = NULL; 69354359Sroberto BOOL ret; 69454359Sroberto DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; 69554359Sroberto OVERLAPPED overlap; 69654359Sroberto#endif /* SYS_WINNT */ 69754359Sroberto 69854359Sroberto checkparent(); /* make sure our guy is still running */ 69954359Sroberto 700182007Sroberto if (sockfd == INVALID_SOCKET) 701200576Sroberto openntp(); 70254359Sroberto 70354359Sroberto#ifdef SYS_WINNT 70454359Sroberto hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 70554359Sroberto#endif /* SYS_WINNT */ 70654359Sroberto 70754359Sroberto /* 70854359Sroberto * Try to clear out any previously received traffic so it 70954359Sroberto * doesn't fool us. Note the socket is nonblocking. 71054359Sroberto */ 71154359Sroberto tvout.tv_sec = 0; 71254359Sroberto tvout.tv_usec = 0; 71354359Sroberto FD_ZERO(&fdset); 71454359Sroberto FD_SET(sockfd, &fdset); 71554359Sroberto while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) > 71654359Sroberto 0) { 71754359Sroberto recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); 71854359Sroberto FD_ZERO(&fdset); 71954359Sroberto FD_SET(sockfd, &fdset); 72054359Sroberto } 72154359Sroberto 72254359Sroberto /* 72354359Sroberto * Make up a request packet with the configuration info 72454359Sroberto */ 72554359Sroberto memset((char *)&reqpkt, 0, sizeof(reqpkt)); 72654359Sroberto 72754359Sroberto reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); 72854359Sroberto reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */ 72954359Sroberto reqpkt.implementation = IMPL_XNTPD; /* local implementation */ 73054359Sroberto reqpkt.request = REQ_CONFIG; /* configure a new peer */ 73154359Sroberto reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ 73254359Sroberto reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer)); 73382498Sroberto /* Make sure mbz_itemsize <= sizeof reqpkt.data */ 73482498Sroberto if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) { 73582498Sroberto msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!"); 736182007Sroberto resolver_exit(1); 73782498Sroberto } 73854359Sroberto memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer)); 73954359Sroberto reqpkt.keyid = htonl(req_keyid); 74054359Sroberto 74154359Sroberto get_systime(&ts); 74254359Sroberto L_ADDUF(&ts, SKEWTIME); 74354359Sroberto HTONL_FP(&ts, &reqpkt.tstamp); 74454359Sroberto n = 0; 74554359Sroberto if (sys_authenticate) 74654359Sroberto n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC); 74754359Sroberto 74854359Sroberto /* 74954359Sroberto * Done. Send it. 75054359Sroberto */ 75154359Sroberto#ifndef SYS_WINNT 75254359Sroberto n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0); 75354359Sroberto if (n < 0) { 75454359Sroberto msyslog(LOG_ERR, "send to NTP server failed: %m"); 75554359Sroberto return 0; /* maybe should exit */ 75654359Sroberto } 75754359Sroberto#else 75854359Sroberto /* In the NT world, documentation seems to indicate that there 75982498Sroberto * exist _write and _read routines that can be used to do blocking 76054359Sroberto * I/O on sockets. Problem is these routines require a socket 76154359Sroberto * handle obtained through the _open_osf_handle C run-time API 76254359Sroberto * of which there is no explanation in the documentation. We need 76354359Sroberto * nonblocking write's and read's anyway for our purpose here. 76454359Sroberto * We're therefore forced to deviate a little bit from the Unix 76554359Sroberto * model here and use the ReadFile and WriteFile Win32 I/O API's 76654359Sroberto * on the socket 76754359Sroberto */ 76854359Sroberto overlap.Offset = overlap.OffsetHigh = (DWORD)0; 76954359Sroberto overlap.hEvent = hReadWriteEvent; 77054359Sroberto ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n, 771182007Sroberto NULL, (LPOVERLAPPED)&overlap); 77254359Sroberto if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { 77354359Sroberto msyslog(LOG_ERR, "send to NTP server failed: %m"); 77454359Sroberto return 0; 77554359Sroberto } 77654359Sroberto dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); 77754359Sroberto if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { 77854359Sroberto if (dwWait == WAIT_FAILED) 77954359Sroberto msyslog(LOG_ERR, "WaitForSingleObject failed: %m"); 78054359Sroberto return 0; 78154359Sroberto } 782182007Sroberto if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap, 783182007Sroberto (LPDWORD)&NumberOfBytesWritten, FALSE)) { 784182007Sroberto msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m"); 785182007Sroberto return 0; 786182007Sroberto } 78754359Sroberto#endif /* SYS_WINNT */ 78854359Sroberto 78954359Sroberto 79054359Sroberto /* 79154359Sroberto * Wait for a response. A weakness of the mode 7 protocol used 79254359Sroberto * is that there is no way to associate a response with a 79354359Sroberto * particular request, i.e. the response to this configuration 79454359Sroberto * request is indistinguishable from that to any other. I should 79554359Sroberto * fix this some day. In any event, the time out is fairly 79654359Sroberto * pessimistic to make sure that if an answer is coming back 79754359Sroberto * at all, we get it. 79854359Sroberto */ 79954359Sroberto for (;;) { 80054359Sroberto FD_ZERO(&fdset); 80154359Sroberto FD_SET(sockfd, &fdset); 80254359Sroberto tvout.tv_sec = TIMEOUT_SEC; 80354359Sroberto tvout.tv_usec = TIMEOUT_USEC; 80454359Sroberto 80554359Sroberto n = select(sockfd + 1, &fdset, (fd_set *)0, 80654359Sroberto (fd_set *)0, &tvout); 80754359Sroberto 80854359Sroberto if (n < 0) 80954359Sroberto { 810132451Sroberto if (errno != EINTR) 811132451Sroberto msyslog(LOG_ERR, "select() fails: %m"); 81254359Sroberto return 0; 81354359Sroberto } 81454359Sroberto else if (n == 0) 81554359Sroberto { 816182007Sroberto#ifdef DEBUG 81782498Sroberto if (debug) 81882498Sroberto msyslog(LOG_INFO, "select() returned 0."); 819182007Sroberto#endif 82054359Sroberto return 0; 82154359Sroberto } 82254359Sroberto 82354359Sroberto#ifndef SYS_WINNT 82454359Sroberto n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); 82554359Sroberto if (n <= 0) { 82654359Sroberto if (n < 0) { 82754359Sroberto msyslog(LOG_ERR, "recv() fails: %m"); 82854359Sroberto return 0; 82954359Sroberto } 83054359Sroberto continue; 83154359Sroberto } 83254359Sroberto#else /* Overlapped I/O used on non-blocking sockets on Windows NT */ 83354359Sroberto ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC, 834182007Sroberto NULL, (LPOVERLAPPED)&overlap); 83554359Sroberto if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { 83654359Sroberto msyslog(LOG_ERR, "ReadFile() fails: %m"); 83754359Sroberto return 0; 83854359Sroberto } 83954359Sroberto dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); 84054359Sroberto if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { 84154359Sroberto if (dwWait == WAIT_FAILED) { 842182007Sroberto msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m"); 84354359Sroberto return 0; 84454359Sroberto } 84554359Sroberto continue; 84654359Sroberto } 847182007Sroberto if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap, 848182007Sroberto (LPDWORD)&NumberOfBytesRead, FALSE)) { 849182007Sroberto msyslog(LOG_ERR, "GetOverlappedResult fails: %m"); 850182007Sroberto return 0; 851182007Sroberto } 85254359Sroberto n = NumberOfBytesRead; 85354359Sroberto#endif /* SYS_WINNT */ 85454359Sroberto 85554359Sroberto /* 85654359Sroberto * Got one. Check through to make sure it is what 85754359Sroberto * we expect. 85854359Sroberto */ 85954359Sroberto if (n < RESP_HEADER_SIZE) { 86054359Sroberto msyslog(LOG_ERR, "received runt response (%d octets)", 86154359Sroberto n); 86254359Sroberto continue; 86354359Sroberto } 86454359Sroberto 86554359Sroberto if (!ISRESPONSE(reqpkt.rm_vn_mode)) { 86654359Sroberto#ifdef DEBUG 86754359Sroberto if (debug > 1) 86854359Sroberto msyslog(LOG_INFO, "received non-response packet"); 86954359Sroberto#endif 87054359Sroberto continue; 87154359Sroberto } 87254359Sroberto 87354359Sroberto if (ISMORE(reqpkt.rm_vn_mode)) { 87454359Sroberto#ifdef DEBUG 87554359Sroberto if (debug > 1) 87654359Sroberto msyslog(LOG_INFO, "received fragmented packet"); 87754359Sroberto#endif 87854359Sroberto continue; 87954359Sroberto } 88054359Sroberto 88154359Sroberto if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2) 88254359Sroberto || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION)) 88354359Sroberto || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) { 88454359Sroberto#ifdef DEBUG 88554359Sroberto if (debug > 1) 88654359Sroberto msyslog(LOG_INFO, 88754359Sroberto "version (%d/%d) or mode (%d/%d) incorrect", 88854359Sroberto INFO_VERSION(reqpkt.rm_vn_mode), 88954359Sroberto NTP_VERSION, 89054359Sroberto INFO_MODE(reqpkt.rm_vn_mode), 89154359Sroberto MODE_PRIVATE); 89254359Sroberto#endif 89354359Sroberto continue; 89454359Sroberto } 89554359Sroberto 89654359Sroberto if (INFO_SEQ(reqpkt.auth_seq) != 0) { 89754359Sroberto#ifdef DEBUG 89854359Sroberto if (debug > 1) 89954359Sroberto msyslog(LOG_INFO, 90054359Sroberto "nonzero sequence number (%d)", 90154359Sroberto INFO_SEQ(reqpkt.auth_seq)); 90254359Sroberto#endif 90354359Sroberto continue; 90454359Sroberto } 90554359Sroberto 90654359Sroberto if (reqpkt.implementation != IMPL_XNTPD || 90754359Sroberto reqpkt.request != REQ_CONFIG) { 90854359Sroberto#ifdef DEBUG 90954359Sroberto if (debug > 1) 91054359Sroberto msyslog(LOG_INFO, 91154359Sroberto "implementation (%d) or request (%d) incorrect", 91254359Sroberto reqpkt.implementation, reqpkt.request); 91354359Sroberto#endif 91454359Sroberto continue; 91554359Sroberto } 91654359Sroberto 91754359Sroberto if (INFO_NITEMS(reqpkt.err_nitems) != 0 || 91854359Sroberto INFO_MBZ(reqpkt.mbz_itemsize) != 0 || 91954359Sroberto INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) { 92054359Sroberto#ifdef DEBUG 92154359Sroberto if (debug > 1) 92254359Sroberto msyslog(LOG_INFO, 92354359Sroberto "nitems (%d) mbz (%d) or itemsize (%d) nonzero", 92454359Sroberto INFO_NITEMS(reqpkt.err_nitems), 92554359Sroberto INFO_MBZ(reqpkt.mbz_itemsize), 92654359Sroberto INFO_ITEMSIZE(reqpkt.mbz_itemsize)); 92754359Sroberto#endif 92854359Sroberto continue; 92954359Sroberto } 93054359Sroberto 93154359Sroberto n = INFO_ERR(reqpkt.err_nitems); 93254359Sroberto switch (n) { 93354359Sroberto case INFO_OKAY: 93454359Sroberto /* success */ 93554359Sroberto return 1; 93654359Sroberto 93754359Sroberto case INFO_ERR_IMPL: 93854359Sroberto msyslog(LOG_ERR, 939132451Sroberto "ntpd reports implementation mismatch!"); 94054359Sroberto return 0; 94154359Sroberto 94254359Sroberto case INFO_ERR_REQ: 94354359Sroberto msyslog(LOG_ERR, 944132451Sroberto "ntpd says configuration request is unknown!"); 94554359Sroberto return 0; 94654359Sroberto 94754359Sroberto case INFO_ERR_FMT: 94854359Sroberto msyslog(LOG_ERR, 949132451Sroberto "ntpd indicates a format error occurred!"); 95054359Sroberto return 0; 95154359Sroberto 95254359Sroberto case INFO_ERR_NODATA: 95354359Sroberto msyslog(LOG_ERR, 954132451Sroberto "ntpd indicates no data available!"); 95554359Sroberto return 0; 95654359Sroberto 95754359Sroberto case INFO_ERR_AUTH: 95854359Sroberto msyslog(LOG_ERR, 959132451Sroberto "ntpd returns a permission denied error!"); 96054359Sroberto return 0; 96154359Sroberto 96254359Sroberto default: 96354359Sroberto msyslog(LOG_ERR, 964132451Sroberto "ntpd returns unknown error code %d!", n); 96554359Sroberto return 0; 96654359Sroberto } 96754359Sroberto } 96854359Sroberto} 96954359Sroberto 97054359Sroberto 97154359Sroberto/* 97254359Sroberto * nexttoken - return the next token from a line 97354359Sroberto */ 97454359Srobertostatic char * 97554359Srobertonexttoken( 97654359Sroberto char **lptr 97754359Sroberto ) 97854359Sroberto{ 97954359Sroberto register char *cp; 98054359Sroberto register char *tstart; 98154359Sroberto 98254359Sroberto cp = *lptr; 98354359Sroberto 98454359Sroberto /* 98554359Sroberto * Skip leading white space 98654359Sroberto */ 98754359Sroberto while (*cp == ' ' || *cp == '\t') 98854359Sroberto cp++; 98954359Sroberto 99054359Sroberto /* 99154359Sroberto * If this is the end of the line, return nothing. 99254359Sroberto */ 99354359Sroberto if (*cp == '\n' || *cp == '\0') { 99454359Sroberto *lptr = cp; 99554359Sroberto return NULL; 99654359Sroberto } 99754359Sroberto 99854359Sroberto /* 99954359Sroberto * Must be the start of a token. Record the pointer and look 100054359Sroberto * for the end. 100154359Sroberto */ 100254359Sroberto tstart = cp++; 100354359Sroberto while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0') 100454359Sroberto cp++; 100554359Sroberto 100654359Sroberto /* 100754359Sroberto * Terminate the token with a \0. If this isn't the end of the 100854359Sroberto * line, space to the next character. 100954359Sroberto */ 101054359Sroberto if (*cp == '\n' || *cp == '\0') 101154359Sroberto *cp = '\0'; 101254359Sroberto else 101354359Sroberto *cp++ = '\0'; 101454359Sroberto 101554359Sroberto *lptr = cp; 101654359Sroberto return tstart; 101754359Sroberto} 101854359Sroberto 101954359Sroberto 102054359Sroberto/* 102154359Sroberto * readconf - read the configuration information out of the file we 102254359Sroberto * were passed. Note that since the file is supposed to be 102354359Sroberto * machine generated, we bail out at the first sign of trouble. 102454359Sroberto */ 102554359Srobertostatic void 102654359Srobertoreadconf( 102754359Sroberto FILE *fp, 102854359Sroberto char *name 102954359Sroberto ) 103054359Sroberto{ 103154359Sroberto register int i; 103254359Sroberto char *token[NUMTOK]; 103354359Sroberto u_long intval[NUMTOK]; 103482498Sroberto u_int flags; 103554359Sroberto char buf[MAXLINESIZE]; 103654359Sroberto char *bp; 103754359Sroberto 103854359Sroberto while (fgets(buf, MAXLINESIZE, fp) != NULL) { 103954359Sroberto 104054359Sroberto bp = buf; 104154359Sroberto for (i = 0; i < NUMTOK; i++) { 104254359Sroberto if ((token[i] = nexttoken(&bp)) == NULL) { 104354359Sroberto msyslog(LOG_ERR, 104454359Sroberto "tokenizing error in file `%s', quitting", 104554359Sroberto name); 1046182007Sroberto resolver_exit(1); 104754359Sroberto } 104854359Sroberto } 104954359Sroberto 105082498Sroberto for (i = 1; i < NUMTOK - 1; i++) { 105154359Sroberto if (!atouint(token[i], &intval[i])) { 105254359Sroberto msyslog(LOG_ERR, 105354359Sroberto "format error for integer token `%s', file `%s', quitting", 105454359Sroberto token[i], name); 1055182007Sroberto resolver_exit(1); 105654359Sroberto } 105754359Sroberto } 105854359Sroberto 1059223667Sbz if (intval[TOK_PEERAF] != AF_UNSPEC && intval[TOK_PEERAF] != 1060223667Sbz AF_INET && intval[TOK_PEERAF] != AF_INET6) { 1061223667Sbz msyslog(LOG_ERR, "invalid peer address family (%u) in " 1062223667Sbz "file %s", intval[TOK_PEERAF], name); 1063223667Sbz exit(1); 1064223667Sbz } 1065223667Sbz 106654359Sroberto if (intval[TOK_HMODE] != MODE_ACTIVE && 106754359Sroberto intval[TOK_HMODE] != MODE_CLIENT && 106854359Sroberto intval[TOK_HMODE] != MODE_BROADCAST) { 106954359Sroberto msyslog(LOG_ERR, "invalid mode (%ld) in file %s", 107054359Sroberto intval[TOK_HMODE], name); 1071182007Sroberto resolver_exit(1); 107254359Sroberto } 107354359Sroberto 107454359Sroberto if (intval[TOK_VERSION] > NTP_VERSION || 107554359Sroberto intval[TOK_VERSION] < NTP_OLDVERSION) { 107654359Sroberto msyslog(LOG_ERR, "invalid version (%ld) in file %s", 107754359Sroberto intval[TOK_VERSION], name); 1078182007Sroberto resolver_exit(1); 107954359Sroberto } 108054359Sroberto if (intval[TOK_MINPOLL] < NTP_MINPOLL || 108154359Sroberto intval[TOK_MINPOLL] > NTP_MAXPOLL) { 108254359Sroberto msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s", 108354359Sroberto intval[TOK_MINPOLL], name); 1084182007Sroberto resolver_exit(1); 108554359Sroberto } 108654359Sroberto 108754359Sroberto if (intval[TOK_MAXPOLL] < NTP_MINPOLL || 108854359Sroberto intval[TOK_MAXPOLL] > NTP_MAXPOLL) { 108954359Sroberto msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s", 109054359Sroberto intval[TOK_MAXPOLL], name); 1091182007Sroberto resolver_exit(1); 109254359Sroberto } 109354359Sroberto 109454359Sroberto if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER | 109582498Sroberto FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY)) 109654359Sroberto != 0) { 109754359Sroberto msyslog(LOG_ERR, "invalid flags (%ld) in file %s", 109854359Sroberto intval[TOK_FLAGS], name); 1099182007Sroberto resolver_exit(1); 110054359Sroberto } 110154359Sroberto 110254359Sroberto flags = 0; 110354359Sroberto if (intval[TOK_FLAGS] & FLAG_AUTHENABLE) 110454359Sroberto flags |= CONF_FLAG_AUTHENABLE; 110554359Sroberto if (intval[TOK_FLAGS] & FLAG_PREFER) 110654359Sroberto flags |= CONF_FLAG_PREFER; 110754359Sroberto if (intval[TOK_FLAGS] & FLAG_NOSELECT) 110854359Sroberto flags |= CONF_FLAG_NOSELECT; 110954359Sroberto if (intval[TOK_FLAGS] & FLAG_BURST) 111054359Sroberto flags |= CONF_FLAG_BURST; 111182498Sroberto if (intval[TOK_FLAGS] & FLAG_IBURST) 111282498Sroberto flags |= CONF_FLAG_IBURST; 111354359Sroberto if (intval[TOK_FLAGS] & FLAG_SKEY) 111454359Sroberto flags |= CONF_FLAG_SKEY; 111554359Sroberto 111654359Sroberto /* 111754359Sroberto * This is as good as we can check it. Add it in. 111854359Sroberto */ 111954359Sroberto addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], 112054359Sroberto (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], 112154359Sroberto (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], 1122223667Sbz intval[TOK_KEYID], token[TOK_KEYSTR], (u_char)intval[TOK_PEERAF]); 112354359Sroberto } 112454359Sroberto} 112554359Sroberto 112654359Sroberto 112754359Sroberto/* 112854359Sroberto * doconfigure - attempt to resolve names and configure the server 112954359Sroberto */ 113054359Srobertostatic void 113154359Srobertodoconfigure( 113254359Sroberto int dores 113354359Sroberto ) 113454359Sroberto{ 113554359Sroberto register struct conf_entry *ce; 113654359Sroberto register struct conf_entry *ceremove; 113754359Sroberto 1138182007Sroberto#ifdef DEBUG 1139182007Sroberto if (debug > 1) 1140182007Sroberto msyslog(LOG_INFO, "Running doconfigure %s DNS", 1141182007Sroberto dores ? "with" : "without" ); 1142182007Sroberto#endif 1143182007Sroberto 1144223667Sbz if (dores) /* Reload /etc/resolv.conf - bug 1226 */ 1145223667Sbz res_init(); 1146223667Sbz 114754359Sroberto ce = confentries; 114854359Sroberto while (ce != NULL) { 114954359Sroberto#ifdef DEBUG 115054359Sroberto if (debug > 1) 115182498Sroberto msyslog(LOG_INFO, 1152132451Sroberto "doconfigure: <%s> has peeraddr %s", 1153132451Sroberto ce->ce_name, stoa(&ce->peer_store)); 115454359Sroberto#endif 1155182007Sroberto if (dores && SOCKNUL(&(ce->peer_store))) { 115654359Sroberto if (!findhostaddr(ce)) { 1157200576Sroberto#ifndef IGNORE_DNS_ERRORS 115854359Sroberto msyslog(LOG_ERR, 115954359Sroberto "couldn't resolve `%s', giving up on it", 116054359Sroberto ce->ce_name); 116154359Sroberto ceremove = ce; 116254359Sroberto ce = ceremove->ce_next; 116354359Sroberto removeentry(ceremove); 116454359Sroberto continue; 1165200576Sroberto#endif 116654359Sroberto } 116754359Sroberto } 116854359Sroberto 1169132451Sroberto if (!SOCKNUL(&ce->peer_store)) { 117054359Sroberto if (request(&ce->ce_config)) { 117154359Sroberto ceremove = ce; 117254359Sroberto ce = ceremove->ce_next; 117354359Sroberto removeentry(ceremove); 117454359Sroberto continue; 117554359Sroberto } 117654359Sroberto#ifdef DEBUG 117754359Sroberto if (debug > 1) { 117854359Sroberto msyslog(LOG_INFO, 117982498Sroberto "doconfigure: request() FAILED, maybe next time."); 118054359Sroberto } 118154359Sroberto#endif 118254359Sroberto } 118354359Sroberto ce = ce->ce_next; 118454359Sroberto } 118554359Sroberto} 1186