2 * ntp_config.c - read and apply configuration information
9 # include <netinfo/ni.h>
14 #include "ntp_unixtime.h"
15 #include "ntp_refclock.h"
16 #include "ntp_filegen.h"
17 #include "ntp_stdlib.h"
18 #include <ntp_random.h>
20 #include <isc/result.h>
24 #ifdef HAVE_SYS_PARAM_H
25 #include <sys/param.h>
29 # define SIGCHLD SIGCLD
32 # ifdef HAVE_SYS_WAIT_H
33 # include <sys/wait.h>
39 static HANDLE ResolverThreadHandle = NULL;
40 HANDLE ResolverEventHandle;
42 int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */
43 #endif /* SYS_WINNT */
46 * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS
47 * so #include these later.
50 #include "ntp_config.h"
51 #include "ntp_cmdargs.h"
53 extern int priority_done;
56 * These routines are used to read the configuration file at
57 * startup time. An entry in the file must fit on a single line.
58 * Entries are processed as multiple tokens separated by white space
59 * Lines are considered terminated when a '#' is encountered. Blank
63 * Translation table - keywords to function index
73 static struct keyword keywords[] = {
74 { "automax", CONFIG_AUTOMAX },
75 { "broadcast", CONFIG_BROADCAST },
76 { "broadcastclient", CONFIG_BROADCASTCLIENT },
77 { "broadcastdelay", CONFIG_BDELAY },
78 { "calldelay", CONFIG_CDELAY},
80 { "crypto", CONFIG_CRYPTO },
82 { "controlkey", CONFIG_CONTROLKEY },
83 { "disable", CONFIG_DISABLE },
84 { "driftfile", CONFIG_DRIFTFILE },
85 { "enable", CONFIG_ENABLE },
86 { "end", CONFIG_END },
87 { "filegen", CONFIG_FILEGEN },
88 { "fudge", CONFIG_FUDGE },
89 { "includefile", CONFIG_INCLUDEFILE },
90 { "keys", CONFIG_KEYS },
91 { "keysdir", CONFIG_KEYSDIR },
92 { "logconfig", CONFIG_LOGCONFIG },
93 { "logfile", CONFIG_LOGFILE },
94 { "manycastclient", CONFIG_MANYCASTCLIENT },
95 { "manycastserver", CONFIG_MANYCASTSERVER },
96 { "multicastclient", CONFIG_MULTICASTCLIENT },
97 { "peer", CONFIG_PEER },
98 { "phone", CONFIG_PHONE },
99 { "pidfile", CONFIG_PIDFILE },
100 { "discard", CONFIG_DISCARD },
101 { "requestkey", CONFIG_REQUESTKEY },
102 { "restrict", CONFIG_RESTRICT },
103 { "revoke", CONFIG_REVOKE },
104 { "server", CONFIG_SERVER },
105 { "setvar", CONFIG_SETVAR },
106 { "statistics", CONFIG_STATISTICS },
107 { "statsdir", CONFIG_STATSDIR },
108 { "tick", CONFIG_ADJ },
109 { "tinker", CONFIG_TINKER },
110 { "tos", CONFIG_TOS },
111 { "trap", CONFIG_TRAP },
112 { "trustedkey", CONFIG_TRUSTEDKEY },
113 { "ttl", CONFIG_TTL },
114 { "", CONFIG_UNKNOWN }
118 * "peer", "server", "broadcast" modifier keywords
120 static struct keyword mod_keywords[] = {
121 { "autokey", CONF_MOD_SKEY },
122 { "burst", CONF_MOD_BURST },
123 { "iburst", CONF_MOD_IBURST },
124 { "key", CONF_MOD_KEY },
125 { "maxpoll", CONF_MOD_MAXPOLL },
126 { "minpoll", CONF_MOD_MINPOLL },
127 { "mode", CONF_MOD_MODE }, /* refclocks */
128 { "noselect", CONF_MOD_NOSELECT },
129 { "preempt", CONF_MOD_PREEMPT },
130 { "true", CONF_MOD_TRUE },
131 { "prefer", CONF_MOD_PREFER },
132 { "ttl", CONF_MOD_TTL }, /* NTP peers */
133 { "version", CONF_MOD_VERSION },
134 { "dynamic", CONF_MOD_DYNAMIC },
135 { "", CONFIG_UNKNOWN }
139 * "restrict" modifier keywords
141 static struct keyword res_keywords[] = {
142 { "ignore", CONF_RES_IGNORE },
143 { "limited", CONF_RES_LIMITED },
144 { "kod", CONF_RES_DEMOBILIZE },
145 { "lowpriotrap", CONF_RES_LPTRAP },
146 { "mask", CONF_RES_MASK },
147 { "nomodify", CONF_RES_NOMODIFY },
148 { "nopeer", CONF_RES_NOPEER },
149 { "noquery", CONF_RES_NOQUERY },
150 { "noserve", CONF_RES_NOSERVE },
151 { "notrap", CONF_RES_NOTRAP },
152 { "notrust", CONF_RES_NOTRUST },
153 { "ntpport", CONF_RES_NTPPORT },
154 { "version", CONF_RES_VERSION },
155 { "", CONFIG_UNKNOWN }
159 * "trap" modifier keywords
161 static struct keyword trap_keywords[] = {
162 { "port", CONF_TRAP_PORT },
163 { "interface", CONF_TRAP_INTERFACE },
164 { "", CONFIG_UNKNOWN }
168 * "fudge" modifier keywords
170 static struct keyword fudge_keywords[] = {
171 { "flag1", CONF_FDG_FLAG1 },
172 { "flag2", CONF_FDG_FLAG2 },
173 { "flag3", CONF_FDG_FLAG3 },
174 { "flag4", CONF_FDG_FLAG4 },
175 { "refid", CONF_FDG_REFID }, /* this mapping should be cleaned up (endianness, \0) - kd 20041031 */
176 { "stratum", CONF_FDG_STRATUM },
177 { "time1", CONF_FDG_TIME1 },
178 { "time2", CONF_FDG_TIME2 },
179 { "", CONFIG_UNKNOWN }
183 * "filegen" modifier keywords
185 static struct keyword filegen_keywords[] = {
186 { "disable", CONF_FGEN_FLAG_DISABLE },
187 { "enable", CONF_FGEN_FLAG_ENABLE },
188 { "file", CONF_FGEN_FILE },
189 { "link", CONF_FGEN_FLAG_LINK },
190 { "nolink", CONF_FGEN_FLAG_NOLINK },
191 { "type", CONF_FGEN_TYPE },
192 { "", CONFIG_UNKNOWN }
196 * "type" modifier keywords
198 static struct keyword fgen_types[] = {
199 { "age", FILEGEN_AGE },
200 { "day", FILEGEN_DAY },
201 { "month", FILEGEN_MONTH },
202 { "none", FILEGEN_NONE },
203 { "pid", FILEGEN_PID },
204 { "week", FILEGEN_WEEK },
205 { "year", FILEGEN_YEAR },
206 { "", CONFIG_UNKNOWN}
210 * "enable", "disable" modifier keywords
212 static struct keyword flags_keywords[] = {
213 { "auth", PROTO_AUTHENTICATE },
214 { "bclient", PROTO_BROADCLIENT },
215 { "calibrate", PROTO_CAL },
216 { "kernel", PROTO_KERNEL },
217 { "monitor", PROTO_MONITOR },
218 { "ntp", PROTO_NTP },
219 { "stats", PROTO_FILEGEN },
220 { "", CONFIG_UNKNOWN }
224 * "discard" modifier keywords
226 static struct keyword discard_keywords[] = {
227 { "average", CONF_DISCARD_AVERAGE },
228 { "minimum", CONF_DISCARD_MINIMUM },
229 { "monitor", CONF_DISCARD_MONITOR },
230 { "", CONFIG_UNKNOWN }
234 * "tinker" modifier keywords
236 static struct keyword tinker_keywords[] = {
237 { "step", CONF_CLOCK_MAX },
238 { "panic", CONF_CLOCK_PANIC },
239 { "dispersion", CONF_CLOCK_PHI },
240 { "stepout", CONF_CLOCK_MINSTEP },
241 { "allan", CONF_CLOCK_ALLAN },
242 { "huffpuff", CONF_CLOCK_HUFFPUFF },
243 { "freq", CONF_CLOCK_FREQ },
244 { "", CONFIG_UNKNOWN }
248 * "tos" modifier keywords
250 static struct keyword tos_keywords[] = {
251 { "minclock", CONF_TOS_MINCLOCK },
252 { "maxclock", CONF_TOS_MAXCLOCK },
253 { "minsane", CONF_TOS_MINSANE },
254 { "floor", CONF_TOS_FLOOR },
255 { "ceiling", CONF_TOS_CEILING },
256 { "cohort", CONF_TOS_COHORT },
257 { "mindist", CONF_TOS_MINDISP },
258 { "maxdist", CONF_TOS_MAXDIST },
259 { "maxhop", CONF_TOS_MAXHOP },
260 { "beacon", CONF_TOS_BEACON },
261 { "orphan", CONF_TOS_ORPHAN },
262 { "", CONFIG_UNKNOWN }
267 * "crypto" modifier keywords
269 static struct keyword crypto_keywords[] = {
270 { "cert", CONF_CRYPTO_CERT },
271 { "gqpar", CONF_CRYPTO_GQPAR },
272 { "host", CONF_CRYPTO_RSA },
273 { "ident", CONF_CRYPTO_IDENT },
274 { "iffpar", CONF_CRYPTO_IFFPAR },
275 { "leap", CONF_CRYPTO_LEAP },
276 { "mvpar", CONF_CRYPTO_MVPAR },
277 { "pw", CONF_CRYPTO_PW },
278 { "randfile", CONF_CRYPTO_RAND },
279 { "sign", CONF_CRYPTO_SIGN },
280 { "", CONFIG_UNKNOWN }
285 * Address type selection, IPv4 or IPv4.
286 * Used on various lines.
288 static struct keyword addr_type[] = {
289 { "-4", CONF_ADDR_IPV4 },
290 { "-6", CONF_ADDR_IPV6 },
291 { "", CONFIG_UNKNOWN }
295 * "logconfig" building blocks
302 static struct masks logcfg_class[] = {
303 { "clock", NLOG_OCLOCK },
304 { "peer", NLOG_OPEER },
305 { "sync", NLOG_OSYNC },
306 { "sys", NLOG_OSYS },
310 static struct masks logcfg_item[] = {
311 { "info", NLOG_INFO },
312 { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
313 { "events", NLOG_EVENT },
314 { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
315 { "status", NLOG_STATUS },
316 { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
317 { "statistics", NLOG_STATIST },
318 { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
319 { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
320 { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
321 { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
322 { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
323 { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
330 #define MAXTOKENS 20 /* 20 tokens on line */
331 #define MAXLINE 1024 /* maximum length of line */
332 #define MAXPHONE 10 /* maximum number of phone strings */
333 #define MAXPPS 20 /* maximum length of PPS device string */
334 #define MAXINCLUDELEVEL 5 /* maximum include file levels */
337 * Miscellaneous macros
339 #define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
340 #define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
341 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
342 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
344 #define KEY_TYPE_MD5 4
347 * File descriptor used by the resolver save routines, and temporary file
350 int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */
353 static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */
354 #define RES_TEMPFILE "/tmp/ntpXXXXXX"
356 static char res_file[MAX_PATH];
357 #endif /* SYS_WINNT */
360 * Definitions of things either imported from or exported to outside
363 short default_ai_family = AF_UNSPEC; /* Default either IPv4 or IPv6 */
364 char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */
365 char *keysdir = NTP_KEYSDIR; /* crypto keys directory */
366 #if defined(HAVE_SCHED_SETSCHEDULER)
367 int config_priority_override = 0;
371 const char *config_file;
373 struct netinfo_config_state *config_netinfo = NULL;
374 int check_netinfo = 1;
375 #endif /* HAVE_NETINFO */
377 char *alt_config_file;
379 char config_file_storage[MAX_PATH];
380 char alt_config_file_storage[MAX_PATH];
381 #endif /* SYS_WINNT */
385 * NetInfo configuration state
387 struct netinfo_config_state {
388 void *domain; /* domain with config */
389 ni_id config_dir; /* ID config dir */
390 int prop_index; /* current property */
391 int val_index; /* current value */
392 char **val_list; /* value list */
397 * Function prototypes
399 static unsigned long get_pfxmatch P((char **, struct masks *));
400 static unsigned long get_match P((char *, struct masks *));
401 static unsigned long get_logmask P((char *));
403 static struct netinfo_config_state *get_netinfo_config P((void));
404 static void free_netinfo_config P((struct netinfo_config_state *));
405 static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
407 static int gettokens P((FILE *, char *, char **, int *));
408 static int matchkey P((char *, struct keyword *, int));
411 t_REF, /* Refclock */
412 t_MSK /* Network Mask */
414 static int getnetnum P((const char *, struct sockaddr_storage *, int,
416 static void save_resolve P((char *, int, int, int, int, u_int, int,
417 keyid_t, u_char *, u_char));
418 static void do_resolve_internal P((void));
419 static void abort_resolve P((void));
420 #if !defined(VMS) && !defined(SYS_WINNT)
421 static RETSIGTYPE catchchild P((int));
425 * get_pfxmatch - find value for prefixmatch
426 * and update char * accordingly
435 if (strncmp(*s, m->name, strlen(m->name)) == 0) {
436 *s += strlen(m->name);
446 * get_match - find logmask value
455 if (strcmp(s, m->name) == 0) {
465 * get_logmask - build bitmask for ntp_syslogmask
473 unsigned long offset;
477 offset = get_pfxmatch(&t, logcfg_class);
478 mask = get_match(t, logcfg_item);
481 return mask << offset;
483 msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);
490 * getconfig - get command line options and read the configuration file
514 struct sockaddr_storage peeraddr;
515 struct sockaddr_storage maskaddr;
516 FILE *fp[MAXINCLUDELEVEL+1];
518 int includelevel = 0;
520 char *(tokens[MAXTOKENS]);
522 int tok = CONFIG_UNKNOWN;
523 struct interface *localaddr;
524 struct refclockstat clock_stat;
528 * Initialize, initialize
533 config_file = CONFIG_FILE;
536 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
537 msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
540 config_file = config_file_storage;
542 temp = ALT_CONFIG_FILE;
543 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
544 msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
547 alt_config_file = alt_config_file_storage;
549 #endif /* SYS_WINNT */
551 ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
554 * install a non default variable with this daemon version
556 (void) sprintf(line, "daemon_version=\"%s\"", Version);
557 set_sys_var(line, strlen(line)+1, RO);
560 * Say how we're setting the time of day
562 (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
563 set_sys_var(line, strlen(line)+1, RO);
566 * Initialize the loop.
568 loop_config(LOOP_DRIFTINIT, 0.);
570 getCmdOpts(argc, argv);
573 (fp[0] = fopen(FindConfig(config_file), "r")) == NULL
575 /* If there is no config_file, try NetInfo. */
576 && check_netinfo && !(config_netinfo = get_netinfo_config())
577 #endif /* HAVE_NETINFO */
579 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
580 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
582 /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
584 if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) {
587 * Broadcast clients can sometimes run without
588 * a configuration file.
591 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
592 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
595 #else /* not SYS_WINNT */
597 #endif /* not SYS_WINNT */
600 proto_config(PROTO_MONITOR, 0, 0., NULL);
603 if (tok == CONFIG_END)
605 if (fp[includelevel])
606 tok = gettokens(fp[includelevel], line, tokens, &ntokens);
609 tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
610 #endif /* HAVE_NETINFO */
612 if (tok == CONFIG_UNKNOWN) {
613 if (includelevel > 0) {
614 fclose(fp[includelevel--]);
624 case CONFIG_MANYCASTCLIENT:
625 case CONFIG_BROADCAST:
626 if (tok == CONFIG_PEER)
628 else if (tok == CONFIG_SERVER)
630 else if (tok == CONFIG_MANYCASTCLIENT)
633 hmode = MODE_BROADCAST;
637 "No address for %s, line ignored",
643 memset((char *)&peeraddr, 0, sizeof(peeraddr));
644 peeraddr.ss_family = default_ai_family;
645 switch (matchkey(tokens[istart], addr_type, 0)) {
647 peeraddr.ss_family = AF_INET;
651 peeraddr.ss_family = AF_INET6;
656 status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK);
658 break; /* Found IPv6 address */
666 !ISREFCLOCKADR(&peeraddr) &&
668 ISBADADR(&peeraddr)) {
670 "attempt to configure invalid address %s",
675 * Shouldn't be able to specify multicast
676 * address for server/peer!
677 * and unicast address for manycastclient!
679 if (peeraddr.ss_family == AF_INET) {
680 if (((tok == CONFIG_SERVER) ||
681 (tok == CONFIG_PEER)) &&
683 !ISREFCLOCKADR(&peeraddr) &&
685 IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
687 "attempt to configure invalid address %s",
691 if ((tok == CONFIG_MANYCASTCLIENT) &&
692 !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) {
694 "attempt to configure invalid address %s",
699 else if(peeraddr.ss_family == AF_INET6) {
700 if (((tok == CONFIG_SERVER) ||
701 (tok == CONFIG_PEER)) &&
703 !ISREFCLOCKADR(&peeraddr) &&
705 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
707 "attempt to configure in valid address %s",
711 if ((tok == CONFIG_MANYCASTCLIENT) &&
712 !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) {
714 "attempt to configure in valid address %s",
720 if (peeraddr.ss_family == AF_INET6 &&
721 isc_net_probeipv6() != ISC_R_SUCCESS)
724 peerversion = NTP_VERSION;
725 minpoll = NTP_MINDPOLL;
726 maxpoll = NTP_MAXDPOLL;
728 peerkeystr = (u_char *)"*";
732 for (i = istart; i < ntokens; i++)
733 switch (matchkey(tokens[i], mod_keywords, 1)) {
734 case CONF_MOD_VERSION:
735 if (i >= ntokens-1) {
737 "peer/server version requires an argument");
741 peerversion = atoi(tokens[++i]);
742 if ((u_char)peerversion > NTP_VERSION
743 || (u_char)peerversion < NTP_OLDVERSION) {
745 "inappropriate version number %s, line ignored",
752 if (i >= ntokens-1) {
754 "key: argument required");
758 peerkey = (int)atol(tokens[++i]);
759 peerflags |= FLAG_AUTHENABLE;
762 case CONF_MOD_MINPOLL:
763 if (i >= ntokens-1) {
765 "minpoll: argument required");
769 minpoll = atoi(tokens[++i]);
770 if (minpoll < NTP_MINPOLL) {
772 "minpoll: provided value (%d) is below minimum (%d)",
773 minpoll, NTP_MINPOLL);
774 minpoll = NTP_MINPOLL;
778 case CONF_MOD_MAXPOLL:
779 if (i >= ntokens-1) {
781 "maxpoll: argument required"
786 maxpoll = atoi(tokens[++i]);
787 if (maxpoll > NTP_MAXPOLL) {
789 "maxpoll: provided value (%d) is above maximum (%d)",
790 maxpoll, NTP_MAXPOLL);
791 maxpoll = NTP_MAXPOLL;
795 case CONF_MOD_PREFER:
796 peerflags |= FLAG_PREFER;
799 case CONF_MOD_PREEMPT:
800 peerflags |= FLAG_PREEMPT;
803 case CONF_MOD_NOSELECT:
804 peerflags |= FLAG_NOSELECT;
808 peerflags |= FLAG_TRUE;
811 peerflags |= FLAG_BURST;
814 case CONF_MOD_IBURST:
815 peerflags |= FLAG_IBURST;
818 case CONF_MOD_DYNAMIC:
820 "Warning: the \"dynamic\" keyword has been obsoleted"
821 " and will be removed in the next release\n");
826 peerflags |= FLAG_SKEY |
832 if (i >= ntokens-1) {
834 "ttl: argument required");
838 ttl = atoi(tokens[++i]);
839 if (ttl >= MAX_TTL) {
841 "ttl: invalid argument");
847 if (i >= ntokens-1) {
849 "mode: argument required");
853 ttl = atoi(tokens[++i]);
860 if (minpoll > maxpoll) {
862 "config error: minpoll > maxpoll");
866 if (peer_config(&peeraddr,
867 ANY_INTERFACE_CHOOSE(&peeraddr), hmode,
868 peerversion, minpoll, maxpoll, peerflags,
869 ttl, peerkey, peerkeystr) == 0) {
871 "configuration of %s failed",
874 } else if (errflg == -1) {
875 save_resolve(tokens[istart - 1], hmode, peerversion,
876 minpoll, maxpoll, peerflags, ttl,
877 peerkey, peerkeystr, peeraddr.ss_family);
881 case CONFIG_DRIFTFILE:
883 stats_config(STATS_FREQ_FILE, tokens[1]);
885 stats_config(STATS_FREQ_FILE, (char *)0);
886 stats_write_period = stats_write_tolerance = 0;
888 stats_write_period = 60 * atol(tokens[2]);
889 if (stats_write_period <= 0)
890 stats_write_period = 3600;
893 sscanf(tokens[3], "%lf", &ftemp);
894 stats_write_tolerance = ftemp / 100;
900 stats_config(STATS_PID_FILE, tokens[1]);
902 stats_config(STATS_PID_FILE, (char *)0);
906 for ( i = 0; i <= includelevel; i++ ) {
911 case CONFIG_INCLUDEFILE:
913 msyslog(LOG_ERR, "includefile needs one argument");
916 if (includelevel >= MAXINCLUDELEVEL) {
917 fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
918 msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
921 includefile = fopen(FindConfig(tokens[1]), "r");
922 if (includefile == NULL) {
923 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
924 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
927 fp[++includelevel] = includefile;
934 new_file = fopen(tokens[1], "a");
935 if (new_file != NULL) {
936 NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
937 msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
938 if (syslog_file != NULL &&
939 fileno(syslog_file) != fileno(new_file))
940 (void)fclose(syslog_file);
942 syslog_file = new_file;
947 "Cannot open log file %s",
951 msyslog(LOG_ERR, "logfile needs one argument");
954 case CONFIG_LOGCONFIG:
955 for (i = 1; i < ntokens; i++)
959 char * s = &tokens[i][0];
974 ntp_syslogmask = get_logmask(s);
977 ntp_syslogmask |= get_logmask(s);
979 ntp_syslogmask &= ~get_logmask(s);
984 printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
989 case CONFIG_BROADCASTCLIENT:
991 proto_config(PROTO_BROADCLIENT, 1, 0., NULL);
993 proto_config(PROTO_BROADCLIENT, 2, 0., NULL);
997 case CONFIG_MULTICASTCLIENT:
998 case CONFIG_MANYCASTSERVER:
1001 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1002 peeraddr.ss_family = default_ai_family;
1003 switch (matchkey(tokens[istart],
1005 case CONF_ADDR_IPV4:
1006 peeraddr.ss_family = AF_INET;
1009 case CONF_ADDR_IPV6:
1010 peeraddr.ss_family = AF_INET6;
1015 * Abuse maskaddr to store the prefered ip
1018 memset((char *)&maskaddr, 0, sizeof(maskaddr));
1019 maskaddr.ss_family = peeraddr.ss_family;
1021 for (i = istart; i < ntokens; i++) {
1022 memset((char *)&peeraddr, 0,
1024 peeraddr.ss_family = maskaddr.ss_family;
1025 if (getnetnum(tokens[i], &peeraddr, 1,
1027 proto_config(PROTO_MULTICAST_ADD,
1031 proto_config(PROTO_MULTICAST_ADD,
1033 if (tok == CONFIG_MULTICASTCLIENT)
1034 proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL);
1035 else if (tok == CONFIG_MANYCASTSERVER)
1036 sys_manycastserver = 1;
1041 getauthkeys(tokens[1]);
1045 case CONFIG_KEYSDIR:
1048 "Keys directory name required");
1051 keysdir = (char *)emalloc(strlen(tokens[1]) + 1);
1052 strcpy(keysdir, tokens[1]);
1056 for (i = 1; i < ntokens; i++) {
1060 temp = matchkey(tokens[i++], tinker_keywords, 1);
1061 if (i > ntokens - 1) {
1063 "tinker: missing argument");
1067 sscanf(tokens[i], "%lf", &ftemp);
1070 case CONF_CLOCK_MAX:
1071 loop_config(LOOP_MAX, ftemp);
1074 case CONF_CLOCK_PANIC:
1075 loop_config(LOOP_PANIC, ftemp);
1078 case CONF_CLOCK_PHI:
1079 loop_config(LOOP_PHI, ftemp);
1082 case CONF_CLOCK_MINSTEP:
1083 loop_config(LOOP_MINSTEP, ftemp);
1086 case CONF_CLOCK_ALLAN:
1087 loop_config(LOOP_ALLAN, ftemp);
1090 case CONF_CLOCK_HUFFPUFF:
1091 loop_config(LOOP_HUFFPUFF, ftemp);
1094 case CONF_CLOCK_FREQ:
1095 loop_config(LOOP_FREQ, ftemp);
1102 for (i = 1; i < ntokens; i++) {
1106 temp = matchkey(tokens[i++], tos_keywords, 1);
1107 if (i > ntokens - 1) {
1109 "tos: missing argument");
1113 sscanf(tokens[i], "%lf", &ftemp);
1116 case CONF_TOS_MINCLOCK:
1117 proto_config(PROTO_MINCLOCK, 0, ftemp, NULL);
1120 case CONF_TOS_MAXCLOCK:
1121 proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL);
1124 case CONF_TOS_MINSANE:
1125 proto_config(PROTO_MINSANE, 0, ftemp, NULL);
1128 case CONF_TOS_FLOOR:
1129 proto_config(PROTO_FLOOR, 0, ftemp, NULL);
1132 case CONF_TOS_CEILING:
1133 proto_config(PROTO_CEILING, 0, ftemp, NULL);
1136 case CONF_TOS_COHORT:
1137 proto_config(PROTO_COHORT, 0, ftemp, NULL);
1140 case CONF_TOS_MINDISP:
1141 proto_config(PROTO_MINDISP, 0, ftemp, NULL);
1144 case CONF_TOS_MAXDIST:
1145 proto_config(PROTO_MAXDIST, 0, ftemp, NULL);
1148 case CONF_TOS_MAXHOP:
1149 proto_config(PROTO_MAXHOP, 0, ftemp, NULL);
1152 case CONF_TOS_ORPHAN:
1153 proto_config(PROTO_ORPHAN, 0, ftemp, NULL);
1156 case CONF_TOS_BEACON:
1157 proto_config(PROTO_BEACON, 0, ftemp, NULL);
1164 for (i = 1; i < ntokens && i < MAX_TTL; i++) {
1165 sys_ttl[i - 1] = (u_char) atoi(tokens[i]);
1170 case CONFIG_DISCARD:
1171 for (i = 1; i < ntokens; i++) {
1174 temp = matchkey(tokens[i++],
1175 discard_keywords, 1);
1176 if (i > ntokens - 1) {
1178 "discard: missing argument");
1183 case CONF_DISCARD_AVERAGE:
1184 res_avg_interval = atoi(tokens[i]);
1187 case CONF_DISCARD_MINIMUM:
1188 res_min_interval = atoi(tokens[i]);
1191 case CONF_DISCARD_MONITOR:
1192 mon_age = atoi(tokens[i]);
1197 "discard: unknown keyword");
1206 sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE);
1209 case CONFIG_AUTOMAX:
1211 sys_automax = 1 << max(atoi(tokens[1]), 10);
1216 crypto_config(CRYPTO_CONF_NONE, NULL);
1219 for (i = 1; i < ntokens; i++) {
1222 temp = matchkey(tokens[i++],
1223 crypto_keywords, 1);
1224 if (i > ntokens - 1) {
1226 "crypto: missing argument");
1232 case CONF_CRYPTO_CERT:
1233 crypto_config(CRYPTO_CONF_CERT,
1237 case CONF_CRYPTO_RSA:
1238 crypto_config(CRYPTO_CONF_PRIV,
1242 case CONF_CRYPTO_IDENT:
1243 crypto_config(CRYPTO_CONF_IDENT,
1247 case CONF_CRYPTO_IFFPAR:
1248 crypto_config(CRYPTO_CONF_IFFPAR,
1252 case CONF_CRYPTO_GQPAR:
1253 crypto_config(CRYPTO_CONF_GQPAR,
1257 case CONF_CRYPTO_MVPAR:
1258 crypto_config(CRYPTO_CONF_MVPAR,
1262 case CONF_CRYPTO_LEAP:
1263 crypto_config(CRYPTO_CONF_LEAP,
1267 case CONF_CRYPTO_PW:
1268 crypto_config(CRYPTO_CONF_PW,
1272 case CONF_CRYPTO_RAND:
1273 crypto_config(CRYPTO_CONF_RAND,
1277 case CONF_CRYPTO_SIGN:
1278 crypto_config(CRYPTO_CONF_SIGN,
1284 "crypto: unknown keyword");
1289 #endif /* OPENSSL */
1291 case CONFIG_RESTRICT:
1293 msyslog(LOG_ERR, "restrict requires an address");
1297 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1298 peeraddr.ss_family = default_ai_family;
1299 switch (matchkey(tokens[istart], addr_type, 0)) {
1300 case CONF_ADDR_IPV4:
1301 peeraddr.ss_family = AF_INET;
1304 case CONF_ADDR_IPV6:
1305 peeraddr.ss_family = AF_INET6;
1311 * Assume default means an IPv4 address, except
1312 * if forced by a -4 or -6.
1314 if (STREQ(tokens[istart], "default")) {
1315 if (peeraddr.ss_family == 0)
1316 peeraddr.ss_family = AF_INET;
1317 } else if (getnetnum(tokens[istart], &peeraddr, 1,
1322 * Use peerversion as flags, peerkey as mflags. Ick.
1327 SET_HOSTMASK(&maskaddr, peeraddr.ss_family);
1329 for (i = istart; i < ntokens; i++) {
1330 switch (matchkey(tokens[i], res_keywords, 1)) {
1332 if (i >= ntokens-1) {
1334 "mask keyword needs argument");
1339 if (getnetnum(tokens[i], &maskaddr, 1,
1344 case CONF_RES_IGNORE:
1345 peerversion |= RES_IGNORE;
1348 case CONF_RES_NOSERVE:
1349 peerversion |= RES_DONTSERVE;
1352 case CONF_RES_NOTRUST:
1353 peerversion |= RES_DONTTRUST;
1356 case CONF_RES_NOQUERY:
1357 peerversion |= RES_NOQUERY;
1360 case CONF_RES_NOMODIFY:
1361 peerversion |= RES_NOMODIFY;
1364 case CONF_RES_NOPEER:
1365 peerversion |= RES_NOPEER;
1368 case CONF_RES_NOTRAP:
1369 peerversion |= RES_NOTRAP;
1372 case CONF_RES_LPTRAP:
1373 peerversion |= RES_LPTRAP;
1376 case CONF_RES_NTPPORT:
1377 peerkey |= RESM_NTPONLY;
1380 case CONF_RES_VERSION:
1381 peerversion |= RES_VERSION;
1384 case CONF_RES_DEMOBILIZE:
1385 peerversion |= RES_DEMOBILIZE;
1388 case CONF_RES_LIMITED:
1389 peerversion |= RES_LIMITED;
1392 case CONFIG_UNKNOWN:
1397 if (SOCKNUL(&peeraddr))
1400 hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
1401 (int)peerkey, peerversion);
1408 if (sscanf(tokens[1], "%lf", &tmp) != 1) {
1410 "broadcastdelay value %s undecodable",
1413 proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
1422 if (sscanf(tokens[1], "%ld", &ui) != 1)
1424 "illegal value - line ignored");
1426 proto_config(PROTO_CALLDELAY, ui, 0, NULL);
1430 case CONFIG_TRUSTEDKEY:
1431 for (i = 1; i < ntokens; i++) {
1434 tkey = atol(tokens[i]);
1437 "trusted key %s unlikely",
1445 case CONFIG_REQUESTKEY:
1447 if (!atouint(tokens[1], &ul)) {
1449 "%s is undecodable as request key",
1451 } else if (ul == 0) {
1453 "%s makes a poor request keyid",
1459 "set info_auth_key to %08lx\n", ul);
1461 info_auth_keyid = (keyid_t)ul;
1466 case CONFIG_CONTROLKEY:
1470 ckey = atol(tokens[1]);
1473 "%s makes a poor control keyid",
1476 ctl_auth_keyid = ckey;
1484 "no address for trap command, line ignored");
1488 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1489 peeraddr.ss_family = default_ai_family;
1490 switch (matchkey(tokens[istart], addr_type, 0)) {
1491 case CONF_ADDR_IPV4:
1492 peeraddr.ss_family = AF_INET;
1495 case CONF_ADDR_IPV6:
1496 peeraddr.ss_family = AF_INET6;
1501 if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1)
1505 * Use peerversion for port number. Barf.
1511 for (i = istart; i < ntokens-1; i++)
1512 switch (matchkey(tokens[i], trap_keywords, 1)) {
1513 case CONF_TRAP_PORT:
1514 if (i >= ntokens-1) {
1516 "trap port requires an argument");
1520 peerversion = atoi(tokens[++i]);
1521 if (peerversion <= 0
1522 || peerversion > 32767) {
1524 "invalid port number %s, trap ignored",
1530 case CONF_TRAP_INTERFACE:
1531 if (i >= ntokens-1) {
1533 "trap interface requires an argument");
1538 memset((char *)&maskaddr, 0,
1540 maskaddr.ss_family = peeraddr.ss_family;
1541 if (getnetnum(tokens[++i],
1542 &maskaddr, 1, t_UNK) != 1) {
1547 localaddr = findinterface(&maskaddr);
1548 if (localaddr == NULL) {
1550 "can't find interface with address %s",
1556 case CONFIG_UNKNOWN:
1562 if (peerversion != 0)
1563 ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion);
1565 ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT);
1566 if (localaddr == NULL)
1567 localaddr = ANY_INTERFACE_CHOOSE(&peeraddr);
1568 if (!ctlsettrap(&peeraddr, localaddr, 0,
1571 "can't set trap for %s, no resources",
1579 "no address for fudge command, line ignored");
1582 memset((char *)&peeraddr, 0, sizeof(peeraddr));
1583 if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1)
1586 if (!ISREFCLOCKADR(&peeraddr)) {
1588 "%s is inappropriate address for the fudge command, line ignored",
1593 memset((void *)&clock_stat, 0, sizeof clock_stat);
1596 for (i = 2; i < ntokens-1; i++) {
1597 switch (c = matchkey(tokens[i],
1598 fudge_keywords, 1)) {
1599 case CONF_FDG_TIME1:
1600 if (sscanf(tokens[++i], "%lf",
1601 &clock_stat.fudgetime1) != 1) {
1603 "fudge %s time1 value in error",
1608 clock_stat.haveflags |= CLK_HAVETIME1;
1611 case CONF_FDG_TIME2:
1612 if (sscanf(tokens[++i], "%lf",
1613 &clock_stat.fudgetime2) != 1) {
1615 "fudge %s time2 value in error",
1620 clock_stat.haveflags |= CLK_HAVETIME2;
1624 case CONF_FDG_STRATUM:
1625 if (!atoint(tokens[++i], &stratum))
1628 "fudge %s stratum value in error",
1633 clock_stat.fudgeval1 = stratum;
1634 clock_stat.haveflags |= CLK_HAVEVAL1;
1637 case CONF_FDG_REFID:
1639 memcpy(&clock_stat.fudgeval2,
1640 tokens[i], min(strlen(tokens[i]),
1642 clock_stat.haveflags |= CLK_HAVEVAL2;
1645 case CONF_FDG_FLAG1:
1646 case CONF_FDG_FLAG2:
1647 case CONF_FDG_FLAG3:
1648 case CONF_FDG_FLAG4:
1649 if (!atouint(tokens[++i], &fudgeflag)
1652 "fudge %s flag value in error",
1658 case CONF_FDG_FLAG1:
1660 clock_stat.haveflags|=CLK_HAVEFLAG1;
1662 case CONF_FDG_FLAG2:
1664 clock_stat.haveflags|=CLK_HAVEFLAG2;
1666 case CONF_FDG_FLAG3:
1668 clock_stat.haveflags|=CLK_HAVEFLAG3;
1670 case CONF_FDG_FLAG4:
1672 clock_stat.haveflags|=CLK_HAVEFLAG4;
1676 clock_stat.flags &= ~c;
1678 clock_stat.flags |= c;
1681 case CONFIG_UNKNOWN:
1689 * If reference clock support isn't defined the
1690 * fudge line will still be accepted and syntax
1691 * checked, but will essentially do nothing.
1694 refclock_control(&peeraddr, &clock_stat,
1695 (struct refclockstat *)0);
1700 case CONFIG_STATSDIR:
1702 stats_config(STATS_STATSDIR,tokens[1]);
1705 case CONFIG_STATISTICS:
1706 for (i = 1; i < ntokens; i++) {
1707 filegen = filegen_get(tokens[i]);
1709 if (filegen == NULL) {
1711 "no statistics named %s available",
1717 printf("enabling filegen for %s statistics \"%s%s\"\n",
1718 tokens[i], filegen->prefix, filegen->basename);
1720 filegen->flag |= FGEN_FLAG_ENABLED;
1724 case CONFIG_FILEGEN:
1727 "no id for filegen command, line ignored");
1731 filegen = filegen_get(tokens[1]);
1732 if (filegen == NULL) {
1734 "unknown filegen \"%s\" ignored",
1739 * peerversion is (ab)used for filegen file (index)
1740 * peerkey is (ab)used for filegen type
1741 * peerflags is (ab)used for filegen flags
1744 peerkey = filegen->type;
1745 peerflags = filegen->flag;
1748 for (i = 2; i < ntokens; i++) {
1749 switch (matchkey(tokens[i],
1750 filegen_keywords, 1)) {
1751 case CONF_FGEN_FILE:
1752 if (i >= ntokens - 1) {
1754 "filegen %s file requires argument",
1761 case CONF_FGEN_TYPE:
1762 if (i >= ntokens -1) {
1764 "filegen %s type requires argument",
1769 peerkey = matchkey(tokens[++i],
1771 if (peerkey == CONFIG_UNKNOWN) {
1773 "filegen %s unknown type \"%s\"",
1774 tokens[1], tokens[i]);
1780 case CONF_FGEN_FLAG_LINK:
1781 peerflags |= FGEN_FLAG_LINK;
1784 case CONF_FGEN_FLAG_NOLINK:
1785 peerflags &= ~FGEN_FLAG_LINK;
1788 case CONF_FGEN_FLAG_ENABLE:
1789 peerflags |= FGEN_FLAG_ENABLED;
1792 case CONF_FGEN_FLAG_DISABLE:
1793 peerflags &= ~FGEN_FLAG_ENABLED;
1798 filegen_config(filegen, tokens[peerversion],
1799 (u_char)peerkey, (u_char)peerflags);
1805 "no value for setvar command - line ignored");
1807 set_sys_var(tokens[1], strlen(tokens[1])+1,
1810 && !strcmp(tokens[2],
1818 for (i = 1; i < ntokens; i++) {
1821 flag = matchkey(tokens[i], flags_keywords, 1);
1822 if (flag == CONFIG_UNKNOWN) {
1824 "enable unknown flag %s",
1829 proto_config(flag, 1, 0., NULL);
1833 case CONFIG_DISABLE:
1834 for (i = 1; i < ntokens; i++) {
1837 flag = matchkey(tokens[i], flags_keywords, 1);
1838 if (flag == CONFIG_UNKNOWN) {
1840 "disable unknown flag %s",
1845 proto_config(flag, 0, 0., NULL);
1850 for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) {
1852 emalloc(strlen(tokens[i]) + 1);
1853 strcpy(sys_phone[i - 1], tokens[i]);
1855 sys_phone[i] = NULL;
1861 sscanf(tokens[1], "%lf", &ftemp);
1862 proto_config(PROTO_ADJ, 0, ftemp, NULL);
1869 (void)fclose(fp[0]);
1873 free_netinfo_config(config_netinfo);
1874 #endif /* HAVE_NETINFO */
1876 #if !defined(VMS) && !defined(SYS_VXWORKS)
1878 if (info_auth_keyid == 0)
1881 req_keyid = info_auth_keyid;
1883 /* if doesn't exist, make up one at random */
1884 if (!authhavekey(req_keyid)) {
1888 for (i = 0; i < 8; i++)
1889 for (j = 1; j < 100; ++j) {
1890 rankey[i] = (char) (ntp_random() & 0xff);
1891 if (rankey[i] != 0) break;
1894 authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
1895 authtrust(req_keyid, 1);
1896 if (!authhavekey(req_keyid)) {
1897 msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
1898 /* HMS: Should this be fatal? */
1902 /* save keyid so we will accept config requests with it */
1903 info_auth_keyid = req_keyid;
1904 #endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
1906 if (res_fp != NULL) {
1907 if (call_resolver) {
1909 * Need name resolution
1911 do_resolve_internal();
1920 * get_netinfo_config - find the nearest NetInfo domain with an ntp
1921 * configuration and initialize the configuration state.
1923 static struct netinfo_config_state *
1924 get_netinfo_config()
1929 struct netinfo_config_state *config;
1931 if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
1933 while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
1935 if (ni_open(domain, "..", &next_domain) != NI_OK) {
1936 ni_free(next_domain);
1940 domain = next_domain;
1942 if (status != NI_OK) {
1947 config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
1948 config->domain = domain;
1949 config->config_dir = config_dir;
1950 config->prop_index = 0;
1951 config->val_index = 0;
1952 config->val_list = NULL;
1960 * free_netinfo_config - release NetInfo configuration state
1963 free_netinfo_config(struct netinfo_config_state *config)
1965 ni_free(config->domain);
1972 * gettokens_netinfo - return tokens from NetInfo
1976 struct netinfo_config_state *config,
1981 int prop_index = config->prop_index;
1982 int val_index = config->val_index;
1983 char **val_list = config->val_list;
1986 * Iterate through each keyword and look for a property that matches it.
1990 for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
1992 ni_namelist namelist;
1993 struct keyword current_prop = keywords[prop_index];
1996 * For each value associated in the property, we're going to return
1997 * a separate line. We squirrel away the values in the config state
1998 * so the next time through, we don't need to do this lookup.
2001 if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
2004 /* Found the property, but it has no values */
2005 if (namelist.ni_namelist_len == 0) continue;
2007 if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
2008 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
2010 for (index = 0; index < namelist.ni_namelist_len; index++) {
2011 char *value = namelist.ni_namelist_val[index];
2013 if (! (val_list[index] = (char*)malloc(strlen(value)+1)))
2014 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
2016 strcpy(val_list[index], value);
2018 val_list[index] = NULL;
2022 ni_namelist_free(&namelist);
2024 config->prop_index = prop_index;
2027 /* No list; we're done here. */
2028 if (!val_list) return CONFIG_UNKNOWN;
2031 * We have a list of values for the current property.
2032 * Iterate through them and return each in order.
2034 if (val_list[val_index])
2038 char *tokens = val_list[val_index];
2040 msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
2042 (const char*)tokenlist[0] = keywords[prop_index].text;
2043 for (ntok = 1; ntok < MAXTOKENS; ntok++) {
2044 tokenlist[ntok] = tokens;
2045 while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
2046 quoted ^= (*tokens++ == '"');
2048 if (ISEOL(*tokens)) {
2051 } else { /* must be space */
2053 while (ISSPACE(*tokens)) tokens++;
2054 if (ISEOL(*tokens)) break;
2058 if (ntok == MAXTOKENS) {
2059 /* HMS: chomp it to lose the EOL? */
2061 "gettokens_netinfo: too many tokens. Ignoring: %s",
2064 *ntokens = ntok + 1;
2067 config->val_index++; /* HMS: Should this be in the 'else'? */
2069 return keywords[prop_index].keytype;
2072 /* We're done with the current property. */
2073 prop_index = ++config->prop_index;
2075 /* Free val_list and reset counters. */
2076 for (val_index = 0; val_list[val_index]; val_index++)
2077 free(val_list[val_index]);
2078 free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0;
2083 #endif /* HAVE_NETINFO */
2087 * gettokens - read a line and return tokens
2099 register int quoted = 0;
2102 * Find start of first token
2105 while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
2107 while (ISSPACE(*cp))
2114 return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
2118 * Now separate out the tokens
2120 for (ntok = 0; ntok < MAXTOKENS; ntok++) {
2121 tokenlist[ntok] = cp;
2122 while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
2123 quoted ^= (*cp++ == '"');
2128 } else { /* must be space */
2130 while (ISSPACE(*cp))
2137 /* Heiko: Remove leading and trailing quotes around tokens */
2142 for (i = 0; i < ntok; i++) {
2143 /* Now check if the first char is a quote and remove that */
2144 if ( tokenlist[ntok][0] == '"' )
2147 /* Now check the last char ... */
2148 j = strlen(tokenlist[ntok])-1;
2149 if ( tokenlist[ntok][j] == '"' )
2150 tokenlist[ntok][j] = '\0';
2155 if (ntok == MAXTOKENS) {
2157 /* HMS: chomp it to lose the EOL? */
2159 "gettokens: too many tokens on the line. Ignoring %s",
2165 *ntokens = ntok + 1;
2166 ntok = matchkey(tokenlist[0], keywords, 1);
2167 if (ntok == CONFIG_UNKNOWN)
2177 * matchkey - match a keyword to a list
2181 register char *word,
2182 register struct keyword *keys,
2187 if (keys->keytype == CONFIG_UNKNOWN) {
2190 "configure: keyword \"%s\" unknown, line ignored",
2192 return CONFIG_UNKNOWN;
2194 if (STRSAME(word, keys->text))
2195 return keys->keytype;
2202 * getnetnum - return a net number (this is crude, but careful)
2207 struct sockaddr_storage *addr,
2209 enum gnn_type a_type
2212 struct addrinfo hints;
2213 struct addrinfo *ptr;
2217 printf("getnetnum: <%s> is a %s (%d)\n",
2229 /* Get host address. Looking for UDP datagram connection */
2230 memset(&hints, 0, sizeof (hints));
2231 if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6)
2232 hints.ai_family = addr->ss_family;
2234 hints.ai_family = AF_UNSPEC;
2236 * If we don't have an IPv6 stack, just look up IPv4 addresses
2238 if (isc_net_probeipv6() != ISC_R_SUCCESS)
2239 hints.ai_family = AF_INET;
2241 hints.ai_socktype = SOCK_DGRAM;
2243 if (a_type != t_UNK) {
2244 hints.ai_flags = AI_NUMERICHOST;
2249 printf("getnetnum: calling getaddrinfo(%s,...)\n", num);
2251 retval = getaddrinfo(num, "ntp", &hints, &ptr);
2253 (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) {
2256 "getaddrinfo: \"%s\" invalid host address, ignored",
2261 "getaddrinfo: \"%s\" invalid host address%s.\n",
2267 ptr->ai_family == AF_INET6 &&
2268 isc_net_probeipv6() != ISC_R_SUCCESS)
2277 memcpy(addr, ptr->ai_addr, ptr->ai_addrlen);
2280 printf("getnetnum given %s, got %s (%s/%d)\n",
2296 #if !defined(VMS) && !defined(SYS_WINNT)
2298 * catchchild - receive the resolver's exit status
2306 * We only start up one child, and if we're here
2307 * it should have already exited. Hence the following
2308 * shouldn't hang. If it does, please tell me.
2310 #if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
2312 #endif /* SYS_WINNT && VXWORKS*/
2318 * save_resolve - save configuration info into a file for later name resolution
2335 if (res_fp == NULL) {
2337 (void) strcpy(res_file, RES_TEMPFILE);
2339 /* no /tmp directory under NT */
2341 if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
2342 msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
2345 (void) strcat(res_file, "ntpdXXXXXX");
2347 #endif /* SYS_WINNT */
2353 if ((fd = mkstemp(res_file)) != -1)
2354 res_fp = fdopen(fd, "r+");
2357 (void) mktemp(res_file);
2358 res_fp = fopen(res_file, "w");
2360 if (res_fp == NULL) {
2361 msyslog(LOG_ERR, "open failed for %s: %m", res_file);
2367 printf("resolving %s\n", name);
2371 (void)fprintf(res_fp, "%s %u %d %d %d %d %d %d %u %s\n", name, peeraf,
2372 mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2375 printf("config: %s %u %d %d %d %d %x %d %u %s\n", name, peeraf, mode,
2376 version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2379 #else /* SYS_VXWORKS */
2380 /* save resolve info to a struct */
2381 #endif /* SYS_VXWORKS */
2386 * abort_resolve - terminate the resolver stuff and delete the file
2392 * In an ideal world we would might reread the file and
2393 * log the hosts which aren't getting configured. Since
2394 * this is too much work, however, just close and delete
2398 (void) fclose(res_fp);
2401 #ifndef SYS_VXWORKS /* we don't open the file to begin with */
2403 (void) unlink(res_file);
2405 (void) delete(res_file);
2407 #endif /* SYS_VXWORKS */
2412 * do_resolve_internal - start up the resolver function (not program)
2415 * On VMS, this routine will simply refuse to resolve anything.
2417 * Possible implementation: keep `res_file' in memory, do async
2418 * name resolution via QIO, update from within completion AST.
2419 * I'm unlikely to find the time for doing this, though. -wjm
2422 do_resolve_internal(void)
2426 if (res_fp == NULL) {
2429 "do_resolve_internal: Fatal: res_fp == NULL");
2433 /* we are done with this now */
2434 (void) fclose(res_fp);
2437 #if !defined(VMS) && !defined (SYS_VXWORKS)
2438 req_file = res_file; /* set up pointer to res file */
2440 (void) signal_no_reset(SIGCHLD, catchchild);
2443 /* the parent process will write to the pipe
2444 * in order to wake up to child process
2445 * which may be waiting in a select() call
2447 if (pipe(resolver_pipe_fd) < 0) {
2449 "unable to open resolver pipe");
2454 /* Shouldn't the code below be re-ordered?
2455 * I.e. first check if the fork() returned an error, then
2456 * check whether we're parent or child.
2461 * this used to close everything
2462 * I don't think this is necessary
2465 * To the unknown commenter above:
2466 * Well, I think it's better to clean up
2467 * after oneself. I have had problems with
2468 * refclock-io when intres was running - things
2469 * where fine again when ntpintres was gone.
2470 * So some systems react erratic at least.
2475 * Further debugging has proven that the above is
2476 * absolutely harmful. The internal resolver
2477 * is still in the SIGIO process group and the lingering
2478 * async io information causes it to process requests from
2479 * all file decriptor causing a race between the NTP daemon
2480 * and the resolver. which then eats data when it wins 8-(.
2481 * It is absolutly necessary to kill any IO associations
2482 * shared with the NTP daemon.
2484 * We also block SIGIO (currently no ports means to
2485 * disable the signal handle for IO).
2487 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
2488 * that it is the ntp-resolver child running into trouble.
2493 /* This is the child process who will read the pipe,
2494 * so we close the write fd */
2495 close(resolver_pipe_fd[1]);
2499 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2507 openlog("ntpd_initres", LOG_PID);
2508 # else /* LOG_DAEMON */
2511 # define LOG_NTP LOG_DAEMON
2513 openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
2514 #ifndef SYS_CYGWIN32
2517 setlogmask(LOG_UPTO(LOG_DEBUG));
2520 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
2521 # endif /* LOG_DAEMON */
2527 * If we got here, the intres code screwed up.
2528 * Print something so we don't die without complaint
2530 msyslog(LOG_ERR, "call to ntp_intres lost");
2535 /* vxWorks spawns a thread... -casey */
2536 i = sp (ntp_intres);
2537 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
2540 msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
2541 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2545 /* This is the parent process who will write to the pipe,
2546 * so we close the read fd */
2547 close(resolver_pipe_fd[0]);
2549 #else /* SYS_WINNT */
2551 /* NT's equivalent of fork() is _spawn(), but the start point
2552 * of the new process is an executable filename rather than
2553 * a function name as desired here.
2557 ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
2558 if (ResolverEventHandle == NULL) {
2559 msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
2562 ResolverThreadHandle = CreateThread(
2563 NULL, /* no security attributes */
2564 0, /* use default stack size */
2565 (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */
2566 NULL, /* argument to thread function */
2567 0, /* use default creation flags */
2568 &dwThreadId); /* returns the thread identifier */
2569 if (ResolverThreadHandle == NULL) {
2570 msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
2571 CloseHandle(ResolverEventHandle);
2572 ResolverEventHandle = NULL;
2576 #endif /* SYS_WINNT */
2577 #else /* VMS VX_WORKS */
2579 "Name resolution not implemented for VMS - use numeric addresses");
2581 #endif /* VMS VX_WORKS */