Deleted Added
sdiff udiff text old ( 106163 ) new ( 132451 )
full compact
1/*
2 * ntp_config.c - read and apply configuration information
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#ifdef HAVE_NETINFO
9# include <netinfo/ni.h>
10#endif
11
12#include "ntpd.h"
13#include "ntp_io.h"
14#include "ntp_unixtime.h"
15#include "ntp_refclock.h"
16#include "ntp_filegen.h"
17#include "ntp_stdlib.h"
18#include "ntp_config.h"
19#include "ntp_cmdargs.h"
20
21#ifdef PUBKEY
22# include "ntp_crypto.h"
23#endif /* PUBKEY */
24
25#include <stdio.h>
26#include <ctype.h>
27#ifdef HAVE_SYS_PARAM_H
28#include <sys/param.h>
29#endif
30#include <signal.h>
31#ifndef SIGCHLD
32# define SIGCHLD SIGCLD
33#endif
34#if !defined(VMS)
35# ifdef HAVE_SYS_WAIT_H
36# include <sys/wait.h>
37# endif
38#endif /* VMS */
39
40#ifdef SYS_WINNT
41# include <io.h>
42extern HANDLE ResolverThreadHandle;
43#endif /* SYS_WINNT */
44
45extern int priority_done;
46
47/*
48 * These routines are used to read the configuration file at
49 * startup time. An entry in the file must fit on a single line.
50 * Entries are processed as multiple tokens separated by white space
51 * Lines are considered terminated when a '#' is encountered. Blank
52 * lines are ignored.
53 */
54
55/*
56 * We understand the following configuration entries and defaults.
57 *
58 * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
59 * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
60 * broadcast [ addr ] [ version 3 ] [ key 0 ] [ ttl 1 ]
61 * broadcastclient
62 * multicastclient [ 224.0.1.1 ]
63 * manycastclient [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
64 * manycastserver [ 224.0.1.1 ]
65 * broadcastdelay 0.0102
66 * restrict [ addr ] [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery
67 * driftfile file_name
68 * keys file_name
69 * publickey file_name
70 * privatekey file_name
71 * statsdir /var/NTP/
72 * filegen peerstats [ file peerstats ] [ type day ] [ link ]
73 * clientlimit [ n ]
74 * clientperiod [ 3600 ]
75 * trustedkey [ key ]
76 * requestkey [ key]
77 * controlkey [ key ]
78 * trap [ addr ]
79 * fudge [ addr ] [ stratum ] [ refid ] ...
80 * pidfile [ ]
81 * setvar [ ]
82 * logfile logfile
83 * logconfig [+|-|=][{sync|sys|peer|clock}{{,all}{info|statistics|events|status}}]...
84 * enable auth|bclient|pll|kernel|monitor|stats|calibrate
85 * disable auth|bclient|pll|kernel|monitor|stats|calibrate
86 * phone ...
87 * pps device [assert|clear] [hardpps]
88 * priority high|normal
89 */
90
91/*
92 * Translation table - keywords to function index
93 */
94struct keyword {
95 const char *text;
96 int keytype;
97};
98
99/*
100 * Command keywords
101 */
102static struct keyword keywords[] = {
103 { "authenticate", CONFIG_AUTHENTICATE },
104 { "automax", CONFIG_AUTOMAX },
105 { "broadcast", CONFIG_BROADCAST },
106 { "broadcastclient", CONFIG_BROADCASTCLIENT },
107 { "broadcastdelay", CONFIG_BDELAY },
108 { "clientlimit", CONFIG_CLIENTLIMIT },
109 { "clientperiod", CONFIG_CLIENTPERIOD },
110#ifdef PUBKEY
111 { "crypto", CONFIG_CRYPTO },
112#endif /* PUBKEY */
113 { "controlkey", CONFIG_CONTROLKEY },
114 { "disable", CONFIG_DISABLE },
115 { "driftfile", CONFIG_DRIFTFILE },
116 { "enable", CONFIG_ENABLE },
117 { "filegen", CONFIG_FILEGEN },
118 { "fudge", CONFIG_FUDGE },
119 { "includefile", CONFIG_INCLUDEFILE },
120 { "keys", CONFIG_KEYS },
121#ifdef PUBKEY
122 { "keysdir", CONFIG_KEYSDIR },
123#endif /* PUBKEY */
124 { "logconfig", CONFIG_LOGCONFIG },
125 { "logfile", CONFIG_LOGFILE },
126 { "manycastclient", CONFIG_MANYCASTCLIENT },
127 { "manycastserver", CONFIG_MANYCASTSERVER },
128 { "multicastclient", CONFIG_MULTICASTCLIENT },
129 { "peer", CONFIG_PEER },
130 { "phone", CONFIG_PHONE },
131 { "pidfile", CONFIG_PIDFILE },
132 { "pps", CONFIG_PPS },
133 { "requestkey", CONFIG_REQUESTKEY },
134 { "restrict", CONFIG_RESTRICT },
135 { "revoke", CONFIG_REVOKE },
136 { "server", CONFIG_SERVER },
137 { "setvar", CONFIG_SETVAR },
138 { "statistics", CONFIG_STATISTICS },
139 { "statsdir", CONFIG_STATSDIR },
140 { "tinker", CONFIG_TINKER },
141 { "trap", CONFIG_TRAP },
142 { "trustedkey", CONFIG_TRUSTEDKEY },
143 { "", CONFIG_UNKNOWN }
144};
145
146/*
147 * "peer", "server", "broadcast" modifier keywords
148 */
149static struct keyword mod_keywords[] = {
150 { "autokey", CONF_MOD_SKEY },
151 { "burst", CONF_MOD_BURST },
152 { "iburst", CONF_MOD_IBURST },
153 { "key", CONF_MOD_KEY },
154 { "maxpoll", CONF_MOD_MAXPOLL },
155 { "minpoll", CONF_MOD_MINPOLL },
156 { "mode", CONF_MOD_MODE }, /* refclocks */
157 { "noselect", CONF_MOD_NOSELECT },
158 { "prefer", CONF_MOD_PREFER },
159#ifdef PUBKEY
160 { "publickey", CONF_MOD_PUBLICKEY },
161#endif /* PUBKEY */
162 { "ttl", CONF_MOD_TTL }, /* NTP peers */
163 { "version", CONF_MOD_VERSION },
164 { "", CONFIG_UNKNOWN }
165};
166
167/*
168 * "restrict" modifier keywords
169 */
170static struct keyword res_keywords[] = {
171 { "ignore", CONF_RES_IGNORE },
172 { "limited", CONF_RES_LIMITED },
173 { "kod", CONF_RES_DEMOBILIZE },
174 { "lowpriotrap", CONF_RES_LPTRAP },
175 { "mask", CONF_RES_MASK },
176 { "nomodify", CONF_RES_NOMODIFY },
177 { "nopeer", CONF_RES_NOPEER },
178 { "noquery", CONF_RES_NOQUERY },
179 { "noserve", CONF_RES_NOSERVE },
180 { "notrap", CONF_RES_NOTRAP },
181 { "notrust", CONF_RES_NOTRUST },
182 { "ntpport", CONF_RES_NTPPORT },
183 { "version", CONF_RES_VERSION },
184 { "", CONFIG_UNKNOWN }
185};
186
187/*
188 * "trap" modifier keywords
189 */
190static struct keyword trap_keywords[] = {
191 { "port", CONF_TRAP_PORT },
192 { "interface", CONF_TRAP_INTERFACE },
193 { "", CONFIG_UNKNOWN }
194};
195
196/*
197 * "fudge" modifier keywords
198 */
199static struct keyword fudge_keywords[] = {
200 { "flag1", CONF_FDG_FLAG1 },
201 { "flag2", CONF_FDG_FLAG2 },
202 { "flag3", CONF_FDG_FLAG3 },
203 { "flag4", CONF_FDG_FLAG4 },
204 { "refid", CONF_FDG_REFID },
205 { "stratum", CONF_FDG_STRATUM },
206 { "time1", CONF_FDG_TIME1 },
207 { "time2", CONF_FDG_TIME2 },
208 { "", CONFIG_UNKNOWN }
209};
210
211
212/*
213 * "filegen" modifier keywords
214 */
215static struct keyword filegen_keywords[] = {
216 { "disable", CONF_FGEN_FLAG_DISABLE },
217 { "enable", CONF_FGEN_FLAG_ENABLE },
218 { "file", CONF_FGEN_FILE },
219 { "link", CONF_FGEN_FLAG_LINK },
220 { "nolink", CONF_FGEN_FLAG_NOLINK },
221 { "type", CONF_FGEN_TYPE },
222 { "", CONFIG_UNKNOWN }
223};
224
225/*
226 * "type" modifier keywords
227 */
228static struct keyword fgen_types[] = {
229 { "age", FILEGEN_AGE },
230 { "day", FILEGEN_DAY },
231 { "month", FILEGEN_MONTH },
232 { "none", FILEGEN_NONE },
233 { "pid", FILEGEN_PID },
234 { "week", FILEGEN_WEEK },
235 { "year", FILEGEN_YEAR },
236 { "", CONFIG_UNKNOWN}
237};
238
239/*
240 * "enable", "disable" modifier keywords
241 */
242static struct keyword flags_keywords[] = {
243 { "auth", PROTO_AUTHENTICATE },
244 { "bclient", PROTO_BROADCLIENT },
245 { "calibrate", PROTO_CAL },
246 { "kernel", PROTO_KERNEL },
247 { "monitor", PROTO_MONITOR },
248 { "ntp", PROTO_NTP },
249 { "pps", PROTO_PPS },
250 { "stats", PROTO_FILEGEN },
251 { "", CONFIG_UNKNOWN }
252};
253
254/*
255 * "pps" modifier keywords
256 */
257static struct keyword pps_keywords[] = {
258 { "assert", CONF_PPS_ASSERT },
259 { "clear", CONF_PPS_CLEAR },
260 { "hardpps", CONF_PPS_HARDPPS },
261 { "", CONFIG_UNKNOWN }
262};
263
264/*
265 * "tinker" modifier keywords
266 */
267static struct keyword tinker_keywords[] = {
268 { "step", CONF_CLOCK_MAX },
269 { "panic", CONF_CLOCK_PANIC },
270 { "dispersion", CONF_CLOCK_PHI },
271 { "stepout", CONF_CLOCK_MINSTEP },
272 { "minpoll", CONF_CLOCK_MINPOLL },
273 { "allan", CONF_CLOCK_ALLAN },
274 { "huffpuff", CONF_CLOCK_HUFFPUFF },
275 { "", CONFIG_UNKNOWN }
276};
277
278#ifdef PUBKEY
279/*
280 * "crypto" modifier keywords
281 */
282static struct keyword crypto_keywords[] = {
283 { "dh", CONF_CRYPTO_DH },
284 { "flags", CONF_CRYPTO_FLAGS },
285 { "leap", CONF_CRYPTO_LEAP },
286 { "privatekey", CONF_CRYPTO_PRIVATEKEY },
287 { "publickey", CONF_CRYPTO_PUBLICKEY },
288 { "", CONFIG_UNKNOWN }
289};
290#endif /* PUBKEY */
291
292/*
293 * "logconfig" building blocks
294 */
295struct masks {
296 const char *name;
297 unsigned long mask;
298};
299
300static struct masks logcfg_class[] = {
301 { "clock", NLOG_OCLOCK },
302 { "peer", NLOG_OPEER },
303 { "sync", NLOG_OSYNC },
304 { "sys", NLOG_OSYS },
305 { (char *)0, 0 }
306};
307
308static struct masks logcfg_item[] = {
309 { "info", NLOG_INFO },
310 { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO },
311 { "events", NLOG_EVENT },
312 { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT },
313 { "status", NLOG_STATUS },
314 { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS },
315 { "statistics", NLOG_STATIST },
316 { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST },
317 { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK },
318 { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER },
319 { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS },
320 { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC },
321 { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK },
322 { (char *)0, 0 }
323};
324
325/*
326 * Limits on things
327 */
328#define MAXTOKENS 20 /* 20 tokens on line */
329#define MAXLINE 1024 /* maximum length of line */
330#define MAXPHONE 5 /* maximum number of phone strings */
331#define MAXPPS 20 /* maximum length of PPS device string */
332#define MAXINCLUDELEVEL 5 /* maximum include file levels */
333
334/*
335 * Miscellaneous macros
336 */
337#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
338#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
339#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
340#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
341
342#define KEY_TYPE_MD5 4
343
344/*
345 * File descriptor used by the resolver save routines, and temporary file
346 * name.
347 */
348static FILE *res_fp;
349#ifndef SYS_WINNT
350static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */
351#define RES_TEMPFILE "/tmp/ntpXXXXXX"
352#else
353static char res_file[MAX_PATH];
354#endif /* SYS_WINNT */
355
356/*
357 * Definitions of things either imported from or exported to outside
358 */
359char const *progname;
360char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */
361char pps_device[MAXPPS + 1]; /* PPS device name */
362int pps_assert;
363int pps_hardpps;
364#if defined(HAVE_SCHED_SETSCHEDULER)
365int config_priority_override = 0;
366int config_priority;
367#endif
368
369const char *config_file;
370#ifdef HAVE_NETINFO
371 struct netinfo_config_state *config_netinfo = NULL;
372 int check_netinfo = 1;
373#endif /* HAVE_NETINFO */
374#ifdef SYS_WINNT
375 char *alt_config_file;
376 LPTSTR temp;
377 char config_file_storage[MAX_PATH];
378 char alt_config_file_storage[MAX_PATH];
379#endif /* SYS_WINNT */
380
381#ifdef HAVE_NETINFO
382/*
383 * NetInfo configuration state
384 */
385struct netinfo_config_state {
386 void *domain; /* domain with config */
387 ni_id config_dir; /* ID config dir */
388 int prop_index; /* current property */
389 int val_index; /* current value */
390 char **val_list; /* value list */
391};
392#endif
393
394/*
395 * Function prototypes
396 */
397static unsigned long get_pfxmatch P((char **, struct masks *));
398static unsigned long get_match P((char *, struct masks *));
399static unsigned long get_logmask P((char *));
400#ifdef HAVE_NETINFO
401static struct netinfo_config_state *get_netinfo_config P((void));
402static void free_netinfo_config P((struct netinfo_config_state *));
403static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *));
404#endif
405static int gettokens P((FILE *, char *, char **, int *));
406static int matchkey P((char *, struct keyword *));
407static int getnetnum P((const char *, struct sockaddr_in *, int));
408static void save_resolve P((char *, int, int, int, int, u_int, int,
409 keyid_t, u_char *));
410static void do_resolve_internal P((void));
411static void abort_resolve P((void));
412#if !defined(VMS)
413static RETSIGTYPE catchchild P((int));
414#endif /* VMS */
415
416/*
417 * get_pfxmatch - find value for prefixmatch
418 * and update char * accordingly
419 */
420static unsigned long
421get_pfxmatch(
422 char ** s,
423 struct masks *m
424 )
425{
426 while (m->name) {
427 if (strncmp(*s, m->name, strlen(m->name)) == 0) {
428 *s += strlen(m->name);
429 return m->mask;
430 } else {
431 m++;
432 }
433 }
434 return 0;
435}
436
437/*
438 * get_match - find logmask value
439 */
440static unsigned long
441get_match(
442 char *s,
443 struct masks *m
444 )
445{
446 while (m->name) {
447 if (strcmp(s, m->name) == 0) {
448 return m->mask;
449 } else {
450 m++;
451 }
452 }
453 return 0;
454}
455
456/*
457 * get_logmask - build bitmask for ntp_syslogmask
458 */
459static unsigned long
460get_logmask(
461 char *s
462 )
463{
464 char *t;
465 unsigned long offset;
466 unsigned long mask;
467
468 t = s;
469 offset = get_pfxmatch(&t, logcfg_class);
470 mask = get_match(t, logcfg_item);
471
472 if (mask)
473 return mask << offset;
474 else
475 msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s);
476
477 return 0;
478}
479
480
481/*
482 * getconfig - get command line options and read the configuration file
483 */
484void
485getconfig(
486 int argc,
487 char *argv[]
488 )
489{
490 register int i;
491 int c;
492 int errflg;
493 int peerversion;
494 int minpoll;
495 int maxpoll;
496 int ttl;
497 long stratum;
498 unsigned long ul;
499 keyid_t peerkey;
500 u_char *peerkeystr;
501 u_long fudgeflag;
502 u_int peerflags;
503 int hmode;
504 struct sockaddr_in peeraddr;
505 struct sockaddr_in maskaddr;
506 FILE *fp[MAXINCLUDELEVEL+1];
507 FILE *includefile;
508 int includelevel = 0;
509 char line[MAXLINE];
510 char *(tokens[MAXTOKENS]);
511 int ntokens;
512 int tok = CONFIG_UNKNOWN;
513 struct interface *localaddr;
514 struct refclockstat clock_stat;
515 FILEGEN *filegen;
516
517 /*
518 * Initialize, initialize
519 */
520 errflg = 0;
521 /* HMS: don't initialize debug to 0 here! */
522#ifndef SYS_WINNT
523 config_file = CONFIG_FILE;
524#else
525 temp = CONFIG_FILE;
526 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
527 msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
528 exit(1);
529 }
530 config_file = config_file_storage;
531
532 temp = ALT_CONFIG_FILE;
533 if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
534 msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
535 exit(1);
536 }
537 alt_config_file = alt_config_file_storage;
538
539#endif /* SYS_WINNT */
540 progname = argv[0];
541 res_fp = NULL;
542 memset((char *)sys_phone, 0, sizeof(sys_phone));
543 ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */
544
545 /*
546 * install a non default variable with this daemon version
547 */
548 (void) sprintf(line, "daemon_version=\"%s\"", Version);
549 set_sys_var(line, strlen(line)+1, RO);
550
551 /*
552 * Say how we're setting the time of day
553 */
554 (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using);
555 set_sys_var(line, strlen(line)+1, RO);
556
557 /*
558 * Initialize the loop.
559 */
560 loop_config(LOOP_DRIFTINIT, 0.);
561
562 getCmdOpts(argc, argv);
563
564 if (
565 (fp[0] = fopen(FindConfig(config_file), "r")) == NULL
566#ifdef HAVE_NETINFO
567 /* If there is no config_file, try NetInfo. */
568 && check_netinfo && !(config_netinfo = get_netinfo_config())
569#endif /* HAVE_NETINFO */
570 ) {
571 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
572 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
573#ifdef SYS_WINNT
574 /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
575
576 if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) {
577
578 /*
579 * Broadcast clients can sometimes run without
580 * a configuration file.
581 */
582
583 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
584 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
585 return;
586 }
587#else /* not SYS_WINNT */
588 return;
589#endif /* not SYS_WINNT */
590 }
591
592 for (;;) {
593 if (fp[includelevel])
594 tok = gettokens(fp[includelevel], line, tokens, &ntokens);
595#ifdef HAVE_NETINFO
596 else
597 tok = gettokens_netinfo(config_netinfo, tokens, &ntokens);
598#endif /* HAVE_NETINFO */
599
600 if (tok == CONFIG_UNKNOWN) {
601 if (includelevel > 0) {
602 fclose(fp[includelevel--]);
603 continue;
604 } else {
605 break;
606 }
607 }
608
609 switch(tok) {
610 case CONFIG_PEER:
611 case CONFIG_SERVER:
612 case CONFIG_MANYCASTCLIENT:
613 case CONFIG_BROADCAST:
614 if (tok == CONFIG_PEER)
615 hmode = MODE_ACTIVE;
616 else if (tok == CONFIG_SERVER)
617 hmode = MODE_CLIENT;
618 else if (tok == CONFIG_MANYCASTCLIENT)
619 hmode = MODE_CLIENT;
620 else
621 hmode = MODE_BROADCAST;
622
623 if (ntokens < 2) {
624 msyslog(LOG_ERR,
625 "No address for %s, line ignored",
626 tokens[0]);
627 break;
628 }
629
630 if (!getnetnum(tokens[1], &peeraddr, 0)) {
631 errflg = -1;
632 } else {
633 errflg = 0;
634
635 if (
636#ifdef REFCLOCK
637 !ISREFCLOCKADR(&peeraddr) &&
638#endif
639 ISBADADR(&peeraddr)) {
640 msyslog(LOG_ERR,
641 "attempt to configure invalid address %s",
642 ntoa(&peeraddr));
643 break;
644 }
645 /*
646 * Shouldn't be able to specify multicast
647 * address for server/peer!
648 * and unicast address for manycastclient!
649 */
650 if (((tok == CONFIG_SERVER) ||
651 (tok == CONFIG_PEER)) &&
652#ifdef REFCLOCK
653 !ISREFCLOCKADR(&peeraddr) &&
654#endif
655 IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) {
656 msyslog(LOG_ERR,
657 "attempt to configure invalid address %s",
658 ntoa(&peeraddr));
659 break;
660 }
661 if ((tok == CONFIG_MANYCASTCLIENT) &&
662 !IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))) {
663 msyslog(LOG_ERR,
664 "attempt to configure invalid address %s",
665 ntoa(&peeraddr));
666 break;
667 }
668 }
669
670 peerversion = NTP_VERSION;
671 minpoll = NTP_MINDPOLL;
672 maxpoll = NTP_MAXDPOLL;
673 peerkey = 0;
674 peerkeystr = "*";
675 peerflags = 0;
676 ttl = 0;
677 for (i = 2; i < ntokens; i++)
678 switch (matchkey(tokens[i], mod_keywords)) {
679 case CONF_MOD_VERSION:
680 if (i >= ntokens-1) {
681 msyslog(LOG_ERR,
682 "peer/server version requires an argument");
683 errflg = 1;
684 break;
685 }
686 peerversion = atoi(tokens[++i]);
687 if ((u_char)peerversion > NTP_VERSION
688 || (u_char)peerversion < NTP_OLDVERSION) {
689 msyslog(LOG_ERR,
690 "inappropriate version number %s, line ignored",
691 tokens[i]);
692 errflg = 1;
693 }
694 break;
695
696 case CONF_MOD_KEY:
697 if (i >= ntokens-1) {
698 msyslog(LOG_ERR,
699 "key: argument required");
700 errflg = 1;
701 break;
702 }
703 peerkey = (int)atol(tokens[++i]);
704 peerflags |= FLAG_AUTHENABLE;
705 break;
706
707 case CONF_MOD_MINPOLL:
708 if (i >= ntokens-1) {
709 msyslog(LOG_ERR,
710 "minpoll: argument required");
711 errflg = 1;
712 break;
713 }
714 minpoll = atoi(tokens[++i]);
715 if (minpoll < NTP_MINPOLL) {
716 msyslog(LOG_INFO,
717 "minpoll: provided value (%d) is below minimum (%d)",
718 minpoll, NTP_MINPOLL);
719 minpoll = NTP_MINPOLL;
720 }
721 break;
722
723 case CONF_MOD_MAXPOLL:
724 if (i >= ntokens-1) {
725 msyslog(LOG_ERR,
726 "maxpoll: argument required"
727 );
728 errflg = 1;
729 break;
730 }
731 maxpoll = atoi(tokens[++i]);
732 if (maxpoll > NTP_MAXPOLL) {
733 msyslog(LOG_INFO,
734 "maxpoll: provided value (%d) is above maximum (%d)",
735 maxpoll, NTP_MAXPOLL);
736 maxpoll = NTP_MAXPOLL;
737 }
738 break;
739
740 case CONF_MOD_PREFER:
741 peerflags |= FLAG_PREFER;
742 break;
743
744 case CONF_MOD_NOSELECT:
745 peerflags |= FLAG_NOSELECT;
746 break;
747
748 case CONF_MOD_BURST:
749 peerflags |= FLAG_BURST;
750 break;
751
752 case CONF_MOD_IBURST:
753 peerflags |= FLAG_IBURST;
754 break;
755#ifdef AUTOKEY
756 case CONF_MOD_SKEY:
757 peerflags |= FLAG_SKEY |
758 FLAG_AUTHENABLE;
759 break;
760
761#ifdef PUBKEY
762 case CONF_MOD_PUBLICKEY:
763 if (i >= ntokens - 1) {
764 msyslog(LOG_ERR,
765 "Public key file name required");
766 errflg = 1;
767 break;
768 }
769 peerflags |= FLAG_SKEY |
770 FLAG_AUTHENABLE;
771 peerkeystr = tokens[++i];
772 break;
773#endif /* PUBKEY */
774#endif /* AUTOKEY */
775
776 case CONF_MOD_TTL:
777 if (i >= ntokens-1) {
778 msyslog(LOG_ERR,
779 "ttl: argument required");
780 errflg = 1;
781 break;
782 }
783 ttl = atoi(tokens[++i]);
784 break;
785
786 case CONF_MOD_MODE:
787 if (i >= ntokens-1) {
788 msyslog(LOG_ERR,
789 "mode: argument required");
790 errflg = 1;
791 break;
792 }
793 ttl = atoi(tokens[++i]);
794 break;
795
796 case CONFIG_UNKNOWN:
797 errflg = 1;
798 break;
799 }
800 if (minpoll > maxpoll) {
801 msyslog(LOG_ERR, "config error: minpoll > maxpoll");
802 errflg = 1;
803 }
804 if (errflg == 0) {
805 if (peer_config(&peeraddr, any_interface, hmode,
806 peerversion, minpoll, maxpoll, peerflags,
807 ttl, peerkey, peerkeystr) == 0) {
808 msyslog(LOG_ERR,
809 "configuration of %s failed",
810 ntoa(&peeraddr));
811 }
812
813 } else if (errflg == -1) {
814 save_resolve(tokens[1], hmode, peerversion,
815 minpoll, maxpoll, peerflags, ttl,
816 peerkey, peerkeystr);
817 }
818 break;
819
820 case CONFIG_DRIFTFILE:
821 if (ntokens >= 2)
822 stats_config(STATS_FREQ_FILE, tokens[1]);
823 else
824 stats_config(STATS_FREQ_FILE, (char *)0);
825 break;
826
827 case CONFIG_PIDFILE:
828 if (ntokens >= 2)
829 stats_config(STATS_PID_FILE, tokens[1]);
830 else
831 stats_config(STATS_PID_FILE, (char *)0);
832 break;
833
834 case CONFIG_INCLUDEFILE:
835 if (ntokens < 2) {
836 msyslog(LOG_ERR, "includefile needs one argument");
837 break;
838 }
839 if (includelevel >= MAXINCLUDELEVEL) {
840 fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
841 msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded.");
842 break;
843 }
844 includefile = fopen(FindConfig(tokens[1]), "r");
845 if (includefile == NULL) {
846 fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1]));
847 msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1]));
848 break;
849 }
850 fp[++includelevel] = includefile;
851 break;
852
853 case CONFIG_LOGFILE:
854 if (ntokens >= 2) {
855 FILE *new_file;
856
857 new_file = fopen(tokens[1], "a");
858 if (new_file != NULL) {
859 NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
860 msyslog(LOG_NOTICE, "logging to file %s", tokens[1]);
861 if (syslog_file != NULL &&
862 fileno(syslog_file) != fileno(new_file))
863 (void)fclose(syslog_file);
864
865 syslog_file = new_file;
866 syslogit = 0;
867 }
868 else
869 msyslog(LOG_ERR,
870 "Cannot open log file %s",
871 tokens[1]);
872 }
873 else
874 msyslog(LOG_ERR, "logfile needs one argument");
875 break;
876
877 case CONFIG_LOGCONFIG:
878 for (i = 1; i < ntokens; i++)
879 {
880 int add = 1;
881 int equals = 0;
882 char * s = &tokens[i][0];
883
884 switch (*s) {
885 case '+':
886 case '-':
887 case '=':
888 add = *s == '+';
889 equals = *s == '=';
890 s++;
891 break;
892
893 default:
894 break;
895 }
896 if (equals) {
897 ntp_syslogmask = get_logmask(s);
898 } else {
899 if (add) {
900 ntp_syslogmask |= get_logmask(s);
901 } else {
902 ntp_syslogmask &= ~get_logmask(s);
903 }
904 }
905#ifdef DEBUG
906 if (debug)
907 printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]);
908#endif
909 }
910 break;
911
912 case CONFIG_BROADCASTCLIENT:
913 proto_config(PROTO_BROADCLIENT, 1, 0.);
914 break;
915
916 case CONFIG_MULTICASTCLIENT:
917 case CONFIG_MANYCASTSERVER:
918 if (ntokens > 1) {
919 for (i = 1; i < ntokens; i++) {
920 if (getnetnum(tokens[i], &peeraddr, 1))
921 proto_config(PROTO_MULTICAST_ADD,
922 peeraddr.sin_addr.s_addr, 0.);
923 }
924 } else
925 proto_config(PROTO_MULTICAST_ADD,
926 htonl(INADDR_NTP), 0.);
927 if (tok == CONFIG_MULTICASTCLIENT)
928 sys_bclient = 1;
929 else if (tok == CONFIG_MANYCASTSERVER)
930 sys_manycastserver = 1;
931 break;
932
933 case CONFIG_AUTHENTICATE:
934 errflg = 0;
935 if (ntokens >= 2) {
936 if (STREQ(tokens[1], "yes"))
937 proto_config(PROTO_AUTHENTICATE, 1, 0.);
938 else if (STREQ(tokens[1], "no"))
939 proto_config(PROTO_AUTHENTICATE, 0, 0.);
940 else
941 errflg++;
942 } else {
943 errflg++;
944 }
945
946 if (errflg)
947 msyslog(LOG_ERR,
948 "should be `authenticate yes|no'");
949 break;
950
951 case CONFIG_KEYS:
952 if (ntokens >= 2) {
953 getauthkeys(tokens[1]);
954 }
955 break;
956
957 case CONFIG_TINKER:
958 for (i = 1; i < ntokens; i++) {
959 int temp;
960 double ftemp;
961
962 temp = matchkey(tokens[i++],
963 tinker_keywords);
964 if (i > ntokens - 1) {
965 msyslog(LOG_ERR,
966 "tinker: missing argument");
967 errflg++;
968 break;
969 }
970 sscanf(tokens[i], "%lf", &ftemp);
971 switch(temp) {
972 case CONF_CLOCK_MAX:
973 loop_config(LOOP_MAX, ftemp);
974 break;
975
976 case CONF_CLOCK_PANIC:
977 loop_config(LOOP_PANIC, ftemp);
978 break;
979
980 case CONF_CLOCK_PHI:
981 loop_config(LOOP_PHI, ftemp);
982 break;
983
984 case CONF_CLOCK_MINSTEP:
985 loop_config(LOOP_MINSTEP, ftemp);
986 break;
987
988 case CONF_CLOCK_MINPOLL:
989 loop_config(LOOP_MINPOLL, ftemp);
990 break;
991
992 case CONF_CLOCK_ALLAN:
993 loop_config(LOOP_ALLAN, ftemp);
994 break;
995
996 case CONF_CLOCK_HUFFPUFF:
997 loop_config(LOOP_HUFFPUFF, ftemp);
998 break;
999 }
1000 }
1001 break;
1002
1003#ifdef AUTOKEY
1004 case CONFIG_REVOKE:
1005 if (ntokens >= 2)
1006 sys_revoke = 1 << max(atoi(tokens[1]), 10);
1007 break;
1008
1009 case CONFIG_AUTOMAX:
1010 if (ntokens >= 2)
1011 sys_automax = 1 << max(atoi(tokens[1]), 10);
1012 break;
1013
1014#ifdef PUBKEY
1015 case CONFIG_KEYSDIR:
1016 if (ntokens < 2) {
1017 msyslog(LOG_ERR,
1018 "Keys directory name required");
1019 break;
1020 }
1021 crypto_config(CRYPTO_CONF_KEYS, tokens[1]);
1022 break;
1023
1024 case CONFIG_CRYPTO:
1025 if (ntokens == 1) {
1026 crypto_config(CRYPTO_CONF_FLAGS , "0");
1027 break;
1028 }
1029 for (i = 1; i < ntokens; i++) {
1030 int temp;
1031
1032 temp = matchkey(tokens[i++], crypto_keywords);
1033 if (i > ntokens - 1) {
1034 msyslog(LOG_ERR,
1035 "crypto: missing argument");
1036 errflg++;
1037 break;
1038 }
1039 switch(temp) {
1040 case CONF_CRYPTO_FLAGS:
1041 crypto_config(CRYPTO_CONF_FLAGS, tokens[i]);
1042 break;
1043
1044 case CONF_CRYPTO_LEAP:
1045 crypto_config(CRYPTO_CONF_LEAP, tokens[i]);
1046 break;
1047
1048 case CONF_CRYPTO_DH:
1049 crypto_config(CRYPTO_CONF_DH, tokens[i]);
1050 break;
1051
1052 case CONF_CRYPTO_PRIVATEKEY:
1053 crypto_config(CRYPTO_CONF_PRIV, tokens[i]);
1054 break;
1055
1056 case CONF_CRYPTO_PUBLICKEY:
1057 crypto_config(CRYPTO_CONF_PUBL, tokens[i]);
1058 break;
1059
1060 case CONF_CRYPTO_CERT:
1061 crypto_config(CRYPTO_CONF_CERT, tokens[i]);
1062 break;
1063
1064 default:
1065 msyslog(LOG_ERR, "crypto: unknown keyword");
1066 break;
1067 }
1068 }
1069 break;
1070#endif /* PUBKEY */
1071#endif /* AUTOKEY */
1072
1073 case CONFIG_RESTRICT:
1074 if (ntokens < 2) {
1075 msyslog(LOG_ERR, "restrict requires an address");
1076 break;
1077 }
1078 if (STREQ(tokens[1], "default"))
1079 peeraddr.sin_addr.s_addr = htonl(INADDR_ANY);
1080 else if (!getnetnum(tokens[1], &peeraddr, 1))
1081 break;
1082
1083 /*
1084 * Use peerversion as flags, peerkey as mflags. Ick.
1085 */
1086 peerversion = 0;
1087 peerkey = 0;
1088 errflg = 0;
1089 maskaddr.sin_addr.s_addr = ~(u_int32)0;
1090 for (i = 2; i < ntokens; i++) {
1091 switch (matchkey(tokens[i], res_keywords)) {
1092 case CONF_RES_MASK:
1093 if (i >= ntokens-1) {
1094 msyslog(LOG_ERR,
1095 "mask keyword needs argument");
1096 errflg++;
1097 break;
1098 }
1099 i++;
1100 if (!getnetnum(tokens[i], &maskaddr, 1))
1101 errflg++;
1102 break;
1103
1104 case CONF_RES_IGNORE:
1105 peerversion |= RES_IGNORE;
1106 break;
1107
1108 case CONF_RES_NOSERVE:
1109 peerversion |= RES_DONTSERVE;
1110 break;
1111
1112 case CONF_RES_NOTRUST:
1113 peerversion |= RES_DONTTRUST;
1114 break;
1115
1116 case CONF_RES_NOQUERY:
1117 peerversion |= RES_NOQUERY;
1118 break;
1119
1120 case CONF_RES_NOMODIFY:
1121 peerversion |= RES_NOMODIFY;
1122 break;
1123
1124 case CONF_RES_NOPEER:
1125 peerversion |= RES_NOPEER;
1126 break;
1127
1128 case CONF_RES_NOTRAP:
1129 peerversion |= RES_NOTRAP;
1130 break;
1131
1132 case CONF_RES_LPTRAP:
1133 peerversion |= RES_LPTRAP;
1134 break;
1135
1136 case CONF_RES_NTPPORT:
1137 peerkey |= RESM_NTPONLY;
1138 break;
1139
1140 case CONF_RES_VERSION:
1141 peerversion |= RES_VERSION;
1142 break;
1143
1144 case CONF_RES_DEMOBILIZE:
1145 peerversion |= RES_DEMOBILIZE;
1146 break;
1147
1148 case CONF_RES_LIMITED:
1149 peerversion |= RES_LIMITED;
1150 break;
1151
1152 case CONFIG_UNKNOWN:
1153 errflg++;
1154 break;
1155 }
1156 }
1157 if (SRCADR(&peeraddr) == htonl(INADDR_ANY))
1158 maskaddr.sin_addr.s_addr = 0;
1159 if (!errflg)
1160 hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
1161 (int)peerkey, peerversion);
1162 break;
1163
1164 case CONFIG_BDELAY:
1165 if (ntokens >= 2) {
1166 double tmp;
1167
1168 if (sscanf(tokens[1], "%lf", &tmp) != 1) {
1169 msyslog(LOG_ERR,
1170 "broadcastdelay value %s undecodable",
1171 tokens[1]);
1172 } else {
1173 proto_config(PROTO_BROADDELAY, 0, tmp);
1174 }
1175 }
1176 break;
1177
1178 case CONFIG_TRUSTEDKEY:
1179 for (i = 1; i < ntokens; i++) {
1180 keyid_t tkey;
1181
1182 tkey = atol(tokens[i]);
1183 if (tkey == 0) {
1184 msyslog(LOG_ERR,
1185 "trusted key %s unlikely",
1186 tokens[i]);
1187 } else {
1188 authtrust(tkey, 1);
1189 }
1190 }
1191 break;
1192
1193 case CONFIG_REQUESTKEY:
1194 if (ntokens >= 2) {
1195 if (!atouint(tokens[1], &ul)) {
1196 msyslog(LOG_ERR,
1197 "%s is undecodable as request key",
1198 tokens[1]);
1199 } else if (ul == 0) {
1200 msyslog(LOG_ERR,
1201 "%s makes a poor request keyid",
1202 tokens[1]);
1203 } else {
1204#ifdef DEBUG
1205 if (debug > 3)
1206 printf(
1207 "set info_auth_key to %08lx\n", ul);
1208#endif
1209 info_auth_keyid = (keyid_t)ul;
1210 }
1211 }
1212 break;
1213
1214 case CONFIG_CONTROLKEY:
1215 if (ntokens >= 2) {
1216 keyid_t ckey;
1217
1218 ckey = atol(tokens[1]);
1219 if (ckey == 0) {
1220 msyslog(LOG_ERR,
1221 "%s makes a poor control keyid",
1222 tokens[1]);
1223 } else {
1224 ctl_auth_keyid = ckey;
1225 }
1226 }
1227 break;
1228
1229 case CONFIG_TRAP:
1230 if (ntokens < 2) {
1231 msyslog(LOG_ERR,
1232 "no address for trap command, line ignored");
1233 break;
1234 }
1235 if (!getnetnum(tokens[1], &peeraddr, 1))
1236 break;
1237
1238 /*
1239 * Use peerversion for port number. Barf.
1240 */
1241 errflg = 0;
1242 peerversion = 0;
1243 localaddr = 0;
1244 for (i = 2; i < ntokens-1; i++)
1245 switch (matchkey(tokens[i], trap_keywords)) {
1246 case CONF_TRAP_PORT:
1247 if (i >= ntokens-1) {
1248 msyslog(LOG_ERR,
1249 "trap port requires an argument");
1250 errflg = 1;
1251 break;
1252 }
1253 peerversion = atoi(tokens[++i]);
1254 if (peerversion <= 0
1255 || peerversion > 32767) {
1256 msyslog(LOG_ERR,
1257 "invalid port number %s, trap ignored",
1258 tokens[i]);
1259 errflg = 1;
1260 }
1261 break;
1262
1263 case CONF_TRAP_INTERFACE:
1264 if (i >= ntokens-1) {
1265 msyslog(LOG_ERR,
1266 "trap interface requires an argument");
1267 errflg = 1;
1268 break;
1269 }
1270
1271 if (!getnetnum(tokens[++i],
1272 &maskaddr, 1)) {
1273 errflg = 1;
1274 break;
1275 }
1276
1277 localaddr = findinterface(&maskaddr);
1278 if (localaddr == NULL) {
1279 msyslog(LOG_ERR,
1280 "can't find interface with address %s",
1281 ntoa(&maskaddr));
1282 errflg = 1;
1283 }
1284 break;
1285
1286 case CONFIG_UNKNOWN:
1287 errflg++;
1288 break;
1289 }
1290
1291 if (!errflg) {
1292 if (peerversion != 0)
1293 peeraddr.sin_port = htons( (u_short) peerversion);
1294 else
1295 peeraddr.sin_port = htons(TRAPPORT);
1296 if (localaddr == NULL)
1297 localaddr = any_interface;
1298 if (!ctlsettrap(&peeraddr, localaddr, 0,
1299 NTP_VERSION))
1300 msyslog(LOG_ERR,
1301 "can't set trap for %s, no resources",
1302 ntoa(&peeraddr));
1303 }
1304 break;
1305
1306 case CONFIG_FUDGE:
1307 if (ntokens < 2) {
1308 msyslog(LOG_ERR,
1309 "no address for fudge command, line ignored");
1310 break;
1311 }
1312 if (!getnetnum(tokens[1], &peeraddr, 1))
1313 break;
1314
1315 if (!ISREFCLOCKADR(&peeraddr)) {
1316 msyslog(LOG_ERR,
1317 "%s is inappropriate address for the fudge command, line ignored",
1318 ntoa(&peeraddr));
1319 break;
1320 }
1321
1322 memset((void *)&clock_stat, 0, sizeof clock_stat);
1323 fudgeflag = 0;
1324 errflg = 0;
1325 for (i = 2; i < ntokens-1; i++) {
1326 switch (c = matchkey(tokens[i],
1327 fudge_keywords)) {
1328 case CONF_FDG_TIME1:
1329 if (sscanf(tokens[++i], "%lf",
1330 &clock_stat.fudgetime1) != 1) {
1331 msyslog(LOG_ERR,
1332 "fudge %s time1 value in error",
1333 ntoa(&peeraddr));
1334 errflg = i;
1335 break;
1336 }
1337 clock_stat.haveflags |= CLK_HAVETIME1;
1338 break;
1339
1340 case CONF_FDG_TIME2:
1341 if (sscanf(tokens[++i], "%lf",
1342 &clock_stat.fudgetime2) != 1) {
1343 msyslog(LOG_ERR,
1344 "fudge %s time2 value in error",
1345 ntoa(&peeraddr));
1346 errflg = i;
1347 break;
1348 }
1349 clock_stat.haveflags |= CLK_HAVETIME2;
1350 break;
1351
1352
1353 case CONF_FDG_STRATUM:
1354 if (!atoint(tokens[++i], &stratum))
1355 {
1356 msyslog(LOG_ERR,
1357 "fudge %s stratum value in error",
1358 ntoa(&peeraddr));
1359 errflg = i;
1360 break;
1361 }
1362 clock_stat.fudgeval1 = stratum;
1363 clock_stat.haveflags |= CLK_HAVEVAL1;
1364 break;
1365
1366 case CONF_FDG_REFID:
1367 /* HMS: Endianness and 0 bytes? */
1368 /* XXX */
1369 strncpy((char *)&clock_stat.fudgeval2,
1370 tokens[++i], 4);
1371 clock_stat.haveflags |= CLK_HAVEVAL2;
1372 break;
1373
1374 case CONF_FDG_FLAG1:
1375 case CONF_FDG_FLAG2:
1376 case CONF_FDG_FLAG3:
1377 case CONF_FDG_FLAG4:
1378 if (!atouint(tokens[++i], &fudgeflag)
1379 || fudgeflag > 1) {
1380 msyslog(LOG_ERR,
1381 "fudge %s flag value in error",
1382 ntoa(&peeraddr));
1383 errflg = i;
1384 break;
1385 }
1386 switch(c) {
1387 case CONF_FDG_FLAG1:
1388 c = CLK_FLAG1;
1389 clock_stat.haveflags|=CLK_HAVEFLAG1;
1390 break;
1391 case CONF_FDG_FLAG2:
1392 c = CLK_FLAG2;
1393 clock_stat.haveflags|=CLK_HAVEFLAG2;
1394 break;
1395 case CONF_FDG_FLAG3:
1396 c = CLK_FLAG3;
1397 clock_stat.haveflags|=CLK_HAVEFLAG3;
1398 break;
1399 case CONF_FDG_FLAG4:
1400 c = CLK_FLAG4;
1401 clock_stat.haveflags|=CLK_HAVEFLAG4;
1402 break;
1403 }
1404 if (fudgeflag == 0)
1405 clock_stat.flags &= ~c;
1406 else
1407 clock_stat.flags |= c;
1408 break;
1409
1410 case CONFIG_UNKNOWN:
1411 errflg = -1;
1412 break;
1413 }
1414 }
1415
1416#ifdef REFCLOCK
1417 /*
1418 * If reference clock support isn't defined the
1419 * fudge line will still be accepted and syntax
1420 * checked, but will essentially do nothing.
1421 */
1422 if (!errflg) {
1423 refclock_control(&peeraddr, &clock_stat,
1424 (struct refclockstat *)0);
1425 }
1426#endif
1427 break;
1428
1429 case CONFIG_STATSDIR:
1430 if (ntokens >= 2)
1431 stats_config(STATS_STATSDIR,tokens[1]);
1432 break;
1433
1434 case CONFIG_STATISTICS:
1435 for (i = 1; i < ntokens; i++) {
1436 filegen = filegen_get(tokens[i]);
1437
1438 if (filegen == NULL) {
1439 msyslog(LOG_ERR,
1440 "no statistics named %s available",
1441 tokens[i]);
1442 continue;
1443 }
1444#ifdef DEBUG
1445 if (debug > 3)
1446 printf("enabling filegen for %s statistics \"%s%s\"\n",
1447 tokens[i], filegen->prefix, filegen->basename);
1448#endif
1449 filegen->flag |= FGEN_FLAG_ENABLED;
1450 }
1451 break;
1452
1453 case CONFIG_FILEGEN:
1454 if (ntokens < 2) {
1455 msyslog(LOG_ERR,
1456 "no id for filegen command, line ignored");
1457 break;
1458 }
1459
1460 filegen = filegen_get(tokens[1]);
1461 if (filegen == NULL) {
1462 msyslog(LOG_ERR,
1463 "unknown filegen \"%s\" ignored",
1464 tokens[1]);
1465 break;
1466 }
1467 /*
1468 * peerversion is (ab)used for filegen file (index)
1469 * peerkey is (ab)used for filegen type
1470 * peerflags is (ab)used for filegen flags
1471 */
1472 peerversion = 0;
1473 peerkey = filegen->type;
1474 peerflags = filegen->flag;
1475 errflg = 0;
1476
1477 for (i = 2; i < ntokens; i++) {
1478 switch (matchkey(tokens[i], filegen_keywords)) {
1479 case CONF_FGEN_FILE:
1480 if (i >= ntokens - 1) {
1481 msyslog(LOG_ERR,
1482 "filegen %s file requires argument",
1483 tokens[1]);
1484 errflg = i;
1485 break;
1486 }
1487 peerversion = ++i;
1488 break;
1489 case CONF_FGEN_TYPE:
1490 if (i >= ntokens -1) {
1491 msyslog(LOG_ERR,
1492 "filegen %s type requires argument",
1493 tokens[1]);
1494 errflg = i;
1495 break;
1496 }
1497 peerkey = matchkey(tokens[++i], fgen_types);
1498 if (peerkey == CONFIG_UNKNOWN) {
1499 msyslog(LOG_ERR,
1500 "filegen %s unknown type \"%s\"",
1501 tokens[1], tokens[i]);
1502 errflg = i;
1503 break;
1504 }
1505 break;
1506
1507 case CONF_FGEN_FLAG_LINK:
1508 peerflags |= FGEN_FLAG_LINK;
1509 break;
1510
1511 case CONF_FGEN_FLAG_NOLINK:
1512 peerflags &= ~FGEN_FLAG_LINK;
1513 break;
1514
1515 case CONF_FGEN_FLAG_ENABLE:
1516 peerflags |= FGEN_FLAG_ENABLED;
1517 break;
1518
1519 case CONF_FGEN_FLAG_DISABLE:
1520 peerflags &= ~FGEN_FLAG_ENABLED;
1521 break;
1522 }
1523 }
1524 if (!errflg)
1525 filegen_config(filegen, tokens[peerversion],
1526 (u_char)peerkey, (u_char)peerflags);
1527 break;
1528
1529 case CONFIG_SETVAR:
1530 if (ntokens < 2) {
1531 msyslog(LOG_ERR,
1532 "no value for setvar command - line ignored");
1533 } else {
1534 set_sys_var(tokens[1], strlen(tokens[1])+1,
1535 RW |
1536 ((((ntokens > 2)
1537 && !strcmp(tokens[2],
1538 "default")))
1539 ? DEF
1540 : 0));
1541 }
1542 break;
1543
1544 case CONFIG_CLIENTLIMIT:
1545 if (ntokens < 2) {
1546 msyslog(LOG_ERR,
1547 "no value for clientlimit command - line ignored");
1548 } else {
1549 u_long ui;
1550
1551 if (!atouint(tokens[1], &ui) || !ui) {
1552 msyslog(LOG_ERR,
1553 "illegal value for clientlimit command - line ignored");
1554 } else {
1555 char bp[80];
1556
1557#ifdef DEBUG
1558 if (debug)
1559 sprintf(bp, "client_limit=%lu", ui);
1560#endif
1561 set_sys_var(bp, strlen(bp)+1, RO);
1562 client_limit = ui;
1563 }
1564 }
1565 break;
1566
1567 case CONFIG_CLIENTPERIOD:
1568 if (ntokens < 2) {
1569 msyslog(LOG_ERR,
1570 "no value for clientperiod command - line ignored");
1571 } else {
1572 u_long ui;
1573
1574 if (!atouint(tokens[1], &ui) || ui < 64) {
1575 msyslog(LOG_ERR,
1576 "illegal value for clientperiod command - line ignored");
1577 } else {
1578 char bp[80];
1579
1580 sprintf(bp, "client_limit_period=%ld", ui);
1581 set_sys_var(bp, strlen(bp)+1, RO);
1582 client_limit_period = ui;
1583 }
1584 }
1585 break;
1586
1587 case CONFIG_ENABLE:
1588 for (i = 1; i < ntokens; i++) {
1589 int flag;
1590
1591 flag = matchkey(tokens[i], flags_keywords);
1592 if (flag == CONFIG_UNKNOWN) {
1593 msyslog(LOG_ERR,
1594 "enable unknown flag %s",
1595 tokens[i]);
1596 errflg = 1;
1597 break;
1598 }
1599 proto_config(flag, 1, 0.);
1600 }
1601 break;
1602
1603 case CONFIG_DISABLE:
1604 for (i = 1; i < ntokens; i++) {
1605 int flag;
1606
1607 flag = matchkey(tokens[i], flags_keywords);
1608 if (flag == CONFIG_UNKNOWN) {
1609 msyslog(LOG_ERR,
1610 "disable unknown flag %s",
1611 tokens[i]);
1612 errflg = 1;
1613 break;
1614 }
1615 proto_config(flag, 0, 0.);
1616 }
1617 break;
1618
1619 case CONFIG_PHONE:
1620 for (i = 1; i < ntokens && i < MAXPHONE; i++) {
1621 (void)strncpy(sys_phone[i - 1],
1622 tokens[i], MAXDIAL);
1623 }
1624 sys_phone[i - 1][0] = '\0';
1625 break;
1626
1627 case CONFIG_PPS:
1628 if (ntokens < 2) {
1629 msyslog(LOG_ERR,
1630 "pps missing device name");
1631 break;
1632 }
1633 (void)strncpy(pps_device, tokens[1], MAXPPS);
1634 for (i = 2; i < ntokens; i++) {
1635 int flag;
1636
1637 flag = matchkey(tokens[i], pps_keywords);
1638 switch(flag) {
1639 case CONF_PPS_ASSERT:
1640 pps_assert = 0;
1641 break;
1642 case CONF_PPS_CLEAR:
1643 pps_assert = 1;
1644 break;
1645 case CONF_PPS_HARDPPS:
1646 pps_hardpps = 1;
1647 break;
1648 default:
1649 msyslog(LOG_ERR,
1650 "pps unknown flag %s",
1651 tokens[i]);
1652 errflg = 1;
1653 break;
1654 }
1655 if(errflg)
1656 break;
1657 }
1658 break;
1659 }
1660 }
1661 if (fp[0])
1662 (void)fclose(fp[0]);
1663
1664#ifdef HAVE_NETINFO
1665 if (config_netinfo)
1666 free_netinfo_config(config_netinfo);
1667#endif /* HAVE_NETINFO */
1668
1669#if !defined(VMS) && !defined(SYS_VXWORKS)
1670 /* find a keyid */
1671 if (info_auth_keyid == 0)
1672 req_keyid = 65535;
1673 else
1674 req_keyid = info_auth_keyid;
1675
1676 /* if doesn't exist, make up one at random */
1677 if (!authhavekey(req_keyid)) {
1678 char rankey[9];
1679 int j;
1680
1681 for (i = 0; i < 8; i++)
1682 for (j = 1; j < 100; ++j) {
1683 rankey[i] = RANDOM & 0xff;
1684 if (rankey[i] != 0) break;
1685 }
1686 rankey[8] = 0;
1687 authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey);
1688 authtrust(req_keyid, 1);
1689 if (!authhavekey(req_keyid)) {
1690 msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!");
1691 /* HMS: Should this be fatal? */
1692 }
1693 }
1694
1695 /* save keyid so we will accept config requests with it */
1696 info_auth_keyid = req_keyid;
1697#endif /* !defined(VMS) && !defined(SYS_VXWORKS) */
1698
1699 if (res_fp != NULL) {
1700 /*
1701 * Need name resolution
1702 */
1703 do_resolve_internal();
1704 }
1705}
1706
1707
1708#ifdef HAVE_NETINFO
1709
1710/*
1711 * get_netinfo_config - find the nearest NetInfo domain with an ntp
1712 * configuration and initialize the configuration state.
1713 */
1714static struct netinfo_config_state *
1715get_netinfo_config()
1716{
1717 ni_status status;
1718 void *domain;
1719 ni_id config_dir;
1720 struct netinfo_config_state *config;
1721
1722 if (ni_open(NULL, ".", &domain) != NI_OK) return NULL;
1723
1724 while ((status = ni_pathsearch(domain, &config_dir, NETINFO_CONFIG_DIR)) == NI_NODIR) {
1725 void *next_domain;
1726 if (ni_open(domain, "..", &next_domain) != NI_OK) {
1727 ni_free(next_domain);
1728 break;
1729 }
1730 ni_free(domain);
1731 domain = next_domain;
1732 }
1733 if (status != NI_OK) {
1734 ni_free(domain);
1735 return NULL;
1736 }
1737
1738 config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state));
1739 config->domain = domain;
1740 config->config_dir = config_dir;
1741 config->prop_index = 0;
1742 config->val_index = 0;
1743 config->val_list = NULL;
1744
1745 return config;
1746}
1747
1748
1749
1750/*
1751 * free_netinfo_config - release NetInfo configuration state
1752 */
1753static void
1754free_netinfo_config(struct netinfo_config_state *config)
1755{
1756 ni_free(config->domain);
1757 free(config);
1758}
1759
1760
1761
1762/*
1763 * gettokens_netinfo - return tokens from NetInfo
1764 */
1765static int
1766gettokens_netinfo (
1767 struct netinfo_config_state *config,
1768 char **tokenlist,
1769 int *ntokens
1770 )
1771{
1772 int prop_index = config->prop_index;
1773 int val_index = config->val_index;
1774 char **val_list = config->val_list;
1775
1776 /*
1777 * Iterate through each keyword and look for a property that matches it.
1778 */
1779 again:
1780 if (!val_list) {
1781 for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++)
1782 {
1783 ni_namelist namelist;
1784 struct keyword current_prop = keywords[prop_index];
1785
1786 /*
1787 * For each value associated in the property, we're going to return
1788 * a separate line. We squirrel away the values in the config state
1789 * so the next time through, we don't need to do this lookup.
1790 */
1791 NI_INIT(&namelist);
1792 if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) {
1793 ni_index index;
1794
1795 /* Found the property, but it has no values */
1796 if (namelist.ni_namelist_len == 0) continue;
1797
1798 if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1))))
1799 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
1800
1801 for (index = 0; index < namelist.ni_namelist_len; index++) {
1802 char *value = namelist.ni_namelist_val[index];
1803
1804 if (! (val_list[index] = (char*)malloc(strlen(value+1))))
1805 { msyslog(LOG_ERR, "out of memory while configuring"); break; }
1806
1807 strcpy(val_list[index], value);
1808 }
1809 val_list[index] = NULL;
1810
1811 break;
1812 }
1813 ni_namelist_free(&namelist);
1814 }
1815 config->prop_index = prop_index;
1816 }
1817
1818 /* No list; we're done here. */
1819 if (!val_list) return CONFIG_UNKNOWN;
1820
1821 /*
1822 * We have a list of values for the current property.
1823 * Iterate through them and return each in order.
1824 */
1825 if (val_list[val_index])
1826 {
1827 int ntok = 1;
1828 int quoted = 0;
1829 char *tokens = val_list[val_index];
1830
1831 msyslog(LOG_INFO, "%s %s", keywords[prop_index].text, val_list[val_index]);
1832
1833 (const char*)tokenlist[0] = keywords[prop_index].text;
1834 for (ntok = 1; ntok < MAXTOKENS; ntok++) {
1835 tokenlist[ntok] = tokens;
1836 while (!ISEOL(*tokens) && (!ISSPACE(*tokens) || quoted))
1837 quoted ^= (*tokens++ == '"');
1838
1839 if (ISEOL(*tokens)) {
1840 *tokens = '\0';
1841 break;
1842 } else { /* must be space */
1843 *tokens++ = '\0';
1844 while (ISSPACE(*tokens)) tokens++;
1845 if (ISEOL(*tokens)) break;
1846 }
1847 }
1848 *ntokens = ntok + 1;
1849
1850 config->val_index++;
1851
1852 return keywords[prop_index].keytype;
1853 }
1854
1855 /* We're done with the current property. */
1856 prop_index = ++config->prop_index;
1857
1858 /* Free val_list and reset counters. */
1859 for (val_index = 0; val_list[val_index]; val_index++)
1860 free(val_list[val_index]);
1861 free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0;
1862
1863 goto again;
1864}
1865
1866#endif /* HAVE_NETINFO */
1867
1868
1869/*
1870 * gettokens - read a line and return tokens
1871 */
1872static int
1873gettokens (
1874 FILE *fp,
1875 char *line,
1876 char **tokenlist,
1877 int *ntokens
1878 )
1879{
1880 register char *cp;
1881 register int ntok;
1882 register int quoted = 0;
1883
1884 /*
1885 * Find start of first token
1886 */
1887 again:
1888 while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
1889 cp = line;
1890 while (ISSPACE(*cp))
1891 cp++;
1892 if (!ISEOL(*cp))
1893 break;
1894 }
1895 if (cp == NULL) {
1896 *ntokens = 0;
1897 return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
1898 }
1899
1900 /*
1901 * Now separate out the tokens
1902 */
1903 for (ntok = 0; ntok < MAXTOKENS; ntok++) {
1904 tokenlist[ntok] = cp;
1905 while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
1906 quoted ^= (*cp++ == '"');
1907
1908 if (ISEOL(*cp)) {
1909 *cp = '\0';
1910 break;
1911 } else { /* must be space */
1912 *cp++ = '\0';
1913 while (ISSPACE(*cp))
1914 cp++;
1915 if (ISEOL(*cp))
1916 break;
1917 }
1918 }
1919
1920 /*
1921 * Return the match
1922 */
1923 *ntokens = ntok + 1;
1924 ntok = matchkey(tokenlist[0], keywords);
1925 if (ntok == CONFIG_UNKNOWN)
1926 goto again;
1927 return ntok;
1928}
1929
1930
1931
1932/*
1933 * matchkey - match a keyword to a list
1934 */
1935static int
1936matchkey(
1937 register char *word,
1938 register struct keyword *keys
1939 )
1940{
1941 for (;;) {
1942 if (keys->keytype == CONFIG_UNKNOWN) {
1943 msyslog(LOG_ERR,
1944 "configure: keyword \"%s\" unknown, line ignored",
1945 word);
1946 return CONFIG_UNKNOWN;
1947 }
1948 if (STRSAME(word, keys->text))
1949 return keys->keytype;
1950 keys++;
1951 }
1952}
1953
1954
1955/*
1956 * getnetnum - return a net number (this is crude, but careful)
1957 */
1958static int
1959getnetnum(
1960 const char *num,
1961 struct sockaddr_in *addr,
1962 int complain
1963 )
1964{
1965 register const char *cp;
1966 register char *bp;
1967 register int i;
1968 register int temp;
1969 char buf[80]; /* will core dump on really stupid stuff */
1970 u_int32 netnum;
1971
1972 /* XXX ELIMINATE replace with decodenetnum */
1973 cp = num;
1974 netnum = 0;
1975 for (i = 0; i < 4; i++) {
1976 bp = buf;
1977 while (isdigit((int)*cp))
1978 *bp++ = *cp++;
1979 if (bp == buf)
1980 break;
1981
1982 if (i < 3) {
1983 if (*cp++ != '.')
1984 break;
1985 } else if (*cp != '\0')
1986 break;
1987
1988 *bp = '\0';
1989 temp = atoi(buf);
1990 if (temp > 255)
1991 break;
1992 netnum <<= 8;
1993 netnum += temp;
1994#ifdef DEBUG
1995 if (debug > 3)
1996 printf("getnetnum %s step %d buf %s temp %d netnum %lu\n",
1997 num, i, buf, temp, (u_long)netnum);
1998#endif
1999 }
2000
2001 if (i < 4) {
2002 if (complain)
2003 msyslog(LOG_ERR,
2004 "getnetnum: \"%s\" invalid host number, line ignored",
2005 num);
2006#ifdef DEBUG
2007 if (debug > 3)
2008 printf(
2009 "getnetnum: \"%s\" invalid host number, line ignored\n",
2010 num);
2011#endif
2012 return 0;
2013 }
2014
2015 /*
2016 * make up socket address. Clear it out for neatness.
2017 */
2018 memset((void *)addr, 0, sizeof(struct sockaddr_in));
2019 addr->sin_family = AF_INET;
2020 addr->sin_port = htons(NTP_PORT);
2021 addr->sin_addr.s_addr = htonl(netnum);
2022#ifdef DEBUG
2023 if (debug > 1)
2024 printf("getnetnum given %s, got %s (%lx)\n",
2025 num, ntoa(addr), (u_long)netnum);
2026#endif
2027 return 1;
2028}
2029
2030
2031#if !defined(VMS)
2032/*
2033 * catchchild - receive the resolver's exit status
2034 */
2035static RETSIGTYPE
2036catchchild(
2037 int sig
2038 )
2039{
2040 /*
2041 * We only start up one child, and if we're here
2042 * it should have already exited. Hence the following
2043 * shouldn't hang. If it does, please tell me.
2044 */
2045#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS)
2046 (void) wait(0);
2047#endif /* SYS_WINNT && VXWORKS*/
2048}
2049#endif /* VMS */
2050
2051
2052/*
2053 * save_resolve - save configuration info into a file for later name resolution
2054 */
2055static void
2056save_resolve(
2057 char *name,
2058 int mode,
2059 int version,
2060 int minpoll,
2061 int maxpoll,
2062 u_int flags,
2063 int ttl,
2064 keyid_t keyid,
2065 u_char *keystr
2066 )
2067{
2068#ifndef SYS_VXWORKS
2069 if (res_fp == NULL) {
2070#ifndef SYS_WINNT
2071 (void) strcpy(res_file, RES_TEMPFILE);
2072#else
2073 /* no /tmp directory under NT */
2074 {
2075 DWORD len;
2076 if(!(len = GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) {
2077 msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m");
2078 return;
2079 }
2080 (void) strcat(res_file, "ntpdXXXXXX");
2081 }
2082#endif /* SYS_WINNT */
2083#ifdef HAVE_MKSTEMP
2084 {
2085 int fd;
2086
2087 res_fp = NULL;
2088 if ((fd = mkstemp(res_file)) != -1)
2089 res_fp = fdopen(fd, "r+");
2090 }
2091#else
2092 (void) mktemp(res_file);
2093 res_fp = fopen(res_file, "w");
2094#endif
2095 if (res_fp == NULL) {
2096 msyslog(LOG_ERR, "open failed for %s: %m", res_file);
2097 return;
2098 }
2099 }
2100#ifdef DEBUG
2101 if (debug) {
2102 printf("resolving %s\n", name);
2103 }
2104#endif
2105
2106 (void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %s\n", name,
2107 mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2108#ifdef DEBUG
2109 if (debug > 1)
2110 printf("config: %s %d %d %d %d %x %d %u %s\n", name, mode,
2111 version, minpoll, maxpoll, flags, ttl, keyid, keystr);
2112#endif
2113
2114#else /* SYS_VXWORKS */
2115 /* save resolve info to a struct */
2116#endif /* SYS_VXWORKS */
2117}
2118
2119
2120/*
2121 * abort_resolve - terminate the resolver stuff and delete the file
2122 */
2123static void
2124abort_resolve(void)
2125{
2126 /*
2127 * In an ideal world we would might reread the file and
2128 * log the hosts which aren't getting configured. Since
2129 * this is too much work, however, just close and delete
2130 * the temp file.
2131 */
2132 if (res_fp != NULL)
2133 (void) fclose(res_fp);
2134 res_fp = NULL;
2135
2136#ifndef SYS_VXWORKS /* we don't open the file to begin with */
2137#if !defined(VMS)
2138 (void) unlink(res_file);
2139#else
2140 (void) delete(res_file);
2141#endif /* VMS */
2142#endif /* SYS_VXWORKS */
2143}
2144
2145
2146/*
2147 * do_resolve_internal - start up the resolver function (not program)
2148 */
2149/*
2150 * On VMS, this routine will simply refuse to resolve anything.
2151 *
2152 * Possible implementation: keep `res_file' in memory, do async
2153 * name resolution via QIO, update from within completion AST.
2154 * I'm unlikely to find the time for doing this, though. -wjm
2155 */
2156static void
2157do_resolve_internal(void)
2158{
2159 int i;
2160
2161 if (res_fp == NULL) {
2162 /* belch */
2163 msyslog(LOG_ERR,
2164 "do_resolve_internal: Fatal: res_fp == NULL");
2165 exit(1);
2166 }
2167
2168 /* we are done with this now */
2169 (void) fclose(res_fp);
2170 res_fp = NULL;
2171
2172#if !defined(VMS) && !defined (SYS_VXWORKS)
2173 req_file = res_file; /* set up pointer to res file */
2174#ifndef SYS_WINNT
2175 (void) signal_no_reset(SIGCHLD, catchchild);
2176
2177#ifndef SYS_VXWORKS
2178 i = fork();
2179 if (i == 0) {
2180 /*
2181 * this used to close everything
2182 * I don't think this is necessary
2183 */
2184 /*
2185 * To the unknown commenter above:
2186 * Well, I think it's better to clean up
2187 * after oneself. I have had problems with
2188 * refclock-io when intres was running - things
2189 * where fine again when ntpintres was gone.
2190 * So some systems react erratic at least.
2191 *
2192 * Frank Kardel
2193 *
2194 * 94-11-16:
2195 * Further debugging has proven that the above is
2196 * absolutely harmful. The internal resolver
2197 * is still in the SIGIO process group and the lingering
2198 * async io information causes it to process requests from
2199 * all file decriptor causing a race between the NTP daemon
2200 * and the resolver. which then eats data when it wins 8-(.
2201 * It is absolutly necessary to kill any IO associations
2202 * shared with the NTP daemon.
2203 *
2204 * We also block SIGIO (currently no ports means to
2205 * disable the signal handle for IO).
2206 *
2207 * Thanks to wgstuken@informatik.uni-erlangen.de to notice
2208 * that it is the ntp-resolver child running into trouble.
2209 *
2210 * THUS:
2211 */
2212
2213 closelog();
2214 kill_asyncio();
2215
2216 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2217
2218#ifdef DEBUG
2219 if (0)
2220 debug = 2;
2221#endif
2222
2223# ifndef LOG_DAEMON
2224 openlog("ntpd_initres", LOG_PID);
2225# else /* LOG_DAEMON */
2226
2227# ifndef LOG_NTP
2228# define LOG_NTP LOG_DAEMON
2229# endif
2230 openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP);
2231#ifndef SYS_CYGWIN32
2232# ifdef DEBUG
2233 if (debug)
2234 setlogmask(LOG_UPTO(LOG_DEBUG));
2235 else
2236# endif /* DEBUG */
2237 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
2238# endif /* LOG_DAEMON */
2239#endif
2240
2241 ntp_intres();
2242
2243 /*
2244 * If we got here, the intres code screwed up.
2245 * Print something so we don't die without complaint
2246 */
2247 msyslog(LOG_ERR, "call to ntp_intres lost");
2248 abort_resolve();
2249 exit(1);
2250 }
2251#else
2252 /* vxWorks spawns a thread... -casey */
2253 i = sp (ntp_intres);
2254 /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/
2255#endif
2256 if (i == -1) {
2257 msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m");
2258 (void) signal_no_reset(SIGCHLD, SIG_DFL);
2259 abort_resolve();
2260 }
2261#else /* SYS_WINNT */
2262 {
2263 /* NT's equivalent of fork() is _spawn(), but the start point
2264 * of the new process is an executable filename rather than
2265 * a function name as desired here.
2266 */
2267 DWORD dwThreadId;
2268 fflush(stdout);
2269 if (!(ResolverThreadHandle = CreateThread(
2270 NULL, /* no security attributes */
2271 0, /* use default stack size */
2272 (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */
2273 NULL, /* argument to thread function */
2274 0, /* use default creation flags */
2275 &dwThreadId))) { /* returns the thread identifier */
2276 msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
2277 abort_resolve();
2278 }
2279 }
2280#endif /* SYS_WINNT */
2281#else /* VMS VX_WORKS */
2282 msyslog(LOG_ERR,
2283 "Name resolution not implemented for VMS - use numeric addresses");
2284 abort_resolve();
2285#endif /* VMS VX_WORKS */
2286}