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