diff options
Diffstat (limited to 'ntpd/ntp_config.c')
-rw-r--r-- | ntpd/ntp_config.c | 5715 |
1 files changed, 3915 insertions, 1800 deletions
diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index beb4c4847e71..db9682a74cbd 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -1,6 +1,14 @@ -/* - * ntp_config.c - read and apply configuration information +/* ntp_config.c + * + * This file contains the ntpd configuration code. + * + * Written By: Sachin Kamboj + * University of Delaware + * Newark, DE 19711 + * Some parts borrowed from the older ntp_config.c + * Copyright (c) 2006 */ + #ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -9,20 +17,30 @@ # include <netinfo/ni.h> #endif +#include "ntp.h" #include "ntpd.h" #include "ntp_io.h" #include "ntp_unixtime.h" #include "ntp_refclock.h" #include "ntp_filegen.h" #include "ntp_stdlib.h" +#include "ntp_assert.h" +#include "ntpd-opts.h" +/* + * Sim header. Currently unconditionally included + * PDMXXX This needs to be a conditional include + */ +#include "ntpsim.h" + #include <ntp_random.h> +#include "ntp_intres.h" #include <isc/net.h> #include <isc/result.h> #include <stdio.h> #include <ctype.h> #ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> +# include <sys/param.h> #endif #include <signal.h> #ifndef SIGCHLD @@ -36,7 +54,6 @@ #ifdef SYS_WINNT # include <io.h> -static HANDLE ResolverThreadHandle = NULL; HANDLE ResolverEventHandle; #else int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */ @@ -50,288 +67,55 @@ int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent p #include "ntp_config.h" #include "ntp_cmdargs.h" -extern int priority_done; - -/* - * These routines are used to read the configuration file at - * startup time. An entry in the file must fit on a single line. - * Entries are processed as multiple tokens separated by white space - * Lines are considered terminated when a '#' is encountered. Blank - * lines are ignored. - */ -/* - * Translation table - keywords to function index - */ -struct keyword { - const char *text; - int keytype; -}; - -/* - * Command keywords - */ -static struct keyword keywords[] = { - { "automax", CONFIG_AUTOMAX }, - { "broadcast", CONFIG_BROADCAST }, - { "broadcastclient", CONFIG_BROADCASTCLIENT }, - { "broadcastdelay", CONFIG_BDELAY }, - { "calldelay", CONFIG_CDELAY}, -#ifdef OPENSSL - { "crypto", CONFIG_CRYPTO }, -#endif /* OPENSSL */ - { "controlkey", CONFIG_CONTROLKEY }, - { "disable", CONFIG_DISABLE }, - { "driftfile", CONFIG_DRIFTFILE }, - { "enable", CONFIG_ENABLE }, - { "end", CONFIG_END }, - { "filegen", CONFIG_FILEGEN }, - { "fudge", CONFIG_FUDGE }, - { "includefile", CONFIG_INCLUDEFILE }, - { "keys", CONFIG_KEYS }, - { "keysdir", CONFIG_KEYSDIR }, - { "logconfig", CONFIG_LOGCONFIG }, - { "logfile", CONFIG_LOGFILE }, - { "manycastclient", CONFIG_MANYCASTCLIENT }, - { "manycastserver", CONFIG_MANYCASTSERVER }, - { "multicastclient", CONFIG_MULTICASTCLIENT }, - { "peer", CONFIG_PEER }, - { "phone", CONFIG_PHONE }, - { "pidfile", CONFIG_PIDFILE }, - { "discard", CONFIG_DISCARD }, - { "requestkey", CONFIG_REQUESTKEY }, - { "restrict", CONFIG_RESTRICT }, - { "revoke", CONFIG_REVOKE }, - { "server", CONFIG_SERVER }, - { "setvar", CONFIG_SETVAR }, - { "statistics", CONFIG_STATISTICS }, - { "statsdir", CONFIG_STATSDIR }, - { "tick", CONFIG_ADJ }, - { "tinker", CONFIG_TINKER }, - { "tos", CONFIG_TOS }, - { "trap", CONFIG_TRAP }, - { "trustedkey", CONFIG_TRUSTEDKEY }, - { "ttl", CONFIG_TTL }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "peer", "server", "broadcast" modifier keywords - */ -static struct keyword mod_keywords[] = { - { "autokey", CONF_MOD_SKEY }, - { "burst", CONF_MOD_BURST }, - { "iburst", CONF_MOD_IBURST }, - { "key", CONF_MOD_KEY }, - { "maxpoll", CONF_MOD_MAXPOLL }, - { "minpoll", CONF_MOD_MINPOLL }, - { "mode", CONF_MOD_MODE }, /* refclocks */ - { "noselect", CONF_MOD_NOSELECT }, - { "preempt", CONF_MOD_PREEMPT }, - { "true", CONF_MOD_TRUE }, - { "prefer", CONF_MOD_PREFER }, - { "ttl", CONF_MOD_TTL }, /* NTP peers */ - { "version", CONF_MOD_VERSION }, - { "dynamic", CONF_MOD_DYNAMIC }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "restrict" modifier keywords - */ -static struct keyword res_keywords[] = { - { "ignore", CONF_RES_IGNORE }, - { "limited", CONF_RES_LIMITED }, - { "kod", CONF_RES_DEMOBILIZE }, - { "lowpriotrap", CONF_RES_LPTRAP }, - { "mask", CONF_RES_MASK }, - { "nomodify", CONF_RES_NOMODIFY }, - { "nopeer", CONF_RES_NOPEER }, - { "noquery", CONF_RES_NOQUERY }, - { "noserve", CONF_RES_NOSERVE }, - { "notrap", CONF_RES_NOTRAP }, - { "notrust", CONF_RES_NOTRUST }, - { "ntpport", CONF_RES_NTPPORT }, - { "version", CONF_RES_VERSION }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "trap" modifier keywords - */ -static struct keyword trap_keywords[] = { - { "port", CONF_TRAP_PORT }, - { "interface", CONF_TRAP_INTERFACE }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "fudge" modifier keywords - */ -static struct keyword fudge_keywords[] = { - { "flag1", CONF_FDG_FLAG1 }, - { "flag2", CONF_FDG_FLAG2 }, - { "flag3", CONF_FDG_FLAG3 }, - { "flag4", CONF_FDG_FLAG4 }, - { "refid", CONF_FDG_REFID }, /* this mapping should be cleaned up (endianness, \0) - kd 20041031 */ - { "stratum", CONF_FDG_STRATUM }, - { "time1", CONF_FDG_TIME1 }, - { "time2", CONF_FDG_TIME2 }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "filegen" modifier keywords - */ -static struct keyword filegen_keywords[] = { - { "disable", CONF_FGEN_FLAG_DISABLE }, - { "enable", CONF_FGEN_FLAG_ENABLE }, - { "file", CONF_FGEN_FILE }, - { "link", CONF_FGEN_FLAG_LINK }, - { "nolink", CONF_FGEN_FLAG_NOLINK }, - { "type", CONF_FGEN_TYPE }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "type" modifier keywords - */ -static struct keyword fgen_types[] = { - { "age", FILEGEN_AGE }, - { "day", FILEGEN_DAY }, - { "month", FILEGEN_MONTH }, - { "none", FILEGEN_NONE }, - { "pid", FILEGEN_PID }, - { "week", FILEGEN_WEEK }, - { "year", FILEGEN_YEAR }, - { "", CONFIG_UNKNOWN} -}; - -/* - * "enable", "disable" modifier keywords - */ -static struct keyword flags_keywords[] = { - { "auth", PROTO_AUTHENTICATE }, - { "bclient", PROTO_BROADCLIENT }, - { "calibrate", PROTO_CAL }, - { "kernel", PROTO_KERNEL }, - { "monitor", PROTO_MONITOR }, - { "ntp", PROTO_NTP }, - { "stats", PROTO_FILEGEN }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "discard" modifier keywords - */ -static struct keyword discard_keywords[] = { - { "average", CONF_DISCARD_AVERAGE }, - { "minimum", CONF_DISCARD_MINIMUM }, - { "monitor", CONF_DISCARD_MONITOR }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "tinker" modifier keywords - */ -static struct keyword tinker_keywords[] = { - { "step", CONF_CLOCK_MAX }, - { "panic", CONF_CLOCK_PANIC }, - { "dispersion", CONF_CLOCK_PHI }, - { "stepout", CONF_CLOCK_MINSTEP }, - { "allan", CONF_CLOCK_ALLAN }, - { "huffpuff", CONF_CLOCK_HUFFPUFF }, - { "freq", CONF_CLOCK_FREQ }, - { "", CONFIG_UNKNOWN } -}; - -/* - * "tos" modifier keywords - */ -static struct keyword tos_keywords[] = { - { "minclock", CONF_TOS_MINCLOCK }, - { "maxclock", CONF_TOS_MAXCLOCK }, - { "minsane", CONF_TOS_MINSANE }, - { "floor", CONF_TOS_FLOOR }, - { "ceiling", CONF_TOS_CEILING }, - { "cohort", CONF_TOS_COHORT }, - { "mindist", CONF_TOS_MINDISP }, - { "maxdist", CONF_TOS_MAXDIST }, - { "maxhop", CONF_TOS_MAXHOP }, - { "beacon", CONF_TOS_BEACON }, - { "orphan", CONF_TOS_ORPHAN }, - { "", CONFIG_UNKNOWN } -}; - -#ifdef OPENSSL -/* - * "crypto" modifier keywords - */ -static struct keyword crypto_keywords[] = { - { "cert", CONF_CRYPTO_CERT }, - { "gqpar", CONF_CRYPTO_GQPAR }, - { "host", CONF_CRYPTO_RSA }, - { "ident", CONF_CRYPTO_IDENT }, - { "iffpar", CONF_CRYPTO_IFFPAR }, - { "leap", CONF_CRYPTO_LEAP }, - { "mvpar", CONF_CRYPTO_MVPAR }, - { "pw", CONF_CRYPTO_PW }, - { "randfile", CONF_CRYPTO_RAND }, - { "sign", CONF_CRYPTO_SIGN }, - { "", CONFIG_UNKNOWN } -}; -#endif /* OPENSSL */ +#include "ntp_scanner.h" +#include "ntp_parser.h" +#include "ntp_data_structures.h" -/* - * Address type selection, IPv4 or IPv4. - * Used on various lines. - */ -static struct keyword addr_type[] = { - { "-4", CONF_ADDR_IPV4 }, - { "-6", CONF_ADDR_IPV6 }, - { "", CONFIG_UNKNOWN } -}; /* * "logconfig" building blocks */ struct masks { - const char *name; - unsigned long mask; + const char * const name; + const u_int32 mask; }; static struct masks logcfg_class[] = { - { "clock", NLOG_OCLOCK }, - { "peer", NLOG_OPEER }, - { "sync", NLOG_OSYNC }, - { "sys", NLOG_OSYS }, - { (char *)0, 0 } + { "clock", NLOG_OCLOCK }, + { "peer", NLOG_OPEER }, + { "sync", NLOG_OSYNC }, + { "sys", NLOG_OSYS }, + { NULL, 0 } }; -static struct masks logcfg_item[] = { +/* logcfg_noclass_items[] masks are complete and must not be shifted */ +static struct masks logcfg_noclass_items[] = { + { "allall", NLOG_SYSMASK | NLOG_PEERMASK | NLOG_CLOCKMASK | NLOG_SYNCMASK }, + { "allinfo", NLOG_SYSINFO | NLOG_PEERINFO | NLOG_CLOCKINFO | NLOG_SYNCINFO }, + { "allevents", NLOG_SYSEVENT | NLOG_PEEREVENT | NLOG_CLOCKEVENT | NLOG_SYNCEVENT }, + { "allstatus", NLOG_SYSSTATUS | NLOG_PEERSTATUS | NLOG_CLOCKSTATUS | NLOG_SYNCSTATUS }, + { "allstatistics", NLOG_SYSSTATIST | NLOG_PEERSTATIST | NLOG_CLOCKSTATIST | NLOG_SYNCSTATIST }, + /* the remainder are misspellings of clockall, peerall, sysall, and syncall. */ + { "allclock", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OCLOCK }, + { "allpeer", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OPEER }, + { "allsys", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYS }, + { "allsync", (NLOG_INFO | NLOG_STATIST | NLOG_EVENT | NLOG_STATUS) << NLOG_OSYNC }, + { NULL, 0 } +}; + +/* logcfg_class_items[] masks are shiftable by NLOG_O* counts */ +static struct masks logcfg_class_items[] = { + { "all", NLOG_INFO | NLOG_EVENT | NLOG_STATUS | NLOG_STATIST }, { "info", NLOG_INFO }, - { "allinfo", NLOG_SYSINFO|NLOG_PEERINFO|NLOG_CLOCKINFO|NLOG_SYNCINFO }, { "events", NLOG_EVENT }, - { "allevents", NLOG_SYSEVENT|NLOG_PEEREVENT|NLOG_CLOCKEVENT|NLOG_SYNCEVENT }, { "status", NLOG_STATUS }, - { "allstatus", NLOG_SYSSTATUS|NLOG_PEERSTATUS|NLOG_CLOCKSTATUS|NLOG_SYNCSTATUS }, { "statistics", NLOG_STATIST }, - { "allstatistics", NLOG_SYSSTATIST|NLOG_PEERSTATIST|NLOG_CLOCKSTATIST|NLOG_SYNCSTATIST }, - { "allclock", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OCLOCK }, - { "allpeer", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OPEER }, - { "allsys", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYS }, - { "allsync", (NLOG_INFO|NLOG_STATIST|NLOG_EVENT|NLOG_STATUS)<<NLOG_OSYNC }, - { "all", NLOG_SYSMASK|NLOG_PEERMASK|NLOG_CLOCKMASK|NLOG_SYNCMASK }, - { (char *)0, 0 } + { NULL, 0 } }; -/* - * Limits on things - */ -#define MAXTOKENS 20 /* 20 tokens on line */ -#define MAXLINE 1024 /* maximum length of line */ +/* Limits */ #define MAXPHONE 10 /* maximum number of phone strings */ #define MAXPPS 20 /* maximum length of PPS device string */ -#define MAXINCLUDELEVEL 5 /* maximum include file levels */ /* * Miscellaneous macros @@ -341,14 +125,11 @@ static struct masks logcfg_item[] = { #define ISSPACE(c) ((c) == ' ' || (c) == '\t') #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) -#define KEY_TYPE_MD5 4 - /* * File descriptor used by the resolver save routines, and temporary file * name. */ int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */ -static FILE *res_fp; #ifndef SYS_WINNT static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */ #define RES_TEMPFILE "/tmp/ntpXXXXXX" @@ -359,25 +140,38 @@ static char res_file[MAX_PATH]; /* * Definitions of things either imported from or exported to outside */ - -short default_ai_family = AF_UNSPEC; /* Default either IPv4 or IPv6 */ -char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */ -char *keysdir = NTP_KEYSDIR; /* crypto keys directory */ +extern int yydebug; /* ntp_parser.c (.y) */ +int curr_include_level; /* The current include level */ +struct FILE_INFO *fp[MAXINCLUDELEVEL+1]; +FILE *res_fp; +struct config_tree cfgt; /* Parser output stored here */ +struct config_tree *cfg_tree_history = NULL; /* History of configs */ +char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */ +char default_keysdir[] = NTP_KEYSDIR; +char *keysdir = default_keysdir; /* crypto keys directory */ +char * saveconfigdir; #if defined(HAVE_SCHED_SETSCHEDULER) int config_priority_override = 0; int config_priority; #endif const char *config_file; +char default_ntp_signd_socket[] = +#ifdef NTP_SIGND_PATH + NTP_SIGND_PATH; +#else + ""; +#endif +char *ntp_signd_socket = default_ntp_signd_socket; #ifdef HAVE_NETINFO - struct netinfo_config_state *config_netinfo = NULL; - int check_netinfo = 1; +struct netinfo_config_state *config_netinfo = NULL; +int check_netinfo = 1; #endif /* HAVE_NETINFO */ #ifdef SYS_WINNT - char *alt_config_file; - LPTSTR temp; - char config_file_storage[MAX_PATH]; - char alt_config_file_storage[MAX_PATH]; +char *alt_config_file; +LPTSTR temp; +char config_file_storage[MAX_PATH]; +char alt_config_file_storage[MAX_PATH]; #endif /* SYS_WINNT */ #ifdef HAVE_NETINFO @@ -393,1513 +187,3744 @@ struct netinfo_config_state { }; #endif +struct REMOTE_CONFIG_INFO remote_config; /* Remote configuration buffer and + pointer info */ +int input_from_file = 1; /* A boolean flag, which when set, indicates that + the input is to be taken from the configuration + file, instead of the remote-configuration buffer + */ + +int old_config_style = 1; /* A boolean flag, which when set, + * indicates that the old configuration + * format with a newline at the end of + * every command is being used + */ +int cryptosw; /* crypto command called */ + +extern int sys_maxclock; +extern char *stats_drift_file; /* name of the driftfile */ +extern char *leapseconds_file_name; /*name of the leapseconds file */ +#ifdef HAVE_IPTOS_SUPPORT +extern unsigned int qos; /* QoS setting */ +#endif /* HAVE_IPTOS_SUPPORT */ + +#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED /* - * Function prototypes + * backwards compatibility flags */ -static unsigned long get_pfxmatch P((char **, struct masks *)); -static unsigned long get_match P((char *, struct masks *)); -static unsigned long get_logmask P((char *)); -#ifdef HAVE_NETINFO -static struct netinfo_config_state *get_netinfo_config P((void)); -static void free_netinfo_config P((struct netinfo_config_state *)); -static int gettokens_netinfo P((struct netinfo_config_state *, char **, int *)); +bc_entry bc_list[] = { + { T_Bc_bugXXXX, 1 } /* default enabled */ +}; + +/* + * declare an int pointer for each flag for quick testing without + * walking bc_list. If the pointer is consumed by libntp rather + * than ntpd, declare it in a libntp source file pointing to storage + * initialized with the appropriate value for other libntp clients, and + * redirect it to point into bc_list during ntpd startup. + */ +int *p_bcXXXX_enabled = &bc_list[0].enabled; #endif -static int gettokens P((FILE *, char *, char **, int *)); -static int matchkey P((char *, struct keyword *, int)); + +/* FUNCTION PROTOTYPES */ + +static void apply_enable_disable(queue *q, int enable); +static void init_syntax_tree(struct config_tree *); + +#ifdef FREE_CFG_T +static void free_auth_node(struct config_tree *); + +static void free_config_other_modes(struct config_tree *); +static void free_config_auth(struct config_tree *); +static void free_config_tos(struct config_tree *); +static void free_config_monitor(struct config_tree *); +static void free_config_access(struct config_tree *); +static void free_config_tinker(struct config_tree *); +static void free_config_system_opts(struct config_tree *); +static void free_config_logconfig(struct config_tree *); +static void free_config_phone(struct config_tree *); +static void free_config_qos(struct config_tree *); +static void free_config_setvar(struct config_tree *); +static void free_config_ttl(struct config_tree *); +static void free_config_trap(struct config_tree *); +static void free_config_fudge(struct config_tree *); +static void free_config_vars(struct config_tree *); +static void free_config_peers(struct config_tree *); +static void free_config_unpeers(struct config_tree *); +static void free_config_nic_rules(struct config_tree *); +#ifdef SIM +static void free_config_sim(struct config_tree *); +#endif + + void free_all_config_trees(void); /* atexit() */ +static void free_config_tree(struct config_tree *ptree); +#endif /* FREE_CFG_T */ + +double *create_dval(double val); +void destroy_restrict_node(struct restrict_node *my_node); +static int is_sane_resolved_address(sockaddr_u *peeraddr, int hmode); +static int get_correct_host_mode(int hmode); +static void save_and_apply_config_tree(void); +void getconfig(int argc,char *argv[]); +#if !defined(SIM) +static sockaddr_u *get_next_address(struct address_node *addr); +#endif + +static void config_other_modes(struct config_tree *); +static void config_auth(struct config_tree *); +static void config_tos(struct config_tree *); +static void config_monitor(struct config_tree *); +static void config_access(struct config_tree *); +static void config_tinker(struct config_tree *); +static void config_system_opts(struct config_tree *); +static void config_logconfig(struct config_tree *); +static void config_phone(struct config_tree *); +static void config_qos(struct config_tree *); +static void config_setvar(struct config_tree *); +static void config_ttl(struct config_tree *); +static void config_trap(struct config_tree *); +static void config_fudge(struct config_tree *); +static void config_vars(struct config_tree *); +static void config_peers(struct config_tree *); +static void config_unpeers(struct config_tree *); +static void config_nic_rules(struct config_tree *); + +#ifdef SIM +static void config_sim(struct config_tree *); +static void config_ntpdsim(struct config_tree *); +#else +static void config_ntpd(struct config_tree *); +#endif + enum gnn_type { t_UNK, /* Unknown */ t_REF, /* Refclock */ t_MSK /* Network Mask */ - }; -static int getnetnum P((const char *, struct sockaddr_storage *, int, - enum gnn_type)); -static void save_resolve P((char *, int, int, int, int, u_int, int, - keyid_t, u_char *)); -static void do_resolve_internal P((void)); -static void abort_resolve P((void)); -#if !defined(VMS) && !defined(SYS_WINNT) -static RETSIGTYPE catchchild P((int)); -#endif /* VMS */ +}; -/* - * get_pfxmatch - find value for prefixmatch - * and update char * accordingly +#define DESTROY_QUEUE(q) \ +do { \ + if (q) { \ + destroy_queue(q); \ + (q) = NULL; \ + } \ +} while (0) + +void ntpd_set_tod_using(const char *); +static u_int32 get_pfxmatch(const char **, struct masks *); +static u_int32 get_match(const char *, struct masks *); +static u_int32 get_logmask(const char *); +static int getnetnum(const char *num,sockaddr_u *addr, int complain, + enum gnn_type a_type); +static int get_multiple_netnums(const char *num, sockaddr_u *addr, + struct addrinfo **res, int complain, + enum gnn_type a_type); +static void save_resolve(char *name, int no_needed, int type, + int mode, int version, int minpoll, int maxpoll, + u_int flags, int ttl, keyid_t keyid, u_char *keystr); +static void abort_resolve(void); +static void do_resolve_internal(void); + + + +/* FUNCTIONS FOR INITIALIZATION + * ---------------------------- */ -static unsigned long -get_pfxmatch( - char ** s, - struct masks *m + +#ifdef FREE_CFG_T +static void +free_auth_node( + struct config_tree *ptree ) { - while (m->name) { - if (strncmp(*s, m->name, strlen(m->name)) == 0) { - *s += strlen(m->name); - return m->mask; - } else { - m++; - } + if (ptree->auth.keys) { + free(ptree->auth.keys); + ptree->auth.keys = NULL; } - return 0; -} -/* - * get_match - find logmask value - */ -static unsigned long -get_match( - char *s, - struct masks *m - ) -{ - while (m->name) { - if (strcmp(s, m->name) == 0) { - return m->mask; - } else { - m++; - } + if (ptree->auth.keysdir) { + free(ptree->auth.keysdir); + ptree->auth.keysdir = NULL; + } + + if (ptree->auth.ntp_signd_socket) { + free(ptree->auth.ntp_signd_socket); + ptree->auth.ntp_signd_socket = NULL; } - return 0; } +#endif /* DEBUG */ -/* - * get_logmask - build bitmask for ntp_syslogmask - */ -static unsigned long -get_logmask( - char *s + +static void +init_syntax_tree( + struct config_tree *ptree ) { - char *t; - unsigned long offset; - unsigned long mask; + memset(ptree, 0, sizeof(*ptree)); + + ptree->peers = create_queue(); + ptree->unpeers = create_queue(); + ptree->orphan_cmds = create_queue(); + ptree->manycastserver = create_queue(); + ptree->multicastclient = create_queue(); + ptree->stats_list = create_queue(); + ptree->filegen_opts = create_queue(); + ptree->discard_opts = create_queue(); + ptree->restrict_opts = create_queue(); + ptree->enable_opts = create_queue(); + ptree->disable_opts = create_queue(); + ptree->tinker = create_queue(); + ptree->fudge = create_queue(); + ptree->logconfig = create_queue(); + ptree->phone = create_queue(); + ptree->qos = create_queue(); + ptree->setvar = create_queue(); + ptree->ttl = create_queue(); + ptree->trap = create_queue(); + ptree->vars = create_queue(); + ptree->nic_rules = create_queue(); + ptree->auth.crypto_cmd_list = create_queue(); + ptree->auth.trusted_key_list = create_queue(); +} - t = s; - offset = get_pfxmatch(&t, logcfg_class); - mask = get_match(t, logcfg_item); - if (mask) - return mask << offset; - else - msyslog(LOG_ERR, "logconfig: illegal argument %s - ignored", s); +#ifdef FREE_CFG_T +void +free_all_config_trees(void) +{ + struct config_tree *ptree; + struct config_tree *pnext; - return 0; + ptree = cfg_tree_history; + + while (ptree != NULL) { + pnext = ptree->link; + free_config_tree(ptree); + ptree = pnext; + } } -/* - * getconfig - get command line options and read the configuration file - */ -void -getconfig( - int argc, - char *argv[] +static void +free_config_tree( + struct config_tree *ptree ) { - register int i; - int c; - int errflg; - int status; - int istart; - int peerversion; - int minpoll; - int maxpoll; - int ttl; - long stratum; - unsigned long ul; - keyid_t peerkey; - u_char *peerkeystr; - u_long fudgeflag; - u_int peerflags; - int hmode; - struct sockaddr_storage peeraddr; - struct sockaddr_storage maskaddr; - FILE *fp[MAXINCLUDELEVEL+1]; - FILE *includefile; - int includelevel = 0; - char line[MAXLINE]; - char *(tokens[MAXTOKENS]); - int ntokens = 0; - int tok = CONFIG_UNKNOWN; - struct interface *localaddr; - struct refclockstat clock_stat; - FILEGEN *filegen; +#if defined(_MSC_VER) && defined (_DEBUG) + _CrtCheckMemory(); +#endif + if (ptree->source.value.s != NULL) + free(ptree->source.value.s); + + free_config_other_modes(ptree); + free_config_auth(ptree); + free_config_tos(ptree); + free_config_monitor(ptree); + free_config_access(ptree); + free_config_tinker(ptree); + free_config_system_opts(ptree); + free_config_logconfig(ptree); + free_config_phone(ptree); + free_config_qos(ptree); + free_config_setvar(ptree); + free_config_ttl(ptree); + free_config_trap(ptree); + free_config_fudge(ptree); + free_config_vars(ptree); + free_config_peers(ptree); + free_config_unpeers(ptree); + free_config_nic_rules(ptree); +#ifdef SIM + free_config_sim(ptree); +#endif /* - * Initialize, initialize + * Most of these DESTROY_QUEUE()s are handled already by the + * free_config_*() routines above but it's safe to use twice. + * Please feel free to remove ones you verified are handled + * in a free_config_*() routine. */ - errflg = 0; - -#ifndef SYS_WINNT - config_file = CONFIG_FILE; -#else - temp = CONFIG_FILE; - if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { - msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); - exit(1); - } - config_file = config_file_storage; + DESTROY_QUEUE(ptree->peers); + DESTROY_QUEUE(ptree->unpeers); + DESTROY_QUEUE(ptree->orphan_cmds); + DESTROY_QUEUE(ptree->manycastserver); + DESTROY_QUEUE(ptree->multicastclient); + DESTROY_QUEUE(ptree->stats_list); + DESTROY_QUEUE(ptree->filegen_opts); + DESTROY_QUEUE(ptree->discard_opts); + DESTROY_QUEUE(ptree->restrict_opts); + DESTROY_QUEUE(ptree->enable_opts); + DESTROY_QUEUE(ptree->disable_opts); + DESTROY_QUEUE(ptree->tinker); + DESTROY_QUEUE(ptree->fudge); + DESTROY_QUEUE(ptree->logconfig); + DESTROY_QUEUE(ptree->phone); + DESTROY_QUEUE(ptree->qos); + DESTROY_QUEUE(ptree->setvar); + DESTROY_QUEUE(ptree->ttl); + DESTROY_QUEUE(ptree->trap); + DESTROY_QUEUE(ptree->vars); + + free_auth_node(ptree); + + free(ptree); + +#if defined(_MSC_VER) && defined (_DEBUG) + _CrtCheckMemory(); +#endif +} +#endif /* FREE_CFG_T */ - temp = ALT_CONFIG_FILE; - if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { - msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); - exit(1); + +#ifdef SAVECONFIG +/* Dump all trees */ +int +dump_all_config_trees( + FILE *df, + int comment + ) +{ + struct config_tree *cfg_ptr = cfg_tree_history; + int return_value = 0; + + for (cfg_ptr = cfg_tree_history; + cfg_ptr != NULL; + cfg_ptr = cfg_ptr->link) + return_value |= dump_config_tree(cfg_ptr, df, comment); + + return return_value; +} + + +/* The config dumper */ +int +dump_config_tree( + struct config_tree *ptree, + FILE *df, + int comment + ) +{ + struct peer_node *peer = NULL; + struct unpeer_node *unpeers = NULL; + struct attr_val *atrv = NULL; + struct address_node *addr = NULL; + struct address_node *peer_addr; + struct address_node *fudge_addr; + struct filegen_node *fgen_node = NULL; + struct restrict_node *rest_node = NULL; + struct addr_opts_node *addr_opts = NULL; + struct setvar_node *setv_node = NULL; + nic_rule_node *rule_node; + + char **pstr = NULL; + char *s1; + char *s2; + int *intp = NULL; + void *fudge_ptr; + void *list_ptr = NULL; + void *options = NULL; + void *opt_ptr = NULL; + int *flags = NULL; + void *opts = NULL; + char timestamp[80]; + int enable; + + DPRINTF(1, ("dump_config_tree(%p)\n", ptree)); + + if (comment) { + if (!strftime(timestamp, sizeof(timestamp), + "%Y-%m-%d %H:%M:%S", + localtime(&ptree->timestamp))) + timestamp[0] = '\0'; + + fprintf(df, "# %s %s %s\n", + timestamp, + (CONF_SOURCE_NTPQ == ptree->source.attr) + ? "ntpq remote config from" + : "startup configuration file", + ptree->source.value.s); } - alt_config_file = alt_config_file_storage; -#endif /* SYS_WINNT */ - res_fp = NULL; - ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */ + /* For options I didn't find documentation I'll just output its name and the cor. value */ + list_ptr = queue_head(ptree->vars); + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { - /* - * install a non default variable with this daemon version - */ - (void) sprintf(line, "daemon_version=\"%s\"", Version); - set_sys_var(line, strlen(line)+1, RO); + atrv = (struct attr_val *) list_ptr; - /* - * Say how we're setting the time of day - */ - (void) sprintf(line, "settimeofday=\"%s\"", set_tod_using); - set_sys_var(line, strlen(line)+1, RO); + switch (atrv->attr) { - /* - * Initialize the loop. - */ - loop_config(LOOP_DRIFTINIT, 0.); + default: + fprintf(df, "\n# dump error:\n" + "# unknown vars token %s\n", + token_name(atrv->attr)); + break; - getCmdOpts(argc, argv); + /* doubles */ + case T_Broadcastdelay: + case T_Tick: + case T_WanderThreshold: + fprintf(df, "%s %g\n", + keyword(atrv->attr), + atrv->value.d); + break; + + /* ints */ + case T_Calldelay: +#ifdef OPENSSL + case T_Automax: +#endif + fprintf(df, "%s %d\n", + keyword(atrv->attr), + atrv->value.i); + break; - if ( - (fp[0] = fopen(FindConfig(config_file), "r")) == NULL -#ifdef HAVE_NETINFO - /* If there is no config_file, try NetInfo. */ - && check_netinfo && !(config_netinfo = get_netinfo_config()) -#endif /* HAVE_NETINFO */ - ) { - fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); - msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); -#ifdef SYS_WINNT - /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ + /* strings */ + case T_Driftfile: + case T_Leapfile: + case T_Logfile: + case T_Pidfile: + case T_Saveconfigdir: + fprintf(df, "%s \"%s\"\n", + keyword(atrv->attr), + atrv->value.s); + break; + } + } - if ((fp[0] = fopen(FindConfig(alt_config_file), "r")) == NULL) { + list_ptr = queue_head(ptree->logconfig); + if (list_ptr != NULL) { + + fprintf(df, "logconfig"); - /* - * Broadcast clients can sometimes run without - * a configuration file. - */ + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { - fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); - msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); - return; + atrv = list_ptr; + fprintf(df, " %c%s", atrv->attr, atrv->value.s); } -#else /* not SYS_WINNT */ - return; -#endif /* not SYS_WINNT */ + fprintf(df, "\n"); } - for (;;) { - if (tok == CONFIG_END) - break; - if (fp[includelevel]) - tok = gettokens(fp[includelevel], line, tokens, &ntokens); -#ifdef HAVE_NETINFO - else - tok = gettokens_netinfo(config_netinfo, tokens, &ntokens); -#endif /* HAVE_NETINFO */ + if (ptree->stats_dir) + fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir); - if (tok == CONFIG_UNKNOWN) { - if (includelevel > 0) { - fclose(fp[includelevel--]); - continue; - } else { - break; - } - } - - switch(tok) { - case CONFIG_PEER: - case CONFIG_SERVER: - case CONFIG_MANYCASTCLIENT: - case CONFIG_BROADCAST: - if (tok == CONFIG_PEER) - hmode = MODE_ACTIVE; - else if (tok == CONFIG_SERVER) - hmode = MODE_CLIENT; - else if (tok == CONFIG_MANYCASTCLIENT) - hmode = MODE_CLIENT; - else - hmode = MODE_BROADCAST; + list_ptr = queue_head(ptree->stats_list); + if (list_ptr != NULL) { - if (ntokens < 2) { - msyslog(LOG_ERR, - "No address for %s, line ignored", - tokens[0]); + fprintf(df, "statistics"); + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + intp = list_ptr; + + fprintf(df, " %s", keyword(*intp)); + } + + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->filegen_opts); + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + fgen_node = list_ptr; + opt_ptr = queue_head(fgen_node->options); + + if (opt_ptr != NULL) + fprintf(df, "filegen %s", + keyword(fgen_node->filegen_token)); + + for(; opt_ptr != NULL; + opt_ptr = next_node(opt_ptr)) { + + atrv = opt_ptr; + + switch (atrv->attr) { + + default: + fprintf(df, "\n# dump error:\n" + "# unknown filegen option token %s\n" + "filegen %s", + token_name(atrv->attr), + keyword(fgen_node->filegen_token)); break; - } - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - peeraddr.ss_family = default_ai_family; - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; + case T_File: + fprintf(df, " file %s", + atrv->value.s); break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; + + case T_Type: + fprintf(df, " type %s", + keyword(atrv->value.i)); + break; + + case T_Flag: + fprintf(df, " %s", + keyword(atrv->value.i)); break; } - status = getnetnum(tokens[istart], &peeraddr, 0, t_UNK); - if (status == -1) - break; /* Found IPv6 address */ - if(status != 1) { - errflg = -1; - } else { - errflg = 0; + } - if ( -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - ISBADADR(&peeraddr)) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); - break; - } - /* - * Shouldn't be able to specify multicast - * address for server/peer! - * and unicast address for manycastclient! - */ - if (peeraddr.ss_family == AF_INET) { - if (((tok == CONFIG_SERVER) || - (tok == CONFIG_PEER)) && -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->auth.crypto_cmd_list); + if (list_ptr != NULL) { + fprintf(df, "crypto"); + + for (; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = list_ptr; + fprintf(df, " %s %s", keyword(atrv->attr), + atrv->value.s); + } + fprintf(df, "\n"); + } + + if (ptree->auth.revoke != 0) + fprintf(df, "revoke %d\n", ptree->auth.revoke); + + if (NULL != ptree->auth.keysdir) + fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir); + + if (NULL != ptree->auth.keys) + fprintf(df, "keys \"%s\"\n", ptree->auth.keys); + + atrv = queue_head(ptree->auth.trusted_key_list); + if (atrv != NULL) { + fprintf(df, "trustedkey"); + do { + if ('i' == atrv->attr) + fprintf(df, " %d", atrv->value.i); + else if ('-' == atrv->attr) + fprintf(df, " (%u ... %u)", + atrv->value.u >> 16, + atrv->value.u & 0xffff); + else + fprintf(df, "\n# dump error:\n" + "# unknown trustedkey attr %d\n" + "trustedkey", atrv->attr); + } while (NULL != (atrv = next_node(atrv))); + fprintf(df, "\n"); + } + + if (ptree->auth.control_key) + fprintf(df, "controlkey %d\n", ptree->auth.control_key); + + if (ptree->auth.request_key) + fprintf(df, "requestkey %d\n", ptree->auth.request_key); + + /* dump enable list, then disable list */ + for (enable = 1; enable >= 0; enable--) { + + list_ptr = (enable) + ? queue_head(ptree->enable_opts) + : queue_head(ptree->disable_opts); + + if (list_ptr != NULL) { + fprintf(df, (enable) + ? "enable" + : "disable"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = (struct attr_val *) list_ptr; + + fprintf(df, " %s", + keyword(atrv->value.i)); + } + fprintf(df, "\n"); + } + } + + list_ptr = queue_head(ptree->orphan_cmds); + if (list_ptr != NULL) + fprintf(df, "tos"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = list_ptr; + + switch (atrv->attr) { + + default: + fprintf(df, "\n# dump error:\n" + "# unknown tos token %s\n" + "tos", token_name(atrv->attr)); + break; + + /* ints */ + case T_Ceiling: + case T_Floor: + case T_Cohort: + case T_Orphan: + case T_Minclock: + case T_Maxclock: + case T_Minsane: + case T_Beacon: + fprintf(df, " %s %d", keyword(atrv->attr), + (int)atrv->value.d); + break; + + /* doubles */ + case T_Mindist: + case T_Maxdist: + fprintf(df, " %s %g", keyword(atrv->attr), + atrv->value.d); + break; + } + } + if (queue_head(ptree->orphan_cmds) != NULL) + fprintf(df, "\n"); + + list_ptr = queue_head(ptree->tinker); + if (list_ptr != NULL) { + + fprintf(df, "tinker"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = list_ptr; + fprintf(df, " %s %g", keyword(atrv->attr), + atrv->value.d); + } + + fprintf(df, "\n"); + } + + if (ptree->broadcastclient) + fprintf(df, "broadcastclient\n"); + + list_ptr = queue_head(ptree->peers); + for (; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + peer = list_ptr; + addr = peer->addr; + fprintf(df, "%s", keyword(peer->host_mode)); + + switch (addr->type) { + + default: + fprintf(df, "# dump error:\n" + "# unknown peer family %d for:\n" + "peer", addr->type); + break; + + case AF_UNSPEC: + break; + + case AF_INET: + fprintf(df, " -4"); + break; + + case AF_INET6: + fprintf(df, " -6"); + break; + } + fprintf(df, " %s", addr->address); + + if (peer->minpoll != 0) + fprintf(df, " minpoll %d", peer->minpoll); + + if (peer->maxpoll != 0) + fprintf(df, " maxpoll %d", peer->maxpoll); + + if (peer->ttl != 0) { + if (strlen(addr->address) > 8 + && !memcmp(addr->address, "127.127.", 8)) + fprintf(df, " mode %d", peer->ttl); + else + fprintf(df, " ttl %d", peer->ttl); + } + + if (peer->peerversion != NTP_VERSION) + fprintf(df, " version %d", peer->peerversion); + + if (peer->peerkey != 0) + fprintf(df, " key %d", peer->peerkey); + + if (peer->bias != 0.) + fprintf(df, " bias %g", peer->bias); + + for (atrv = queue_head(peer->peerflags); + atrv != NULL; + atrv = next_node(atrv)) { + + NTP_INSIST(T_Flag == atrv->attr); + NTP_INSIST(T_Integer == atrv->type); + + fprintf(df, " %s", keyword(atrv->value.i)); + } + + fprintf(df, "\n"); + + fudge_ptr = queue_head(ptree->fudge); + for(; fudge_ptr != NULL; + fudge_ptr = next_node(fudge_ptr)) { + + + addr_opts = (struct addr_opts_node *) fudge_ptr; + peer_addr = peer->addr; + fudge_addr = addr_opts->addr; + + s1 = peer_addr->address; + s2 = fudge_addr->address; + + if (!strcmp(s1, s2)) { + + fprintf(df, "fudge %s", addr_opts->addr->address); + + opts = queue_head(addr_opts->options); + + for(; opts != NULL; opts = next_node(opts)) { + atrv = (struct attr_val *) opts; + + switch (atrv->attr) { + + default: + fprintf(df, "\n# dump error:\n" + "# unknown fudge option %s\n" + "fudge %s", + token_name(atrv->attr), + addr_opts->addr->address); break; - } - if ((tok == CONFIG_MANYCASTCLIENT) && - !IN_CLASSD(ntohl(((struct sockaddr_in*)&peeraddr)->sin_addr.s_addr))) { - msyslog(LOG_ERR, - "attempt to configure invalid address %s", - stoa(&peeraddr)); + + /* doubles */ + case T_Time1: + case T_Time2: + fprintf(df, " %s %g", + keyword(atrv->attr), + atrv->value.d); + break; + + /* ints */ + case T_Stratum: + case T_Flag1: + case T_Flag2: + case T_Flag3: + case T_Flag4: + fprintf(df, " %s %d", + keyword(atrv->attr), + atrv->value.i); + break; + + /* strings */ + case T_Refid: + fprintf(df, " %s %s", + keyword(atrv->attr), + atrv->value.s); break; } } - else if(peeraddr.ss_family == AF_INET6) { - if (((tok == CONFIG_SERVER) || - (tok == CONFIG_PEER)) && -#ifdef REFCLOCK - !ISREFCLOCKADR(&peeraddr) && -#endif - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) { - msyslog(LOG_ERR, - "attempt to configure in valid address %s", - stoa(&peeraddr)); - break; - } - if ((tok == CONFIG_MANYCASTCLIENT) && - !IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)&peeraddr)->sin6_addr)) { - msyslog(LOG_ERR, - "attempt to configure in valid address %s", - stoa(&peeraddr)); - break; - } - } + fprintf(df, "\n"); } - if (peeraddr.ss_family == AF_INET6 && - isc_net_probeipv6() != ISC_R_SUCCESS) - break; + } + } - peerversion = NTP_VERSION; - minpoll = NTP_MINDPOLL; - maxpoll = NTP_MAXDPOLL; - peerkey = 0; - peerkeystr = (u_char *)"*"; - peerflags = 0; - ttl = 0; - istart++; - for (i = istart; i < ntokens; i++) - switch (matchkey(tokens[i], mod_keywords, 1)) { - case CONF_MOD_VERSION: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "peer/server version requires an argument"); - errflg = 1; - break; - } - peerversion = atoi(tokens[++i]); - if ((u_char)peerversion > NTP_VERSION - || (u_char)peerversion < NTP_OLDVERSION) { - msyslog(LOG_ERR, - "inappropriate version number %s, line ignored", - tokens[i]); - errflg = 1; - } - break; - - case CONF_MOD_KEY: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "key: argument required"); - errflg = 1; - break; - } - peerkey = (int)atol(tokens[++i]); - peerflags |= FLAG_AUTHENABLE; - break; - - case CONF_MOD_MINPOLL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "minpoll: argument required"); - errflg = 1; - break; - } - minpoll = atoi(tokens[++i]); - if (minpoll < NTP_MINPOLL) { - msyslog(LOG_INFO, - "minpoll: provided value (%d) is below minimum (%d)", - minpoll, NTP_MINPOLL); - minpoll = NTP_MINPOLL; - } - break; - - case CONF_MOD_MAXPOLL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "maxpoll: argument required" - ); - errflg = 1; - break; - } - maxpoll = atoi(tokens[++i]); - if (maxpoll > NTP_MAXPOLL) { - msyslog(LOG_INFO, - "maxpoll: provided value (%d) is above maximum (%d)", - maxpoll, NTP_MAXPOLL); - maxpoll = NTP_MAXPOLL; - } - break; - - case CONF_MOD_PREFER: - peerflags |= FLAG_PREFER; - break; - - case CONF_MOD_PREEMPT: - peerflags |= FLAG_PREEMPT; - break; - - case CONF_MOD_NOSELECT: - peerflags |= FLAG_NOSELECT; - break; - - case CONF_MOD_TRUE: - peerflags |= FLAG_TRUE; - - case CONF_MOD_BURST: - peerflags |= FLAG_BURST; - break; - - case CONF_MOD_IBURST: - peerflags |= FLAG_IBURST; - break; - - case CONF_MOD_DYNAMIC: - msyslog(LOG_WARNING, - "Warning: the \"dynamic\" keyword has been obsoleted" - " and will be removed in the next release\n"); - break; + list_ptr = queue_head(ptree->manycastserver); + if (list_ptr != NULL) { + addr = list_ptr; + fprintf(df, "manycastserver %s", addr->address); + for (addr = next_node(addr); + addr != NULL; + addr = next_node(addr)) + fprintf(df, " %s", addr->address); + fprintf(df, "\n"); + } -#ifdef OPENSSL - case CONF_MOD_SKEY: - peerflags |= FLAG_SKEY | - FLAG_AUTHENABLE; - break; -#endif /* OPENSSL */ + list_ptr = queue_head(ptree->multicastclient); + if (list_ptr != NULL) { + addr = list_ptr; + fprintf(df, "multicastclient %s", addr->address); + for (addr = next_node(addr); + addr != NULL; + addr = next_node(addr)) + fprintf(df, " %s", addr->address); + fprintf(df, "\n"); + } - case CONF_MOD_TTL: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "ttl: argument required"); - errflg = 1; - break; - } - ttl = atoi(tokens[++i]); - if (ttl >= MAX_TTL) { - msyslog(LOG_ERR, - "ttl: invalid argument"); - errflg = 1; - } - break; + list_ptr = queue_head(ptree->unpeers); + for (; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + unpeers = (struct unpeer_node *) list_ptr; + + fprintf(df, "unpeer %s\n", (unpeers->addr)->address); + } - case CONF_MOD_MODE: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "mode: argument required"); - errflg = 1; - break; - } - ttl = atoi(tokens[++i]); - break; - - case CONFIG_UNKNOWN: - errflg = 1; - break; - } - if (minpoll > maxpoll) { - msyslog(LOG_ERR, - "config error: minpoll > maxpoll"); - errflg = 1; + list_ptr = queue_head(ptree->discard_opts); + if (list_ptr != NULL) { + + fprintf(df, "discard"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = list_ptr; + fprintf(df, " %s %d", keyword(atrv->attr), + atrv->value.i); + } + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->restrict_opts); + for (; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + rest_node = list_ptr; + if (NULL == rest_node->addr) + s1 = "default"; + else + s1 = rest_node->addr->address; + + fprintf(df, "restrict %s", s1); + + if (rest_node->mask != NULL) + fprintf(df, " mask %s", + rest_node->mask->address); + + flags = queue_head(rest_node->flags); + for (; flags != NULL; flags = next_node(flags)) + fprintf(df, " %s", keyword(*flags)); + + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->nic_rules); + for (; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + rule_node = list_ptr; + fprintf(df, "interface %s %s\n", + keyword(rule_node->action), + (rule_node->match_class) + ? keyword(rule_node->match_class) + : rule_node->if_name); + } + + list_ptr = queue_head(ptree->phone); + if (list_ptr != NULL) { + + fprintf(df, "phone"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + pstr = list_ptr; + fprintf(df, " %s", *pstr); + } + + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->qos); + if (list_ptr != NULL) { + + fprintf(df, "qos"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + atrv = list_ptr; + fprintf(df, " %s", atrv->value.s); + } + + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->setvar); + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + setv_node = list_ptr; + s1 = quote_if_needed(setv_node->var); + s2 = quote_if_needed(setv_node->val); + fprintf(df, "setvar %s = %s", s1, s2); + free(s1); + free(s2); + + if (setv_node->isdefault) + fprintf(df, " default"); + + fprintf(df, "\n"); + } + + + list_ptr = queue_head(ptree->ttl); + if (list_ptr != NULL) { + + fprintf(df, "ttl"); + + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + intp = list_ptr; + fprintf(df, " %d", *intp); + } + + fprintf(df, "\n"); + } + + list_ptr = queue_head(ptree->trap); + for(; list_ptr != NULL; + list_ptr = next_node(list_ptr)) { + + addr_opts = list_ptr; + addr = addr_opts->addr; + + fprintf(df, "trap %s", addr->address); + + options = queue_head(addr_opts->options); + + for(; options != NULL; + options = next_node(options)) { + + atrv = options; + + switch (atrv->attr) { + + default: + fprintf(df, "\n# dump error:\n" + "# unknown trap token %d\n" + "trap %s", atrv->attr, + addr->address); + break; + + case T_Port: + fprintf(df, " port %d", atrv->value.i); + break; + + case T_Interface: + addr = (struct address_node *) atrv->value.p; + fprintf(df, " interface %s", addr->address); + break; } - if (errflg == 0) { - if (peer_config(&peeraddr, - ANY_INTERFACE_CHOOSE(&peeraddr), hmode, - peerversion, minpoll, maxpoll, peerflags, - ttl, peerkey, peerkeystr) == 0) { - msyslog(LOG_ERR, - "configuration of %s failed", - stoa(&peeraddr)); - } - } else if (errflg == -1) { - save_resolve(tokens[1], hmode, peerversion, - minpoll, maxpoll, peerflags, ttl, - peerkey, peerkeystr); + } + + fprintf(df, "\n"); + } + + return 0; +} +#endif /* SAVECONFIG */ + + +/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE + * ----------------------------------------------- + */ + +queue * +enqueue_in_new_queue( + void *my_node + ) +{ + queue *my_queue = create_queue(); + + enqueue(my_queue, my_node); + return my_queue; +} + +struct attr_val * +create_attr_dval( + int attr, + double value + ) +{ + struct attr_val *my_val; + + my_val = get_node(sizeof *my_val); + my_val->attr = attr; + my_val->value.d = value; + my_val->type = T_Double; + return my_val; +} + +struct attr_val * +create_attr_ival( + int attr, + int value + ) +{ + struct attr_val *my_val; + + my_val = get_node(sizeof *my_val); + my_val->attr = attr; + my_val->value.i = value; + my_val->type = T_Integer; + return my_val; +} + +struct attr_val * +create_attr_shorts( + int attr, + ntp_u_int16_t val1, + ntp_u_int16_t val2 + ) +{ + struct attr_val *my_val; + + my_val = get_node(sizeof *my_val); + my_val->attr = attr; + my_val->value.u = (val1 << 16) | val2; + my_val->type = T_Integer; + return my_val; +} + +struct attr_val * +create_attr_sval( + int attr, + char *s + ) +{ + struct attr_val *my_val; + + my_val = get_node(sizeof *my_val); + my_val->attr = attr; + if (NULL == s) /* free() hates NULL */ + s = estrdup(""); + my_val->value.s = s; + my_val->type = T_String; + return my_val; +} + +struct attr_val * +create_attr_pval( + int attr, + void *p + ) +{ + struct attr_val *my_val; + + my_val = get_node(sizeof *my_val); + my_val->attr = attr; + my_val->value.p = p; + my_val->type = T_Void; + return my_val; +} + +int * +create_ival( + int val + ) +{ + int *p = get_node(sizeof *p); + + *p = val; + return p; +} + +double * +create_dval( + double val + ) +{ + double *p = get_node(sizeof *p); + + *p = val; + return p; +} + +void ** +create_pval( + void *val + ) +{ + void **p = get_node(sizeof *p); + + *p = val; + return p; +} + +struct address_node * +create_address_node( + char *addr, + int type + ) +{ + struct address_node *my_node; + + NTP_REQUIRE(NULL != addr); + + my_node = get_node(sizeof *my_node); + + my_node->address = addr; + my_node->type = type; + + return my_node; +} + + +void +destroy_address_node( + struct address_node *my_node + ) +{ + NTP_REQUIRE(NULL != my_node); + NTP_REQUIRE(NULL != my_node->address); + + free(my_node->address); + free_node(my_node); +} + + +struct peer_node * +create_peer_node( + int hmode, + struct address_node *addr, + queue *options + ) +{ + struct peer_node *my_node; + struct attr_val *option; + int freenode; + int errflag = 0; + + my_node = get_node(sizeof(*my_node)); + + /* Initialize node values to default */ + my_node->minpoll = 0; + my_node->maxpoll = 0; + my_node->ttl = 0; + my_node->peerversion = NTP_VERSION; + my_node->peerkey = 0; + my_node->bias = 0; + my_node->peerflags = create_queue(); + + /* Now set the node to the read values */ + my_node->host_mode = hmode; + my_node->addr = addr; + + /* + * the options list mixes items that will be saved in the + * peer_node as explicit members, such as minpoll, and + * those that are moved from the options queue intact + * to the peer_node's peerflags queue. The options + * queue is consumed and destroyed here. + */ + + while (options && NULL != (option = dequeue(options))) { + + freenode = 1; + /* Check the kind of option being set */ + switch (option->attr) { + + case T_Flag: + enqueue(my_node->peerflags, option); + freenode = 0; + break; + + case T_Minpoll: + if (option->value.i < NTP_MINPOLL) { + msyslog(LOG_INFO, + "minpoll: provided value (%d) is below minimum (%d)", + option->value.i, NTP_MINPOLL); + my_node->minpoll = NTP_MINPOLL; } + else + my_node->minpoll = option->value.i; break; - case CONFIG_DRIFTFILE: - if (ntokens >= 2) - stats_config(STATS_FREQ_FILE, tokens[1]); + case T_Maxpoll: + if (option->value.i > NTP_MAXPOLL) { + msyslog(LOG_INFO, + "maxpoll: provided value (%d) is above maximum (%d)", + option->value.i, NTP_MAXPOLL); + my_node->maxpoll = NTP_MAXPOLL; + } else - stats_config(STATS_FREQ_FILE, (char *)0); - stats_write_period = stats_write_tolerance = 0; - if (ntokens >= 3) - stats_write_period = 60 * atol(tokens[2]); - if (stats_write_period <= 0) - stats_write_period = 3600; - if (ntokens >= 4) { - double ftemp; - sscanf(tokens[3], "%lf", &ftemp); - stats_write_tolerance = ftemp / 100; + my_node->maxpoll = option->value.i; + break; + + case T_Ttl: + if (my_node->ttl >= MAX_TTL) { + msyslog(LOG_ERR, "ttl: invalid argument"); + errflag = 1; } + else + my_node->ttl = option->value.i; + break; + + case T_Mode: + my_node->ttl = option->value.i; + break; + + case T_Key: + my_node->peerkey = option->value.i; + break; + + case T_Version: + my_node->peerversion = option->value.i; break; + + case T_Bias: + my_node->bias = option->value.d; + break; + + default: + msyslog(LOG_ERR, + "Unknown peer/server option token %s", + token_name(option->attr)); + errflag = 1; + } + if (freenode) + free_node(option); + } + DESTROY_QUEUE(options); + + /* Check if errors were reported. If yes, ignore the node */ + if (errflag) { + free_node(my_node); + my_node = NULL; + } + return my_node; +} + + +struct unpeer_node * +create_unpeer_node( + struct address_node *addr + ) +{ + struct unpeer_node * my_node; + char * pch; + + my_node = get_node(sizeof(*my_node)); + + /* + * From the parser's perspective an association ID fits into + * its generic T_String definition of a name/address "address". + * We treat all valid 16-bit numbers as association IDs. + */ + pch = addr->address; + while (*pch && isdigit(*pch)) + pch++; + + if (!*pch + && 1 == sscanf(addr->address, "%u", &my_node->assocID) + && my_node->assocID <= USHRT_MAX) { + + destroy_address_node(addr); + my_node->addr = NULL; + } else { + my_node->assocID = 0; + my_node->addr = addr; + } + + return my_node; +} + +struct filegen_node * +create_filegen_node( + int filegen_token, + queue * options + ) +{ + struct filegen_node *my_node; - case CONFIG_PIDFILE: - if (ntokens >= 2) - stats_config(STATS_PID_FILE, tokens[1]); - else - stats_config(STATS_PID_FILE, (char *)0); + my_node = get_node(sizeof *my_node); + my_node->filegen_token = filegen_token; + my_node->options = options; + + return my_node; +} + + +struct restrict_node * +create_restrict_node( + struct address_node *addr, + struct address_node *mask, + queue *flags, + int line_no + ) +{ + struct restrict_node *my_node; + + my_node = get_node(sizeof *my_node); + + my_node->addr = addr; + my_node->mask = mask; + my_node->flags = flags; + my_node->line_no = line_no; + + return my_node; +} + +void +destroy_restrict_node( + struct restrict_node *my_node + ) +{ + /* With great care, free all the memory occupied by + * the restrict node + */ + if (my_node->addr) + destroy_address_node(my_node->addr); + if (my_node->mask) + destroy_address_node(my_node->mask); + DESTROY_QUEUE(my_node->flags); + free_node(my_node); +} + + +struct setvar_node * +create_setvar_node( + char * var, + char * val, + int isdefault + ) +{ + char * pch; + struct setvar_node *my_node; + + /* do not allow = in the variable name */ + if (NULL != (pch = strchr(var, '='))) + *pch = '\0'; + + /* Now store the string into a setvar_node */ + my_node = get_node(sizeof *my_node); + my_node->var = var; + my_node->val = val; + my_node->isdefault = isdefault; + + return my_node; +} + + +nic_rule_node * +create_nic_rule_node( + int match_class, + char *if_name, /* interface name or numeric address */ + int action + ) +{ + nic_rule_node *my_node; + + NTP_REQUIRE(match_class != 0 || if_name != NULL); + + my_node = get_node(sizeof(*my_node)); + my_node->match_class = match_class; + my_node->if_name = if_name; + my_node->action = action; + + return my_node; +} + + +struct addr_opts_node * +create_addr_opts_node( + struct address_node *addr, + queue *options + ) +{ + struct addr_opts_node *my_node; + + my_node = get_node(sizeof *my_node); + my_node->addr = addr; + my_node->options = options; + return my_node; +} + +script_info * +create_sim_script_info( + double duration, + queue *script_queue + ) +{ +#ifdef SIM + return NULL; +#else + script_info *my_info; + struct attr_val *my_attr_val; + + my_info = get_node(sizeof *my_info); + + /* Initialize Script Info with default values*/ + my_info->duration = duration; + my_info->freq_offset = 0; + my_info->wander = 0; + my_info->jitter = 0; + my_info->prop_delay = NET_DLY; + my_info->proc_delay = PROC_DLY; + + /* Traverse the script_queue and fill out non-default values */ + my_attr_val = queue_head(script_queue); + while (my_attr_val != NULL) { + /* Set the desired value */ + switch (my_attr_val->attr) { + + case T_Freq_Offset: + my_info->freq_offset = my_attr_val->value.d; break; - case CONFIG_END: - for ( i = 0; i <= includelevel; i++ ) { - fclose(fp[i]); - } + case T_Wander: + my_info->wander = my_attr_val->value.d; break; - - case CONFIG_INCLUDEFILE: - if (ntokens < 2) { - msyslog(LOG_ERR, "includefile needs one argument"); - break; - } - if (includelevel >= MAXINCLUDELEVEL) { - fprintf(stderr, "getconfig: Maximum include file level exceeded.\n"); - msyslog(LOG_INFO, "getconfig: Maximum include file level exceeded."); - break; - } - includefile = fopen(FindConfig(tokens[1]), "r"); - if (includefile == NULL) { - fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(tokens[1])); - msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(tokens[1])); - break; - } - fp[++includelevel] = includefile; + + case T_Jitter: + my_info->jitter = my_attr_val->value.d; break; - case CONFIG_LOGFILE: - if (ntokens >= 2) { - FILE *new_file; + case T_Prop_Delay: + my_info->prop_delay = my_attr_val->value.d; + break; - new_file = fopen(tokens[1], "a"); - if (new_file != NULL) { - NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ - msyslog(LOG_NOTICE, "logging to file %s", tokens[1]); - if (syslog_file != NULL && - fileno(syslog_file) != fileno(new_file)) - (void)fclose(syslog_file); + case T_Proc_Delay: + my_info->proc_delay = my_attr_val->value.d; + break; - syslog_file = new_file; - syslogit = 0; - } - else - msyslog(LOG_ERR, - "Cannot open log file %s", - tokens[1]); - } - else - msyslog(LOG_ERR, "logfile needs one argument"); - break; - - case CONFIG_LOGCONFIG: - for (i = 1; i < ntokens; i++) - { - int add = 1; - int equals = 0; - char * s = &tokens[i][0]; - - switch (*s) { - case '+': - case '-': - case '=': - add = *s == '+'; - equals = *s == '='; - s++; - break; + default: + msyslog(LOG_ERR, + "Unknown script token %d", + my_attr_val->attr); + } + } + return (my_info); +#endif +} - default: - break; - } - if (equals) { - ntp_syslogmask = get_logmask(s); - } else { - if (add) { - ntp_syslogmask |= get_logmask(s); - } else { - ntp_syslogmask &= ~get_logmask(s); - } - } -#ifdef DEBUG - if (debug) - printf("ntp_syslogmask = 0x%08lx (%s)\n", ntp_syslogmask, tokens[i]); + +#if !defined(SIM) + +#define ADDR_LENGTH 16 + 1 + +static sockaddr_u * +get_next_address( + struct address_node *addr + ) +{ + const char addr_prefix[] = "192.168.0."; + static int curr_addr_no = 1; + char addr_string[ADDR_LENGTH]; + sockaddr_u *final_addr; + struct addrinfo *ptr; + int retval; + + final_addr = emalloc(sizeof *final_addr); + + if (addr->type == T_String) { + snprintf(addr_string, ADDR_LENGTH, "%s%d", addr_prefix, curr_addr_no++); + printf("Selecting ip address %s for hostname %s\n", addr_string, addr->address); + retval = getaddrinfo(addr_string, "ntp", NULL, &ptr); + } else + retval = getaddrinfo(addr->address, "ntp", NULL, &ptr); + + if (!retval) { + memcpy(final_addr, ptr->ai_addr, ptr->ai_addrlen); + fprintf(stderr, "Successful in setting ip address of simulated server to: %s\n", stoa(final_addr)); + } + else { + fprintf(stderr, "ERROR!! Could not get a new address\n"); + exit(1); + } + freeaddrinfo(ptr); + return final_addr; +} +#endif /* !SIM */ + + +server_info * +create_sim_server( + struct address_node *addr, + double server_offset, + queue *script + ) +{ +#ifdef SIM + return NULL; +#else + server_info *my_info; + + my_info = get_node(sizeof *my_info); + + my_info->server_time = server_offset; + my_info->addr = get_next_address(addr); + my_info->script = script; + my_info->curr_script = dequeue(my_info->script); + return my_info; +#endif /* SIM */ +} + +struct sim_node * +create_sim_node( + queue *init_opts, + queue *servers + ) +{ + struct sim_node *my_node; + + my_node = get_node(sizeof *my_node); + + my_node->init_opts = init_opts; + my_node->servers = servers; + return my_node; +} + + + + +/* FUNCTIONS FOR PERFORMING THE CONFIGURATION + * ------------------------------------------ + */ + +static void +config_other_modes( + struct config_tree *ptree + ) +{ + sockaddr_u addr_sock; + struct address_node *addr_node; + + if (ptree->broadcastclient) + proto_config(PROTO_BROADCLIENT, ptree->broadcastclient, 0., NULL); + + /* Configure the many-cast servers */ + addr_node = queue_head(ptree->manycastserver); + if (addr_node != NULL) { + do { + ZERO_SOCK(&addr_sock); + AF(&addr_sock) = (u_short)addr_node->type; + + if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK) == 1) + proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock); + + addr_node = next_node(addr_node); + } while (addr_node != NULL); + sys_manycastserver = 1; + } + + /* Configure the multicast clients */ + addr_node = queue_head(ptree->multicastclient); + if (addr_node != NULL) { + do { + ZERO_SOCK(&addr_sock); + AF(&addr_sock) = (u_short)addr_node->type; + + if (getnetnum(addr_node->address, &addr_sock, 1, t_UNK) == 1) + proto_config(PROTO_MULTICAST_ADD, 0, 0., &addr_sock); + + addr_node = next_node(addr_node); + } while (addr_node != NULL); + proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_other_modes( + struct config_tree *ptree + ) +{ + struct address_node *addr_node; + + while (NULL != (addr_node = dequeue(ptree->manycastserver))) + destroy_address_node(addr_node); + + while (NULL != (addr_node = dequeue(ptree->multicastclient))) + destroy_address_node(addr_node); +} +#endif /* FREE_CFG_T */ + + +static void +config_auth( + struct config_tree *ptree + ) +{ + ntp_u_int16_t ufirst; + ntp_u_int16_t ulast; + ntp_u_int16_t u; + struct attr_val *my_val; +#ifdef OPENSSL +#ifndef NO_INTRES + u_char digest[EVP_MAX_MD_SIZE]; + u_int digest_len; + EVP_MD_CTX ctx; #endif - } + int item; +#endif + + /* Crypto Command */ +#ifdef OPENSSL + item = -1; /* quiet warning */ + my_val = queue_head(ptree->auth.crypto_cmd_list); + while (my_val != NULL) { + switch (my_val->attr) { + + default: + NTP_INSIST(0); break; - case CONFIG_BROADCASTCLIENT: - if (ntokens == 1) { - proto_config(PROTO_BROADCLIENT, 1, 0., NULL); - } else { - proto_config(PROTO_BROADCLIENT, 2, 0., NULL); - } + case T_Host: + item = CRYPTO_CONF_PRIV; break; - case CONFIG_MULTICASTCLIENT: - case CONFIG_MANYCASTSERVER: - if (ntokens > 1) { - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - peeraddr.ss_family = default_ai_family; - switch (matchkey(tokens[istart], - addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; - break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; - break; - } - /* - * Abuse maskaddr to store the prefered ip - * version. - */ - memset((char *)&maskaddr, 0, sizeof(maskaddr)); - maskaddr.ss_family = peeraddr.ss_family; - - for (i = istart; i < ntokens; i++) { - memset((char *)&peeraddr, 0, - sizeof(peeraddr)); - peeraddr.ss_family = maskaddr.ss_family; - if (getnetnum(tokens[i], &peeraddr, 1, - t_UNK) == 1) - proto_config(PROTO_MULTICAST_ADD, - 0, 0., &peeraddr); - } - } else - proto_config(PROTO_MULTICAST_ADD, - 0, 0., NULL); - if (tok == CONFIG_MULTICASTCLIENT) - proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL); - else if (tok == CONFIG_MANYCASTSERVER) - sys_manycastserver = 1; + case T_Ident: + item = CRYPTO_CONF_IDENT; break; - case CONFIG_KEYS: - if (ntokens >= 2) { - getauthkeys(tokens[1]); - } + case T_Pw: + item = CRYPTO_CONF_PW; break; - case CONFIG_KEYSDIR: - if (ntokens < 2) { - msyslog(LOG_ERR, - "Keys directory name required"); - break; - } - keysdir = (char *)emalloc(strlen(tokens[1]) + 1); - strcpy(keysdir, tokens[1]); + case T_Randfile: + item = CRYPTO_CONF_RAND; break; - case CONFIG_TINKER: - for (i = 1; i < ntokens; i++) { - int temp; - double ftemp; + case T_Sign: + item = CRYPTO_CONF_SIGN; + break; - temp = matchkey(tokens[i++], tinker_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "tinker: missing argument"); - errflg++; - break; - } - sscanf(tokens[i], "%lf", &ftemp); - switch(temp) { + case T_Digest: + item = CRYPTO_CONF_NID; + break; + } + crypto_config(item, my_val->value.s); + my_val = next_node(my_val); + } +#endif /* OPENSSL */ - case CONF_CLOCK_MAX: - loop_config(LOOP_MAX, ftemp); - break; + /* Keysdir Command */ + if (ptree->auth.keysdir) { + if (keysdir != default_keysdir) + free(keysdir); + keysdir = estrdup(ptree->auth.keysdir); + } - case CONF_CLOCK_PANIC: - loop_config(LOOP_PANIC, ftemp); - break; - case CONF_CLOCK_PHI: - loop_config(LOOP_PHI, ftemp); - break; + /* ntp_signd_socket Command */ + if (ptree->auth.ntp_signd_socket) { + if (ntp_signd_socket != default_ntp_signd_socket) + free(ntp_signd_socket); + ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket); + } - case CONF_CLOCK_MINSTEP: - loop_config(LOOP_MINSTEP, ftemp); - break; +#ifdef OPENSSL + if (ptree->auth.cryptosw && !cryptosw) { + crypto_setup(); + cryptosw = 1; + } +#endif /* OPENSSL */ - case CONF_CLOCK_ALLAN: - loop_config(LOOP_ALLAN, ftemp); - break; + /* Keys Command */ + if (ptree->auth.keys) + getauthkeys(ptree->auth.keys); - case CONF_CLOCK_HUFFPUFF: - loop_config(LOOP_HUFFPUFF, ftemp); - break; + /* Control Key Command */ + if (ptree->auth.control_key) + ctl_auth_keyid = (keyid_t)ptree->auth.control_key; - case CONF_CLOCK_FREQ: - loop_config(LOOP_FREQ, ftemp); - break; - } - } - break; + /* Requested Key Command */ + if (ptree->auth.request_key) { + DPRINTF(4, ("set info_auth_keyid to %08lx\n", + (u_long) ptree->auth.request_key)); + info_auth_keyid = (keyid_t)ptree->auth.request_key; + } - case CONFIG_TOS: - for (i = 1; i < ntokens; i++) { - int temp; - double ftemp; + /* Trusted Key Command */ + my_val = queue_head(ptree->auth.trusted_key_list); + for (; my_val != NULL; my_val = next_node(my_val)) { + if ('i' == my_val->attr) + authtrust(my_val->value.i, 1); + else if ('-' == my_val->attr) { + ufirst = my_val->value.u >> 16; + ulast = my_val->value.u & 0xffff; + for (u = ufirst; u <= ulast; u++) + authtrust(u, 1); + } + } - temp = matchkey(tokens[i++], tos_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "tos: missing argument"); - errflg++; - break; - } - sscanf(tokens[i], "%lf", &ftemp); - switch(temp) { +#ifdef OPENSSL + /* crypto revoke command */ + if (ptree->auth.revoke) + sys_revoke = ptree->auth.revoke; +#endif /* OPENSSL */ - case CONF_TOS_MINCLOCK: - proto_config(PROTO_MINCLOCK, 0, ftemp, NULL); - break; +#ifndef NO_INTRES + /* find a keyid */ + if (info_auth_keyid == 0) + req_keyid = 65535; + else + req_keyid = info_auth_keyid; - case CONF_TOS_MAXCLOCK: - proto_config(PROTO_MAXCLOCK, 0, ftemp, NULL); - break; + /* if doesn't exist, make up one at random */ + if (authhavekey(req_keyid)) { + req_keytype = cache_type; +#ifndef OPENSSL + req_hashlen = 16; +#else /* OPENSSL follows */ + EVP_DigestInit(&ctx, EVP_get_digestbynid(req_keytype)); + EVP_DigestFinal(&ctx, digest, &digest_len); + req_hashlen = digest_len; +#endif + } else { + int rankey; - case CONF_TOS_MINSANE: - proto_config(PROTO_MINSANE, 0, ftemp, NULL); - break; + rankey = ntp_random(); + req_keytype = NID_md5; + req_hashlen = 16; + MD5auth_setkey(req_keyid, req_keytype, + (u_char *)&rankey, sizeof(rankey)); + authtrust(req_keyid, 1); + } - case CONF_TOS_FLOOR: - proto_config(PROTO_FLOOR, 0, ftemp, NULL); - break; + /* save keyid so we will accept config requests with it */ + info_auth_keyid = req_keyid; +#endif /* !NO_INTRES */ - case CONF_TOS_CEILING: - proto_config(PROTO_CEILING, 0, ftemp, NULL); - break; +} - case CONF_TOS_COHORT: - proto_config(PROTO_COHORT, 0, ftemp, NULL); - break; - case CONF_TOS_MINDISP: - proto_config(PROTO_MINDISP, 0, ftemp, NULL); - break; +#ifdef FREE_CFG_T +static void +free_config_auth( + struct config_tree *ptree + ) +{ + struct attr_val *my_val; - case CONF_TOS_MAXDIST: - proto_config(PROTO_MAXDIST, 0, ftemp, NULL); - break; + while (NULL != + (my_val = dequeue(ptree->auth.crypto_cmd_list))) { - case CONF_TOS_MAXHOP: - proto_config(PROTO_MAXHOP, 0, ftemp, NULL); - break; + free(my_val->value.s); + free_node(my_val); + } + DESTROY_QUEUE(ptree->auth.crypto_cmd_list); - case CONF_TOS_ORPHAN: - proto_config(PROTO_ORPHAN, 0, ftemp, NULL); - break; + DESTROY_QUEUE(ptree->auth.trusted_key_list); +} +#endif /* FREE_CFG_T */ - case CONF_TOS_BEACON: - proto_config(PROTO_BEACON, 0, ftemp, NULL); - break; - } - } + +static void +config_tos( + struct config_tree *ptree + ) +{ + struct attr_val *tos; + int item; + + item = -1; /* quiet warning */ + tos = queue_head(ptree->orphan_cmds); + while (tos != NULL) { + switch(tos->attr) { + + default: + NTP_INSIST(0); break; - case CONFIG_TTL: - for (i = 1; i < ntokens && i < MAX_TTL; i++) { - sys_ttl[i - 1] = (u_char) atoi(tokens[i]); - sys_ttlmax = i - 1; - } + case T_Ceiling: + item = PROTO_CEILING; break; - case CONFIG_DISCARD: - for (i = 1; i < ntokens; i++) { - int temp; + case T_Floor: + item = PROTO_FLOOR; + break; - temp = matchkey(tokens[i++], - discard_keywords, 1); - if (i > ntokens - 1) { - msyslog(LOG_ERR, - "discard: missing argument"); - errflg++; - break; - } - switch(temp) { - case CONF_DISCARD_AVERAGE: - res_avg_interval = atoi(tokens[i]); - break; + case T_Cohort: + item = PROTO_COHORT; + break; + + case T_Orphan: + item = PROTO_ORPHAN; + break; - case CONF_DISCARD_MINIMUM: - res_min_interval = atoi(tokens[i]); + case T_Mindist: + item = PROTO_MINDISP; + break; + + case T_Maxdist: + item = PROTO_MAXDIST; + break; + + case T_Minclock: + item = PROTO_MINCLOCK; + break; + + case T_Maxclock: + item = PROTO_MAXCLOCK; + break; + + case T_Minsane: + item = PROTO_MINSANE; + break; + + case T_Beacon: + item = PROTO_BEACON; + break; + } + proto_config(item, 0, tos->value.d, NULL); + tos = next_node(tos); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_tos( + struct config_tree *ptree + ) +{ + struct attr_val *tos; + + while (!empty(ptree->orphan_cmds)) { + tos = dequeue(ptree->orphan_cmds); + free_node(tos); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_monitor( + struct config_tree *ptree + ) +{ + int *pfilegen_token; + const char *filegen_string; + const char *filegen_file; + FILEGEN *filegen; + struct filegen_node *my_node; + struct attr_val *my_opts; + int filegen_type; + int filegen_flag; + + /* Set the statistics directory */ + if (ptree->stats_dir) + stats_config(STATS_STATSDIR, ptree->stats_dir); + + /* NOTE: + * Calling filegen_get is brain dead. Doing a string + * comparison to find the relavant filegen structure is + * expensive. + * + * Through the parser, we already know which filegen is + * being specified. Hence, we should either store a + * pointer to the specified structure in the syntax tree + * or an index into a filegen array. + * + * Need to change the filegen code to reflect the above. + */ + + /* Turn on the specified statistics */ + pfilegen_token = queue_head(ptree->stats_list); + while (pfilegen_token != NULL) { + filegen_string = keyword(*pfilegen_token); + filegen = filegen_get(filegen_string); + + DPRINTF(4, ("enabling filegen for %s statistics '%s%s'\n", + filegen_string, filegen->prefix, + filegen->basename)); + filegen->flag |= FGEN_FLAG_ENABLED; + pfilegen_token = next_node(pfilegen_token); + } + + /* Configure the statistics with the options */ + my_node = queue_head(ptree->filegen_opts); + while (my_node != NULL) { + filegen_file = keyword(my_node->filegen_token); + filegen = filegen_get(filegen_file); + + /* Initialize the filegen variables to their pre-configurtion states */ + filegen_flag = filegen->flag; + filegen_type = filegen->type; + + /* "filegen ... enabled" is the default (when filegen is used) */ + filegen_flag |= FGEN_FLAG_ENABLED; + + my_opts = queue_head(my_node->options); + while (my_opts != NULL) { + + switch (my_opts->attr) { + + case T_File: + filegen_file = my_opts->value.p; break; - case CONF_DISCARD_MONITOR: - mon_age = atoi(tokens[i]); + case T_Type: + switch (my_opts->value.i) { + + default: + NTP_INSIST(0); + break; + + case T_None: + filegen_type = FILEGEN_NONE; + break; + + case T_Pid: + filegen_type = FILEGEN_PID; + break; + + case T_Day: + filegen_type = FILEGEN_DAY; + break; + + case T_Week: + filegen_type = FILEGEN_WEEK; + break; + + case T_Month: + filegen_type = FILEGEN_MONTH; + break; + + case T_Year: + filegen_type = FILEGEN_YEAR; + break; + + case T_Age: + filegen_type = FILEGEN_AGE; + break; + } break; - default: - msyslog(LOG_ERR, - "discard: unknown keyword"); + case T_Flag: + switch (my_opts->value.i) { + + case T_Link: + filegen_flag |= FGEN_FLAG_LINK; + break; + + case T_Nolink: + filegen_flag &= ~FGEN_FLAG_LINK; + break; + + case T_Enable: + filegen_flag |= FGEN_FLAG_ENABLED; + break; + + case T_Disable: + filegen_flag &= ~FGEN_FLAG_ENABLED; + break; + + default: + msyslog(LOG_ERR, + "Unknown filegen flag token %d", + my_opts->value.i); + exit(1); + } break; - } + default: + msyslog(LOG_ERR, + "Unknown filegen option token %d", + my_opts->attr); + exit(1); } + my_opts = next_node(my_opts); + } + filegen_config(filegen, filegen_file, filegen_type, + filegen_flag); + my_node = next_node(my_node); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_monitor( + struct config_tree *ptree + ) +{ + char **filegen_string; + struct filegen_node *my_node; + struct attr_val *my_opts; + + if (ptree->stats_dir) { + free(ptree->stats_dir); + ptree->stats_dir = NULL; + } + + while (NULL != (filegen_string = dequeue(ptree->stats_list))) + free_node(filegen_string); + + while (NULL != (my_node = dequeue(ptree->filegen_opts))) { + + while (NULL != (my_opts = dequeue(my_node->options))) + free_node(my_opts); + + free_node(my_node); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_access( + struct config_tree *ptree + ) +{ + static int warned_signd; + struct attr_val * my_opt; + struct restrict_node * my_node; + int * curr_flag; + sockaddr_u addr_sock; + sockaddr_u addr_mask; + u_short flags; + u_short mflags; + int restrict_default; + const char * signd_warning = +#ifdef HAVE_NTP_SIGND + "MS-SNTP signd operations currently block ntpd degrading service to all clients."; +#else + "mssntp restrict bit ignored, this ntpd was configured without --enable-ntp-signd."; +#endif + + /* Configure the discard options */ + my_opt = queue_head(ptree->discard_opts); + while (my_opt != NULL) { + + switch(my_opt->attr) { + + case T_Average: + ntp_minpoll = my_opt->value.i; break; -#ifdef OPENSSL - case CONFIG_REVOKE: - if (ntokens >= 2) - sys_revoke = (u_char) max(atoi(tokens[1]), KEY_REVOKE); + case T_Minimum: + ntp_minpkt = my_opt->value.i; break; - case CONFIG_AUTOMAX: - if (ntokens >= 2) - sys_automax = 1 << max(atoi(tokens[1]), 10); + case T_Monitor: + mon_age = my_opt->value.i; break; - case CONFIG_CRYPTO: - if (ntokens == 1) { - crypto_config(CRYPTO_CONF_NONE, NULL); - break; - } - for (i = 1; i < ntokens; i++) { - int temp; + default: + msyslog(LOG_ERR, + "Unknown discard option token %d", + my_opt->attr); + exit(1); + } + my_opt = next_node(my_opt); + } + + /* Configure the restrict options */ + for (my_node = queue_head(ptree->restrict_opts); + my_node != NULL; + my_node = next_node(my_node)) { + + ZERO_SOCK(&addr_sock); + + if (NULL == my_node->addr) { + /* + * The user specified a default rule without a + * -4 / -6 qualifier, add to both lists + */ + restrict_default = 1; + ZERO_SOCK(&addr_mask); + } else { + restrict_default = 0; + /* Resolve the specified address */ + AF(&addr_sock) = (u_short)my_node->addr->type; + + if (getnetnum(my_node->addr->address, + &addr_sock, 1, t_UNK) != 1) { - temp = matchkey(tokens[i++], - crypto_keywords, 1); - if (i > ntokens - 1) { msyslog(LOG_ERR, - "crypto: missing argument"); - errflg++; + "restrict: error in address '%s' on line %d. Ignoring...", + my_node->addr->address, my_node->line_no); + continue; + } + + SET_HOSTMASK(&addr_mask, AF(&addr_sock)); + + /* Resolve the mask */ + if (my_node->mask) { + ZERO_SOCK(&addr_mask); + AF(&addr_mask) = (u_short)my_node->mask->type; + if (getnetnum(my_node->mask->address, &addr_mask, 1, t_MSK) != 1) { + + msyslog(LOG_ERR, + "restrict: error in mask '%s' on line %d. Ignoring...", + my_node->mask->address, my_node->line_no); + continue; + } + } + } + + /* Parse the flags */ + flags = 0; + mflags = 0; + + curr_flag = queue_head(my_node->flags); + while (curr_flag != NULL) { + switch (*curr_flag) { + + default: + NTP_INSIST(0); break; - } - switch(temp) { - case CONF_CRYPTO_CERT: - crypto_config(CRYPTO_CONF_CERT, - tokens[i]); + case T_Ntpport: + mflags |= RESM_NTPONLY; break; - case CONF_CRYPTO_RSA: - crypto_config(CRYPTO_CONF_PRIV, - tokens[i]); + case T_Flake: + flags |= RES_TIMEOUT; break; - case CONF_CRYPTO_IDENT: - crypto_config(CRYPTO_CONF_IDENT, - tokens[i]); + case T_Ignore: + flags |= RES_IGNORE; break; - case CONF_CRYPTO_IFFPAR: - crypto_config(CRYPTO_CONF_IFFPAR, - tokens[i]); + case T_Kod: + flags |= RES_KOD; break; - case CONF_CRYPTO_GQPAR: - crypto_config(CRYPTO_CONF_GQPAR, - tokens[i]); + case T_Mssntp: + flags |= RES_MSSNTP; break; - case CONF_CRYPTO_MVPAR: - crypto_config(CRYPTO_CONF_MVPAR, - tokens[i]); + case T_Limited: + flags |= RES_LIMITED; break; - case CONF_CRYPTO_LEAP: - crypto_config(CRYPTO_CONF_LEAP, - tokens[i]); + case T_Lowpriotrap: + flags |= RES_LPTRAP; break; - case CONF_CRYPTO_PW: - crypto_config(CRYPTO_CONF_PW, - tokens[i]); + case T_Nomodify: + flags |= RES_NOMODIFY; break; - case CONF_CRYPTO_RAND: - crypto_config(CRYPTO_CONF_RAND, - tokens[i]); + case T_Nopeer: + flags |= RES_NOPEER; break; - case CONF_CRYPTO_SIGN: - crypto_config(CRYPTO_CONF_SIGN, - tokens[i]); + case T_Noquery: + flags |= RES_NOQUERY; break; - default: - msyslog(LOG_ERR, - "crypto: unknown keyword"); + case T_Noserve: + flags |= RES_DONTSERVE; break; - } - } - break; -#endif /* OPENSSL */ - case CONFIG_RESTRICT: - if (ntokens < 2) { - msyslog(LOG_ERR, "restrict requires an address"); + case T_Notrap: + flags |= RES_NOTRAP; break; - } - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - peeraddr.ss_family = default_ai_family; - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; + + case T_Notrust: + flags |= RES_DONTTRUST; break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; + + case T_Version: + flags |= RES_VERSION; break; } + curr_flag = next_node(curr_flag); + } + + /* Set the flags */ + if (restrict_default) { + AF(&addr_sock) = AF_INET; + hack_restrict(RESTRICT_FLAGS, &addr_sock, &addr_mask, + mflags, flags); + + AF(&addr_sock) = AF_INET6; + } + + hack_restrict(RESTRICT_FLAGS, &addr_sock, &addr_mask, + mflags, flags); + + if ((RES_MSSNTP & flags) && !warned_signd) { + warned_signd = 1; + fprintf(stderr, "%s\n", signd_warning); + msyslog(LOG_WARNING, signd_warning); + } + } +} + +#ifdef FREE_CFG_T +static void +free_config_access( + struct config_tree *ptree + ) +{ + struct attr_val * my_opt; + struct restrict_node * my_node; + int * curr_flag; + + while (NULL != (my_opt = dequeue(ptree->discard_opts))) + free_node(my_opt); + + while (NULL != (my_node = dequeue(ptree->restrict_opts))) { + while (NULL != (curr_flag = dequeue(my_node->flags))) + free_node(curr_flag); + + destroy_restrict_node(my_node); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_tinker( + struct config_tree *ptree + ) +{ + struct attr_val *tinker; + int item; + + item = -1; /* quiet warning */ + tinker = queue_head(ptree->tinker); + while (tinker != NULL) { + switch (tinker->attr) { + + default: + NTP_INSIST(0); + break; + + case T_Allan: + item = LOOP_ALLAN; + break; + + case T_Dispersion: + item = LOOP_PHI; + break; + + case T_Freq: + item = LOOP_FREQ; + break; + + case T_Huffpuff: + item = LOOP_HUFFPUFF; + break; + + case T_Panic: + item = LOOP_PANIC; + break; + + case T_Step: + item = LOOP_MAX; + break; + + case T_Stepout: + item = LOOP_MINSTEP; + break; + } + loop_config(item, tinker->value.d); + tinker = next_node(tinker); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_tinker( + struct config_tree *ptree + ) +{ + struct attr_val *tinker; + + while (NULL != (tinker = dequeue(ptree->tinker))) + free_node(tinker); +} +#endif /* FREE_CFG_T */ + + +/* + * config_nic_rules - apply interface listen/ignore/drop items + */ +void +config_nic_rules( + struct config_tree *ptree + ) +{ + nic_rule_node * curr_node; + sockaddr_u addr; + nic_rule_match match_type; + nic_rule_action action; + char * if_name; + char * pchSlash; + int prefixlen; + int addrbits; + + curr_node = queue_head(ptree->nic_rules); + + if (curr_node != NULL + && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) { + msyslog(LOG_ERR, + "interface/nic rules are not allowed with --interface (-I) or --novirtualips (-L)%s", + (input_from_file) ? ", exiting" : ""); + if (input_from_file) + exit(1); + else + return; + } + + for (; + curr_node != NULL; + curr_node = next_node(curr_node)) { + + prefixlen = -1; + if_name = curr_node->if_name; + if (if_name != NULL) + if_name = estrdup(if_name); + + switch (curr_node->match_class) { + + default: /* - * Assume default means an IPv4 address, except - * if forced by a -4 or -6. + * this assignment quiets a gcc "may be used + * uninitialized" warning and is here for no + * other reason. */ - if (STREQ(tokens[istart], "default")) { - if (peeraddr.ss_family == 0) - peeraddr.ss_family = AF_INET; - } else if (getnetnum(tokens[istart], &peeraddr, 1, - t_UNK) != 1) - break; + match_type = MATCH_ALL; + NTP_INSIST(0); + break; + case 0: /* - * Use peerversion as flags, peerkey as mflags. Ick. + * 0 is out of range for valid token T_... + * and in a nic_rules_node indicates the + * interface descriptor is either a name or + * address, stored in if_name in either case. */ - peerversion = 0; - peerkey = 0; - errflg = 0; - SET_HOSTMASK(&maskaddr, peeraddr.ss_family); - istart++; - for (i = istart; i < ntokens; i++) { - switch (matchkey(tokens[i], res_keywords, 1)) { - case CONF_RES_MASK: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "mask keyword needs argument"); - errflg++; - break; - } - i++; - if (getnetnum(tokens[i], &maskaddr, 1, - t_MSK) != 1) - errflg++; - break; + NTP_INSIST(if_name != NULL); + pchSlash = strchr(if_name, '/'); + if (pchSlash != NULL) + *pchSlash = '\0'; + if (is_ip_address(if_name, &addr)) { + match_type = MATCH_IFADDR; + if (pchSlash != NULL) { + sscanf(pchSlash + 1, "%d", + &prefixlen); + addrbits = 8 * + SIZEOF_INADDR(AF(&addr)); + prefixlen = max(-1, prefixlen); + prefixlen = min(prefixlen, + addrbits); + } + } else { + match_type = MATCH_IFNAME; + if (pchSlash != NULL) + *pchSlash = '/'; + } + break; - case CONF_RES_IGNORE: - peerversion |= RES_IGNORE; - break; + case T_All: + match_type = MATCH_ALL; + break; - case CONF_RES_NOSERVE: - peerversion |= RES_DONTSERVE; - break; + case T_Ipv4: + match_type = MATCH_IPV4; + break; - case CONF_RES_NOTRUST: - peerversion |= RES_DONTTRUST; - break; + case T_Ipv6: + match_type = MATCH_IPV6; + break; - case CONF_RES_NOQUERY: - peerversion |= RES_NOQUERY; - break; + case T_Wildcard: + match_type = MATCH_WILDCARD; + break; + } - case CONF_RES_NOMODIFY: - peerversion |= RES_NOMODIFY; - break; + switch (curr_node->action) { - case CONF_RES_NOPEER: - peerversion |= RES_NOPEER; - break; + default: + /* + * this assignment quiets a gcc "may be used + * uninitialized" warning and is here for no + * other reason. + */ + action = ACTION_LISTEN; + NTP_INSIST(0); + break; - case CONF_RES_NOTRAP: - peerversion |= RES_NOTRAP; - break; + case T_Listen: + action = ACTION_LISTEN; + break; - case CONF_RES_LPTRAP: - peerversion |= RES_LPTRAP; - break; + case T_Ignore: + action = ACTION_IGNORE; + break; - case CONF_RES_NTPPORT: - peerkey |= RESM_NTPONLY; - break; + case T_Drop: + action = ACTION_DROP; + break; + } - case CONF_RES_VERSION: - peerversion |= RES_VERSION; - break; + add_nic_rule(match_type, if_name, prefixlen, + action); + timer_interfacetimeout(current_time + 2); + if (if_name != NULL) + free(if_name); + } +} - case CONF_RES_DEMOBILIZE: - peerversion |= RES_DEMOBILIZE; - break; - case CONF_RES_LIMITED: - peerversion |= RES_LIMITED; - break; +#ifdef FREE_CFG_T +static void +free_config_nic_rules( + struct config_tree *ptree + ) +{ + nic_rule_node *curr_node; - case CONFIG_UNKNOWN: - errflg++; - break; - } - } - if (SOCKNUL(&peeraddr)) - ANYSOCK(&maskaddr); - if (!errflg) - hack_restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr, - (int)peerkey, peerversion); + while (NULL != (curr_node = dequeue(ptree->nic_rules))) { + if (curr_node->if_name != NULL) + free(curr_node->if_name); + free_node(curr_node); + } + DESTROY_QUEUE(ptree->nic_rules); +} +#endif /* FREE_CFG_T */ + + +static void +apply_enable_disable( + queue * q, + int enable + ) +{ + struct attr_val *curr_flag; + int option; +#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED + bc_entry *pentry; +#endif + + for (curr_flag = queue_head(q); + curr_flag != NULL; + curr_flag = next_node(curr_flag)) { + + option = curr_flag->value.i; + switch (option) { + + default: + msyslog(LOG_ERR, + "can not apply enable/disable token %d, unknown", + option); break; - case CONFIG_BDELAY: - if (ntokens >= 2) { - double tmp; + case T_Auth: + proto_config(PROTO_AUTHENTICATE, enable, 0., NULL); + break; - if (sscanf(tokens[1], "%lf", &tmp) != 1) { - msyslog(LOG_ERR, - "broadcastdelay value %s undecodable", - tokens[1]); - } else { - proto_config(PROTO_BROADDELAY, 0, tmp, NULL); - } - } + case T_Bclient: + proto_config(PROTO_BROADCLIENT, enable, 0., NULL); break; - case CONFIG_CDELAY: - if (ntokens >= 2) { - u_long ui; + case T_Calibrate: + proto_config(PROTO_CAL, enable, 0., NULL); + break; - if (sscanf(tokens[1], "%ld", &ui) != 1) - msyslog(LOG_ERR, - "illegal value - line ignored"); - else - proto_config(PROTO_CALLDELAY, ui, 0, NULL); - } + case T_Kernel: + proto_config(PROTO_KERNEL, enable, 0., NULL); break; - case CONFIG_TRUSTEDKEY: - for (i = 1; i < ntokens; i++) { - keyid_t tkey; + case T_Monitor: + proto_config(PROTO_MONITOR, enable, 0., NULL); + break; - tkey = atol(tokens[i]); - if (tkey == 0) { - msyslog(LOG_ERR, - "trusted key %s unlikely", - tokens[i]); - } else { - authtrust(tkey, 1); - } + case T_Ntp: + proto_config(PROTO_NTP, enable, 0., NULL); + break; + + case T_Stats: + proto_config(PROTO_FILEGEN, enable, 0., NULL); + break; + +#ifdef BC_LIST_FRAMEWORK_NOT_YET_USED + case T_Bc_bugXXXX: + pentry = bc_list; + while (pentry->token) { + if (pentry->token == option) + break; + pentry++; } + if (!pentry->token) { + msyslog(LOG_ERR, + "compat token %d not in bc_list[]", + option); + continue; + } + pentry->enabled = enable; break; +#endif + } + } +} - case CONFIG_REQUESTKEY: - if (ntokens >= 2) { - if (!atouint(tokens[1], &ul)) { - msyslog(LOG_ERR, - "%s is undecodable as request key", - tokens[1]); - } else if (ul == 0) { - msyslog(LOG_ERR, - "%s makes a poor request keyid", - tokens[1]); - } else { -#ifdef DEBUG - if (debug > 3) - printf( - "set info_auth_key to %08lx\n", ul); + +static void +config_system_opts( + struct config_tree *ptree + ) +{ + apply_enable_disable(ptree->enable_opts, 1); + apply_enable_disable(ptree->disable_opts, 0); +} + + +#ifdef FREE_CFG_T +static void +free_config_system_opts( + struct config_tree *ptree + ) +{ + struct attr_val *flag; + + while (NULL != (flag = dequeue(ptree->enable_opts))) + free_node(flag); + + while (NULL != (flag = dequeue(ptree->disable_opts))) + free_node(flag); +} +#endif /* FREE_CFG_T */ + + +static void +config_logconfig( + struct config_tree *ptree + ) +{ + struct attr_val *my_logconfig; + + my_logconfig = queue_head(ptree->logconfig); + while (my_logconfig != NULL) { + + switch (my_logconfig->attr) { + case '+': + ntp_syslogmask |= get_logmask(my_logconfig->value.s); + break; + case '-': + ntp_syslogmask &= ~get_logmask(my_logconfig->value.s); + break; + case '=': + ntp_syslogmask = get_logmask(my_logconfig->value.s); + break; + } + my_logconfig = next_node(my_logconfig); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_logconfig( + struct config_tree *ptree + ) +{ + struct attr_val *my_logconfig; + + while (NULL != (my_logconfig = dequeue(ptree->logconfig))) { + free(my_logconfig->value.s); + free_node(my_logconfig); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_phone( + struct config_tree *ptree + ) +{ + int i = 0; + char **s; + + s = queue_head(ptree->phone); + while (s != NULL) { + if (i < COUNTOF(sys_phone) - 1) { + sys_phone[i++] = estrdup(*s); + sys_phone[i] = NULL; + } else { + msyslog(LOG_INFO, + "phone: Number of phone entries exceeds %lu. Ignoring phone %s...", + (u_long)(COUNTOF(sys_phone) - 1), *s); + } + s = next_node(s); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_phone( + struct config_tree *ptree + ) +{ + char **s; + + while (NULL != (s = dequeue(ptree->phone))) { + free(*s); + free_node(s); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_qos( + struct config_tree *ptree + ) +{ + struct attr_val *my_qosconfig; + char *s; +#ifdef HAVE_IPTOS_SUPPORT + unsigned int qtos = 0; #endif - info_auth_keyid = (keyid_t)ul; + + my_qosconfig = queue_head(ptree->qos); + while (my_qosconfig != NULL) { + s = my_qosconfig->value.s; +#ifdef HAVE_IPTOS_SUPPORT + if (!strcmp(s, "lowdelay")) + qtos = CONF_QOS_LOWDELAY; + else if (!strcmp(s, "throughput")) + qtos = CONF_QOS_THROUGHPUT; + else if (!strcmp(s, "reliability")) + qtos = CONF_QOS_RELIABILITY; + else if (!strcmp(s, "mincost")) + qtos = CONF_QOS_MINCOST; +#ifdef IPTOS_PREC_INTERNETCONTROL + else if (!strcmp(s, "routine") || !strcmp(s, "cs0")) + qtos = CONF_QOS_CS0; + else if (!strcmp(s, "priority") || !strcmp(s, "cs1")) + qtos = CONF_QOS_CS1; + else if (!strcmp(s, "immediate") || !strcmp(s, "cs2")) + qtos = CONF_QOS_CS2; + else if (!strcmp(s, "flash") || !strcmp(s, "cs3")) + qtos = CONF_QOS_CS3; /* overlapping prefix on keyword */ + if (!strcmp(s, "flashoverride") || !strcmp(s, "cs4")) + qtos = CONF_QOS_CS4; + else if (!strcmp(s, "critical") || !strcmp(s, "cs5")) + qtos = CONF_QOS_CS5; + else if(!strcmp(s, "internetcontrol") || !strcmp(s, "cs6")) + qtos = CONF_QOS_CS6; + else if (!strcmp(s, "netcontrol") || !strcmp(s, "cs7")) + qtos = CONF_QOS_CS7; +#endif /* IPTOS_PREC_INTERNETCONTROL */ + if (qtos == 0) + msyslog(LOG_ERR, "parse error, qos %s not accepted\n", s); + else + qos = qtos; +#endif /* HAVE IPTOS_SUPPORT */ + /* + * value is set, but not being effective. Need code to + * change the current connections to notice. Might + * also consider logging a message about the action. + * XXX msyslog(LOG_INFO, "QoS %s requested by config\n", s); + */ + my_qosconfig = next_node(my_qosconfig); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_qos( + struct config_tree *ptree + ) +{ + struct attr_val *my_qosconfig; + + while (NULL != (my_qosconfig = dequeue(ptree->qos))) { + free(my_qosconfig->value.s); + free_node(my_qosconfig); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_setvar( + struct config_tree *ptree + ) +{ + struct setvar_node *my_node; + size_t varlen, vallen, octets; + char * str; + + str = NULL; + my_node = queue_head(ptree->setvar); + while (my_node != NULL) { + varlen = strlen(my_node->var); + vallen = strlen(my_node->val); + octets = varlen + vallen + 1 + 1; + str = erealloc(str, octets); + snprintf(str, octets, "%s=%s", my_node->var, + my_node->val); + set_sys_var(str, octets, (my_node->isdefault) + ? DEF + : 0); + my_node = next_node(my_node); + } + if (str != NULL) + free(str); +} + + +#ifdef FREE_CFG_T +static void +free_config_setvar( + struct config_tree *ptree + ) +{ + struct setvar_node *my_node; + + while (NULL != (my_node = dequeue(ptree->setvar))) { + free(my_node->var); + free(my_node->val); + free_node(my_node); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_ttl( + struct config_tree *ptree + ) +{ + int i = 0; + int *curr_ttl; + + curr_ttl = queue_head(ptree->ttl); + while (curr_ttl != NULL) { + if (i < COUNTOF(sys_ttl)) + sys_ttl[i++] = (u_char)*curr_ttl; + else + msyslog(LOG_INFO, + "ttl: Number of TTL entries exceeds %lu. Ignoring TTL %d...", + (u_long)COUNTOF(sys_ttl), *curr_ttl); + + curr_ttl = next_node(curr_ttl); + } + sys_ttlmax = i - 1; +} + + +#ifdef FREE_CFG_T +static void +free_config_ttl( + struct config_tree *ptree + ) +{ + /* coming DESTROY_QUEUE(ptree->ttl) is enough */ +} +#endif /* FREE_CFG_T */ + + +static void +config_trap( + struct config_tree *ptree + ) +{ + struct addr_opts_node *curr_trap; + struct attr_val *curr_opt; + sockaddr_u addr_sock; + sockaddr_u peeraddr; + struct address_node *addr_node; + struct interface *localaddr; + u_short port_no; + int err_flag; + + /* silence warning about addr_sock potentially uninitialized */ + AF(&addr_sock) = AF_UNSPEC; + + for (curr_trap = queue_head(ptree->trap); + curr_trap != NULL; + curr_trap = next_node(curr_trap)) { + + err_flag = 0; + port_no = 0; + localaddr = NULL; + + curr_opt = queue_head(curr_trap->options); + while (curr_opt != NULL) { + if (T_Port == curr_opt->attr) { + if (curr_opt->value.i < 1 + || curr_opt->value.i > USHRT_MAX) { + msyslog(LOG_ERR, + "invalid port number " + "%d, trap ignored", + curr_opt->value.i); + err_flag = 1; } + port_no = (u_short)curr_opt->value.i; } - break; + else if (T_Interface == curr_opt->attr) { + addr_node = curr_opt->value.p; + + /* Resolve the interface address */ + ZERO_SOCK(&addr_sock); + AF(&addr_sock) = (u_short)addr_node->type; + + if (getnetnum(addr_node->address, + &addr_sock, 1, t_UNK) != 1) { + err_flag = 1; + break; + } - case CONFIG_CONTROLKEY: - if (ntokens >= 2) { - keyid_t ckey; + localaddr = findinterface(&addr_sock); - ckey = atol(tokens[1]); - if (ckey == 0) { + if (NULL == localaddr) { msyslog(LOG_ERR, - "%s makes a poor control keyid", - tokens[1]); - } else { - ctl_auth_keyid = ckey; + "can't find interface with address %s", + stoa(&addr_sock)); + err_flag = 1; } } - break; + curr_opt = next_node(curr_opt); + } - case CONFIG_TRAP: - if (ntokens < 2) { + /* Now process the trap for the specified interface + * and port number + */ + if (!err_flag) { + ZERO_SOCK(&peeraddr); + if (1 != getnetnum(curr_trap->addr->address, + &peeraddr, 1, t_UNK)) + continue; + + /* port is at same location for v4 and v6 */ + SET_PORT(&peeraddr, port_no ? port_no : TRAPPORT); + + if (NULL == localaddr) + localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); + else + AF(&peeraddr) = AF(&addr_sock); + + if (!ctlsettrap(&peeraddr, localaddr, 0, + NTP_VERSION)) msyslog(LOG_ERR, - "no address for trap command, line ignored"); - break; + "can't set trap for %s", + stoa(&peeraddr)); + } + } +} + + +#ifdef FREE_CFG_T +static void +free_config_trap( + struct config_tree *ptree + ) +{ + struct addr_opts_node *curr_trap; + struct attr_val *curr_opt; + struct address_node *addr_node; + + while (NULL != (curr_trap = dequeue(ptree->trap))) { + while (curr_trap->options != NULL && NULL != + (curr_opt = dequeue(curr_trap->options))) { + + if (T_Interface == curr_opt->attr) { + addr_node = curr_opt->value.p; + destroy_address_node(addr_node); } - istart = 1; - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - peeraddr.ss_family = default_ai_family; - switch (matchkey(tokens[istart], addr_type, 0)) { - case CONF_ADDR_IPV4: - peeraddr.ss_family = AF_INET; - istart++; + free_node(curr_opt); + } + DESTROY_QUEUE(curr_trap->options); + free_node(curr_trap); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_fudge( + struct config_tree *ptree + ) +{ + struct addr_opts_node *curr_fudge; + struct attr_val *curr_opt; + sockaddr_u addr_sock; + struct address_node *addr_node; + struct refclockstat clock_stat; + int err_flag; + + curr_fudge = queue_head(ptree->fudge); + while (curr_fudge != NULL) { + err_flag = 0; + + /* Get the reference clock address and + * ensure that it is sane + */ + addr_node = curr_fudge->addr; + ZERO_SOCK(&addr_sock); + if (getnetnum(addr_node->address, &addr_sock, 1, t_REF) + != 1) + err_flag = 1; + + if (!ISREFCLOCKADR(&addr_sock)) { + msyslog(LOG_ERR, + "inappropriate address %s for the fudge command, line ignored", + stoa(&addr_sock)); + err_flag = 1; + } + + /* Parse all the options to the fudge command */ + memset(&clock_stat, 0, sizeof(clock_stat)); + curr_opt = queue_head(curr_fudge->options); + while (curr_opt != NULL) { + switch (curr_opt->attr) { + case T_Time1: + clock_stat.haveflags |= CLK_HAVETIME1; + clock_stat.fudgetime1 = curr_opt->value.d; + break; + case T_Time2: + clock_stat.haveflags |= CLK_HAVETIME2; + clock_stat.fudgetime2 = curr_opt->value.d; + break; + case T_Stratum: + clock_stat.haveflags |= CLK_HAVEVAL1; + clock_stat.fudgeval1 = curr_opt->value.i; break; - case CONF_ADDR_IPV6: - peeraddr.ss_family = AF_INET6; - istart++; + case T_Refid: + clock_stat.haveflags |= CLK_HAVEVAL2; + clock_stat.fudgeval2 = 0; + memcpy(&clock_stat.fudgeval2, + curr_opt->value.s, + min(strlen(curr_opt->value.s), 4)); break; + case T_Flag1: + clock_stat.haveflags |= CLK_HAVEFLAG1; + if (curr_opt->value.i) + clock_stat.flags |= CLK_FLAG1; + else + clock_stat.flags &= ~CLK_FLAG1; + break; + case T_Flag2: + clock_stat.haveflags |= CLK_HAVEFLAG2; + if (curr_opt->value.i) + clock_stat.flags |= CLK_FLAG2; + else + clock_stat.flags &= ~CLK_FLAG2; + break; + case T_Flag3: + clock_stat.haveflags |= CLK_HAVEFLAG3; + if (curr_opt->value.i) + clock_stat.flags |= CLK_FLAG3; + else + clock_stat.flags &= ~CLK_FLAG3; + break; + case T_Flag4: + clock_stat.haveflags |= CLK_HAVEFLAG4; + if (curr_opt->value.i) + clock_stat.flags |= CLK_FLAG4; + else + clock_stat.flags &= ~CLK_FLAG4; + break; + default: + msyslog(LOG_ERR, + "Unexpected fudge internal flag 0x%x for %s\n", + curr_opt->attr, stoa(&addr_sock)); + exit(curr_opt->attr ? curr_opt->attr : 1); } - if (getnetnum(tokens[istart], &peeraddr, 1, t_UNK) != 1) - break; + curr_opt = next_node(curr_opt); + } - /* - * Use peerversion for port number. Barf. - */ - errflg = 0; - peerversion = 0; - localaddr = 0; - istart++; - for (i = istart; i < ntokens-1; i++) - switch (matchkey(tokens[i], trap_keywords, 1)) { - case CONF_TRAP_PORT: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "trap port requires an argument"); - errflg = 1; - break; - } - peerversion = atoi(tokens[++i]); - if (peerversion <= 0 - || peerversion > 32767) { - msyslog(LOG_ERR, - "invalid port number %s, trap ignored", - tokens[i]); - errflg = 1; - } - break; - - case CONF_TRAP_INTERFACE: - if (i >= ntokens-1) { - msyslog(LOG_ERR, - "trap interface requires an argument"); - errflg = 1; - break; - } - - memset((char *)&maskaddr, 0, - sizeof(maskaddr)); - maskaddr.ss_family = peeraddr.ss_family; - if (getnetnum(tokens[++i], - &maskaddr, 1, t_UNK) != 1) { - errflg = 1; - break; - } - - localaddr = findinterface(&maskaddr); - if (localaddr == NULL) { - msyslog(LOG_ERR, - "can't find interface with address %s", - stoa(&maskaddr)); - errflg = 1; - } - break; - - case CONFIG_UNKNOWN: - errflg++; - break; - } - - if (!errflg) { - if (peerversion != 0) - ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons( (u_short) peerversion); - else - ((struct sockaddr_in6*)&peeraddr)->sin6_port = htons(TRAPPORT); - if (localaddr == NULL) - localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); - if (!ctlsettrap(&peeraddr, localaddr, 0, - NTP_VERSION)) - msyslog(LOG_ERR, - "can't set trap for %s, no resources", - stoa(&peeraddr)); +#ifdef REFCLOCK + if (!err_flag) + refclock_control(&addr_sock, &clock_stat, + (struct refclockstat *)0); +#endif + + curr_fudge = next_node(curr_fudge); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_fudge( + struct config_tree *ptree + ) +{ + struct addr_opts_node *curr_fudge; + struct attr_val *curr_opt; + + while (NULL != (curr_fudge = dequeue(ptree->fudge))) { + while (NULL != (curr_opt = dequeue(curr_fudge->options))) { + + switch (curr_opt->attr) { + case CLK_HAVEVAL2: + free(curr_opt->value.s); } - break; - case CONFIG_FUDGE: - if (ntokens < 2) { + free_node(curr_opt); + } + + DESTROY_QUEUE(curr_fudge->options); + free_node(curr_fudge); + } +} +#endif /* FREE_CFG_T */ + + +static void +config_vars( + struct config_tree *ptree + ) +{ + struct attr_val *curr_var; + FILE *new_file; + int len; + + curr_var = queue_head(ptree->vars); + while (curr_var != NULL) { + /* Determine which variable to set and set it */ + switch (curr_var->attr) { + case T_Broadcastdelay: + proto_config(PROTO_BROADDELAY, 0, curr_var->value.d, NULL); + break; + case T_Calldelay: + proto_config(PROTO_CALLDELAY, curr_var->value.i, 0, NULL); + break; + case T_Tick: + proto_config(PROTO_ADJ, 0, curr_var->value.d, NULL); + break; + case T_Driftfile: + if ('\0' == curr_var->value.s[0]) { + stats_drift_file = 0; + msyslog(LOG_INFO, "config: driftfile disabled\n"); + } else + stats_config(STATS_FREQ_FILE, curr_var->value.s); + break; + case T_WanderThreshold: + wander_threshold = curr_var->value.d; + break; + case T_Leapfile: + stats_config(STATS_LEAP_FILE, curr_var->value.s); + break; + case T_Pidfile: + stats_config(STATS_PID_FILE, curr_var->value.s); + break; + case T_Logfile: + new_file = fopen(curr_var->value.s, "a"); + if (new_file != NULL) { + NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ + msyslog(LOG_NOTICE, "logging to file %s", curr_var->value.s); + if (syslog_file != NULL && + fileno(syslog_file) != fileno(new_file)) + (void)fclose(syslog_file); + + syslog_file = new_file; + syslogit = 0; + } + else msyslog(LOG_ERR, - "no address for fudge command, line ignored"); + "Cannot open log file %s", + curr_var->value.s); + break; + + case T_Saveconfigdir: + if (saveconfigdir != NULL) + free(saveconfigdir); + len = strlen(curr_var->value.s); + if (0 == len) + saveconfigdir = NULL; + else if (DIR_SEP != curr_var->value.s[len - 1] +#ifdef SYS_WINNT /* slash is also a dir. sep. on Windows */ + && '/' != curr_var->value.s[len - 1] +#endif + ) { + len++; + saveconfigdir = emalloc(len + 1); + snprintf(saveconfigdir, len + 1, + "%s%c", + curr_var->value.s, + DIR_SEP); + } else + saveconfigdir = estrdup( + curr_var->value.s); + break; + + case T_Automax: +#ifdef OPENSSL + sys_automax = curr_var->value.i; +#endif + break; + + default: + msyslog(LOG_ERR, + "config_vars(): unexpected token %d", + curr_var->attr); + } + curr_var = next_node(curr_var); + } +} + + +#ifdef FREE_CFG_T +static void +free_config_vars( + struct config_tree *ptree + ) +{ + struct attr_val *curr_var; + + while (NULL != (curr_var = dequeue(ptree->vars))) { + /* Determine which variable to set and set it */ + switch (curr_var->attr) { + case T_Driftfile: + case T_Leapfile: + case T_Pidfile: + case T_Logfile: + free(curr_var->value.s); + } + free_node(curr_var); + } +} +#endif /* FREE_CFG_T */ + + +/* Define a function to check if a resolved address is sane. + * If yes, return 1, else return 0; + */ +static int +is_sane_resolved_address( + sockaddr_u * peeraddr, + int hmode + ) +{ + if (!ISREFCLOCKADR(peeraddr) && ISBADADR(peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + stoa(peeraddr)); + return 0; + } + /* + * Shouldn't be able to specify multicast + * address for server/peer! + * and unicast address for manycastclient! + */ + if ((T_Server == hmode || T_Peer == hmode || T_Pool == hmode) + && IS_MCAST(peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + stoa(peeraddr)); + return 0; + } + if (T_Manycastclient == hmode && !IS_MCAST(peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + stoa(peeraddr)); + return 0; + } + + if (IS_IPV6(peeraddr) && !ipv6_works) + return 0; + + /* Ok, all tests succeeded, now we can return 1 */ + return 1; +} + +static int +get_correct_host_mode( + int hmode + ) +{ + switch (hmode) { + case T_Server: + case T_Pool: + case T_Manycastclient: + return MODE_CLIENT; + break; + case T_Peer: + return MODE_ACTIVE; + break; + case T_Broadcast: + return MODE_BROADCAST; + break; + default: + return -1; + } +} + +static void +config_peers( + struct config_tree *ptree + ) +{ + struct addrinfo *res, *res_bak; + sockaddr_u peeraddr; + struct peer_node *curr_peer; + struct attr_val *option; + int hmode; + int peerflags; + int status; + int no_needed; + int i; + + curr_peer = queue_head(ptree->peers); + while (curr_peer != NULL) { + /* Find the number of associations needed. + * If a pool coomand is specified, then sys_maxclock needed + * else, only one is needed + */ + no_needed = (T_Pool == curr_peer->host_mode) + ? sys_maxclock + : 1; + + /* Find the correct host-mode */ + hmode = get_correct_host_mode(curr_peer->host_mode); + NTP_INSIST(hmode != -1); + + /* translate peerflags options to bits */ + peerflags = 0; + option = queue_head(curr_peer->peerflags); + for (; option != NULL; option = next_node(option)) + switch (option->value.i) { + + default: + NTP_INSIST(0); break; - } - memset((char *)&peeraddr, 0, sizeof(peeraddr)); - if (getnetnum(tokens[1], &peeraddr, 1, t_REF) != 1) - break; - if (!ISREFCLOCKADR(&peeraddr)) { - msyslog(LOG_ERR, - "%s is inappropriate address for the fudge command, line ignored", - stoa(&peeraddr)); + case T_Autokey: + peerflags |= FLAG_SKEY; break; - } - memset((void *)&clock_stat, 0, sizeof clock_stat); - fudgeflag = 0; - errflg = 0; - for (i = 2; i < ntokens-1; i++) { - switch (c = matchkey(tokens[i], - fudge_keywords, 1)) { - case CONF_FDG_TIME1: - if (sscanf(tokens[++i], "%lf", - &clock_stat.fudgetime1) != 1) { - msyslog(LOG_ERR, - "fudge %s time1 value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.haveflags |= CLK_HAVETIME1; - break; + case T_Burst: + peerflags |= FLAG_BURST; + break; - case CONF_FDG_TIME2: - if (sscanf(tokens[++i], "%lf", - &clock_stat.fudgetime2) != 1) { - msyslog(LOG_ERR, - "fudge %s time2 value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.haveflags |= CLK_HAVETIME2; - break; + case T_Iburst: + peerflags |= FLAG_IBURST; + break; + case T_Noselect: + peerflags |= FLAG_NOSELECT; + break; - case CONF_FDG_STRATUM: - if (!atoint(tokens[++i], &stratum)) - { - msyslog(LOG_ERR, - "fudge %s stratum value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - clock_stat.fudgeval1 = stratum; - clock_stat.haveflags |= CLK_HAVEVAL1; - break; + case T_Preempt: + peerflags |= FLAG_PREEMPT; + break; - case CONF_FDG_REFID: - i++; - memcpy(&clock_stat.fudgeval2, - tokens[i], min(strlen(tokens[i]), - 4)); - clock_stat.haveflags |= CLK_HAVEVAL2; - break; + case T_Prefer: + peerflags |= FLAG_PREFER; + break; - case CONF_FDG_FLAG1: - case CONF_FDG_FLAG2: - case CONF_FDG_FLAG3: - case CONF_FDG_FLAG4: - if (!atouint(tokens[++i], &fudgeflag) - || fudgeflag > 1) { - msyslog(LOG_ERR, - "fudge %s flag value in error", - stoa(&peeraddr)); - errflg = i; - break; - } - switch(c) { - case CONF_FDG_FLAG1: - c = CLK_FLAG1; - clock_stat.haveflags|=CLK_HAVEFLAG1; - break; - case CONF_FDG_FLAG2: - c = CLK_FLAG2; - clock_stat.haveflags|=CLK_HAVEFLAG2; - break; - case CONF_FDG_FLAG3: - c = CLK_FLAG3; - clock_stat.haveflags|=CLK_HAVEFLAG3; - break; - case CONF_FDG_FLAG4: - c = CLK_FLAG4; - clock_stat.haveflags|=CLK_HAVEFLAG4; - break; - } - if (fudgeflag == 0) - clock_stat.flags &= ~c; - else - clock_stat.flags |= c; - break; + case T_True: + peerflags |= FLAG_TRUE; + break; - case CONFIG_UNKNOWN: - errflg = -1; - break; - } + case T_Xleave: + peerflags |= FLAG_XLEAVE; + break; } -#ifdef REFCLOCK + /* Attempt to resolve the address */ + ZERO_SOCK(&peeraddr); + AF(&peeraddr) = (u_short)curr_peer->addr->type; + + status = get_multiple_netnums(curr_peer->addr->address, + &peeraddr, &res, 0, t_UNK); + +#ifdef FORCE_DEFER_DNS + /* Hack for debugging Deferred DNS + * Pretend working names didn't work. + */ + if (status == 1) { + /* Deferring everything breaks refclocks. */ + memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); + if (!ISREFCLOCKADR(&peeraddr)) { + status = 0; /* force deferred DNS path */ + msyslog(LOG_INFO, "Forcing Deferred DNS for %s, %s", + curr_peer->addr->address, stoa(&peeraddr)); + } else { + msyslog(LOG_INFO, "NOT Deferring DNS for %s, %s", + curr_peer->addr->address, stoa(&peeraddr)); + } + } +#endif + + /* I don't know why getnetnum would return -1. + * The old code had this test, so I guess it must be + * useful + */ + if (status == -1) { + /* Do nothing, apparently we found an IPv6 + * address and can't do anything about it */ + } + /* Check if name resolution failed. If yes, store the + * peer information in a file for asynchronous + * resolution later + */ + else if (status != 1) { + msyslog(LOG_INFO, "Deferring DNS for %s %d", curr_peer->addr->address, no_needed); + save_resolve(curr_peer->addr->address, + no_needed, + curr_peer->addr->type, + hmode, + curr_peer->peerversion, + curr_peer->minpoll, + curr_peer->maxpoll, + peerflags, + curr_peer->ttl, + curr_peer->peerkey, + (u_char *)"*"); + } + /* Yippie!! Name resolution has succeeded!!! + * Now we can proceed to some more sanity checks on + * the resolved address before we start to configure + * the peer + */ + else { + res_bak = res; + /* - * If reference clock support isn't defined the - * fudge line will still be accepted and syntax - * checked, but will essentially do nothing. + * Loop to configure the desired number of + * associations */ - if (!errflg) { - refclock_control(&peeraddr, &clock_stat, - (struct refclockstat *)0); + for (i = 0; (i < no_needed) && res; res = + res->ai_next) { + ++i; + memcpy(&peeraddr, res->ai_addr, + res->ai_addrlen); + if (is_sane_resolved_address( + &peeraddr, + curr_peer->host_mode)) + + peer_config(&peeraddr, + NULL, + hmode, + curr_peer->peerversion, + curr_peer->minpoll, + curr_peer->maxpoll, + peerflags, + curr_peer->ttl, + curr_peer->peerkey, + (u_char *)"*"); } -#endif - break; + freeaddrinfo(res_bak); + } + curr_peer = next_node(curr_peer); + } +} - case CONFIG_STATSDIR: - if (ntokens >= 2) - stats_config(STATS_STATSDIR,tokens[1]); - break; - case CONFIG_STATISTICS: - for (i = 1; i < ntokens; i++) { - filegen = filegen_get(tokens[i]); +#ifdef FREE_CFG_T +static void +free_config_peers( + struct config_tree *ptree + ) +{ + struct peer_node *curr_peer; - if (filegen == NULL) { - msyslog(LOG_ERR, - "no statistics named %s available", - tokens[i]); - continue; - } -#ifdef DEBUG - if (debug > 3) - printf("enabling filegen for %s statistics \"%s%s\"\n", - tokens[i], filegen->prefix, filegen->basename); -#endif - filegen->flag |= FGEN_FLAG_ENABLED; - } - break; + while (NULL != (curr_peer = dequeue(ptree->peers))) { + destroy_address_node(curr_peer->addr); + DESTROY_QUEUE(curr_peer->peerflags); + free_node(curr_peer); + } +} +#endif /* FREE_CFG_T */ - case CONFIG_FILEGEN: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no id for filegen command, line ignored"); - break; - } - filegen = filegen_get(tokens[1]); - if (filegen == NULL) { - msyslog(LOG_ERR, - "unknown filegen \"%s\" ignored", - tokens[1]); - break; - } +static void +config_unpeers( + struct config_tree *ptree + ) +{ + struct addrinfo *res, *res_bak; + sockaddr_u peeraddr; + struct unpeer_node *curr_unpeer; + struct peer *peer; + int status; + int found; + + for (curr_unpeer = queue_head(ptree->unpeers); + curr_unpeer != NULL; + curr_unpeer = next_node(curr_unpeer)) { + + /* + * Either AssocID will be zero, and we unpeer by name/ + * address addr, or it is nonzero and addr NULL. + */ + if (curr_unpeer->assocID) { + peer = findpeerbyassoc((u_int)curr_unpeer->assocID); + if (peer != NULL) { + peer_clear(peer, "GONE"); + unpeer(peer); + } + + continue; + } + + /* Attempt to resolve the name or address */ + ZERO_SOCK(&peeraddr); + AF(&peeraddr) = (u_short)curr_unpeer->addr->type; + + status = get_multiple_netnums( + curr_unpeer->addr->address, &peeraddr, &res, 0, + t_UNK); + + /* I don't know why getnetnum would return -1. + * The old code had this test, so I guess it must be + * useful + */ + if (status == -1) { + /* Do nothing, apparently we found an IPv6 + * address and can't do anything about it */ + } + /* Check if name resolution failed. If yes, throw + * up our hands. + */ + else if (status != 1) { + /* Do nothing */ + } + /* Yippie!! Name resolution has succeeded!!! + */ + else { + res_bak = res; + /* - * peerversion is (ab)used for filegen file (index) - * peerkey is (ab)used for filegen type - * peerflags is (ab)used for filegen flags + * Loop through the addresses found */ - peerversion = 0; - peerkey = filegen->type; - peerflags = filegen->flag; - errflg = 0; - - for (i = 2; i < ntokens; i++) { - switch (matchkey(tokens[i], - filegen_keywords, 1)) { - case CONF_FGEN_FILE: - if (i >= ntokens - 1) { - msyslog(LOG_ERR, - "filegen %s file requires argument", - tokens[1]); - errflg = i; - break; - } - peerversion = ++i; - break; - case CONF_FGEN_TYPE: - if (i >= ntokens -1) { - msyslog(LOG_ERR, - "filegen %s type requires argument", - tokens[1]); - errflg = i; - break; - } - peerkey = matchkey(tokens[++i], - fgen_types, 1); - if (peerkey == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "filegen %s unknown type \"%s\"", - tokens[1], tokens[i]); - errflg = i; - break; - } - break; + while (res) { + memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); - case CONF_FGEN_FLAG_LINK: - peerflags |= FGEN_FLAG_LINK; - break; + found = 0; + peer = NULL; - case CONF_FGEN_FLAG_NOLINK: - peerflags &= ~FGEN_FLAG_LINK; - break; + DPRINTF(1, ("searching for %s\n", stoa(&peeraddr))); - case CONF_FGEN_FLAG_ENABLE: - peerflags |= FGEN_FLAG_ENABLED; - break; + while (!found) { + peer = findexistingpeer(&peeraddr, peer, -1, 0); + if (!peer) + break; + if (peer->flags & FLAG_CONFIG) + found = 1; + } - case CONF_FGEN_FLAG_DISABLE: - peerflags &= ~FGEN_FLAG_ENABLED; - break; + if (found) { + peer_clear(peer, "GONE"); + unpeer(peer); } - } - if (!errflg) - filegen_config(filegen, tokens[peerversion], - (u_char)peerkey, (u_char)peerflags); - break; - case CONFIG_SETVAR: - if (ntokens < 2) { - msyslog(LOG_ERR, - "no value for setvar command - line ignored"); - } else { - set_sys_var(tokens[1], strlen(tokens[1])+1, - (u_short) (RW | - ((((ntokens > 2) - && !strcmp(tokens[2], - "default"))) - ? DEF - : 0))); + res = res->ai_next; } - break; + freeaddrinfo(res_bak); + } + } +} - case CONFIG_ENABLE: - for (i = 1; i < ntokens; i++) { - int flag; - flag = matchkey(tokens[i], flags_keywords, 1); - if (flag == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "enable unknown flag %s", - tokens[i]); - errflg = 1; - break; - } - proto_config(flag, 1, 0., NULL); - } - break; +#ifdef FREE_CFG_T +static void +free_config_unpeers( + struct config_tree *ptree + ) +{ + struct unpeer_node *curr_unpeer; + + while (NULL != (curr_unpeer = dequeue(ptree->unpeers))) { + destroy_address_node(curr_unpeer->addr); + free_node(curr_unpeer); + } +} +#endif /* FREE_CFG_T */ - case CONFIG_DISABLE: - for (i = 1; i < ntokens; i++) { - int flag; - flag = matchkey(tokens[i], flags_keywords, 1); - if (flag == CONFIG_UNKNOWN) { - msyslog(LOG_ERR, - "disable unknown flag %s", - tokens[i]); - errflg = 1; - break; - } - proto_config(flag, 0, 0., NULL); - } - break; +#ifdef SIM +static void +config_sim( + struct config_tree *ptree + ) +{ + int i; + server_info *serv_info; + struct attr_val *init_stmt; - case CONFIG_PHONE: - for (i = 1; i < ntokens && i < MAXPHONE - 1; i++) { - sys_phone[i - 1] = - emalloc(strlen(tokens[i]) + 1); - strcpy(sys_phone[i - 1], tokens[i]); - } - sys_phone[i] = NULL; - break; + /* Check if a simulate block was found in the configuration code. + * If not, return an error and exit + */ + if (NULL == ptree->sim_details) { + fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n"); + fprintf(stderr, "\tCheck your configuration file.\n"); + exit(1); + } - case CONFIG_ADJ: { - double ftemp; + /* Process the initialization statements + * ------------------------------------- + */ + init_stmt = queue_head(ptree->sim_details->init_opts); + while (init_stmt != NULL) { - sscanf(tokens[1], "%lf", &ftemp); - proto_config(PROTO_ADJ, 0, ftemp, NULL); - } + switch(init_stmt->attr) { + + case T_Beep_Delay: + simulation.beep_delay = init_stmt->value.d; break; + case T_Sim_Duration: + simulation.end_time = init_stmt->value.d; + break; + + default: + fprintf(stderr, + "Unknown simulator init token %d\n", + init_stmt->attr); + exit(1); } + init_stmt = next_node(init_stmt); + } + + + /* Process the server list + * ----------------------- + */ + simulation.num_of_servers = + get_no_of_elements(ptree->sim_details->servers); + simulation.servers = emalloc(simulation.num_of_servers + * sizeof(server_info)); + + serv_info = queue_head(ptree->sim_details->servers); + for (i = 0;i < simulation.num_of_servers; i++) { + if (NULL == serv_info) { + fprintf(stderr, "Simulator server list is corrupt\n"); + exit(1); + } else + memcpy(&simulation.servers[i], serv_info, sizeof(server_info)); + serv_info = next_node(serv_info); } - if (fp[0]) - (void)fclose(fp[0]); + /* Create server associations */ + printf("Creating server associations\n"); + create_server_associations(); + fprintf(stderr,"\tServer associations successfully created!!\n"); +} + + +#ifdef FREE_CFG_T +static void +free_config_sim( + struct config_tree *ptree + ) +{ + if (NULL == ptree->sim_details) + return; + + DESTROY_QUEUE(ptree->sim_details->init_opts); + DESTROY_QUEUE(ptree->sim_details->servers); + + /* Free the sim_node memory and set the sim_details as NULL */ + free_node(ptree->sim_details); + ptree->sim_details = NULL; +} +#endif /* FREE_CFG_T */ +#endif /* SIM */ + + +/* Define two different config functions. One for the daemon and the other for + * the simulator. The simulator ignores a lot of the standard ntpd configuration + * options + */ +#ifndef SIM +static void +config_ntpd( + struct config_tree *ptree + ) +{ + config_nic_rules(ptree); + io_open_sockets(); + config_monitor(ptree); + config_auth(ptree); + config_tos(ptree); + config_access(ptree); + config_tinker(ptree); + config_system_opts(ptree); + config_logconfig(ptree); + config_phone(ptree); + config_setvar(ptree); + config_ttl(ptree); + config_trap(ptree); + config_vars(ptree); + config_other_modes(ptree); + config_peers(ptree); + config_unpeers(ptree); + config_fudge(ptree); + config_qos(ptree); +} +#endif /* !SIM */ + + +#ifdef SIM +static void +config_ntpdsim( + struct config_tree *ptree + ) +{ + printf("Configuring Simulator...\n"); + printf("Some ntpd-specific commands in the configuration file will be ignored.\n"); + + config_tos(ptree); + config_monitor(ptree); + config_tinker(ptree); + config_system_opts(ptree); + config_logconfig(ptree); + config_vars(ptree); + config_sim(ptree); +} +#endif /* SIM */ + + +/* + * config_remotely() - implements ntpd side of ntpq :config + */ +void +config_remotely( + sockaddr_u * remote_addr + ) +{ + struct FILE_INFO remote_cuckoo; + char origin[128]; + + snprintf(origin, sizeof(origin), "remote config from %s", + stoa(remote_addr)); + memset(&remote_cuckoo, 0, sizeof(remote_cuckoo)); + remote_cuckoo.fname = origin; + remote_cuckoo.line_no = 1; + remote_cuckoo.col_no = 1; + ip_file = &remote_cuckoo; + input_from_file = 0; + + init_syntax_tree(&cfgt); + yyparse(); + cfgt.source.attr = CONF_SOURCE_NTPQ; + cfgt.timestamp = time(NULL); + cfgt.source.value.s = estrdup(stoa(remote_addr)); + + DPRINTF(1, ("Finished Parsing!!\n")); + + save_and_apply_config_tree(); + + input_from_file = 1; +} + + +/* + * getconfig() - process startup configuration file e.g /etc/ntp.conf + */ +void +getconfig( + int argc, + char *argv[] + ) +{ + char line[MAXLINE]; + +#ifdef DEBUG + atexit(free_all_config_trees); +#endif +#ifndef SYS_WINNT + config_file = CONFIG_FILE; +#else + temp = CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); + exit(1); + } + config_file = config_file_storage; + + temp = ALT_CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); + exit(1); + } + alt_config_file = alt_config_file_storage; + +#endif /* SYS_WINNT */ + res_fp = NULL; + ntp_syslogmask = NLOG_SYNCMASK; /* set more via logconfig */ + + /* + * install a non default variable with this daemon version + */ + snprintf(line, sizeof(line), "daemon_version=\"%s\"", Version); + set_sys_var(line, strlen(line)+1, RO); + + /* + * Set up for the first time step to install a variable showing + * which syscall is being used to step. + */ + set_tod_using = &ntpd_set_tod_using; + + /* + * On Windows, the variable has already been set, on the rest, + * initialize it to "UNKNOWN". + */ +#ifndef SYS_WINNT + strncpy(line, "settimeofday=\"UNKNOWN\"", sizeof(line)); + set_sys_var(line, strlen(line) + 1, RO); +#endif + + /* + * Initialize the loop. + */ + loop_config(LOOP_DRIFTINIT, 0.); + + getCmdOpts(argc, argv); + + init_syntax_tree(&cfgt); + + curr_include_level = 0; + if ( + (fp[curr_include_level] = F_OPEN(FindConfig(config_file), "r")) == NULL #ifdef HAVE_NETINFO - if (config_netinfo) - free_netinfo_config(config_netinfo); + /* If there is no config_file, try NetInfo. */ + && check_netinfo && !(config_netinfo = get_netinfo_config()) #endif /* HAVE_NETINFO */ + ) { + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); +#ifndef SYS_WINNT + io_open_sockets(); -#if !defined(VMS) && !defined(SYS_VXWORKS) - /* find a keyid */ - if (info_auth_keyid == 0) - req_keyid = 65535; - else - req_keyid = info_auth_keyid; + return; +#else + /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ - /* if doesn't exist, make up one at random */ - if (!authhavekey(req_keyid)) { - char rankey[9]; - int j; - - for (i = 0; i < 8; i++) - for (j = 1; j < 100; ++j) { - rankey[i] = (char) (ntp_random() & 0xff); - if (rankey[i] != 0) break; - } - rankey[8] = 0; - authusekey(req_keyid, KEY_TYPE_MD5, (u_char *)rankey); - authtrust(req_keyid, 1); - if (!authhavekey(req_keyid)) { - msyslog(LOG_ERR, "getconfig: Couldn't generate a valid random key!"); - /* HMS: Should this be fatal? */ + if ((fp[curr_include_level] = F_OPEN(FindConfig(alt_config_file), "r")) == NULL) { + + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); + io_open_sockets(); + + return; } - } + cfgt.source.value.s = estrdup(alt_config_file); +#endif /* SYS_WINNT */ + } else + cfgt.source.value.s = estrdup(config_file); - /* save keyid so we will accept config requests with it */ - info_auth_keyid = req_keyid; -#endif /* !defined(VMS) && !defined(SYS_VXWORKS) */ + + /*** BULK OF THE PARSER ***/ +#ifdef DEBUG + yydebug = !!(debug >= 5); +#endif + ip_file = fp[curr_include_level]; + yyparse(); + + DPRINTF(1, ("Finished Parsing!!\n")); + + cfgt.source.attr = CONF_SOURCE_FILE; + cfgt.timestamp = time(NULL); + + save_and_apply_config_tree(); + + while (curr_include_level != -1) + FCLOSE(fp[curr_include_level--]); + +#ifdef HAVE_NETINFO + if (config_netinfo) + free_netinfo_config(config_netinfo); +#endif /* HAVE_NETINFO */ + + /* + printf("getconfig: res_fp <%p> call_resolver: %d", res_fp, call_resolver); + */ if (res_fp != NULL) { if (call_resolver) { @@ -1912,19 +3937,180 @@ getconfig( } +void +save_and_apply_config_tree(void) +{ + struct config_tree *ptree; +#ifndef SAVECONFIG + struct config_tree *punlinked; +#endif + + /* + * Keep all the configuration trees applied since startup in + * a list that can be used to dump the configuration back to + * a text file. + */ + ptree = emalloc(sizeof(*ptree)); + memcpy(ptree, &cfgt, sizeof(*ptree)); + memset(&cfgt, 0, sizeof(cfgt)); + + LINK_TAIL_SLIST(cfg_tree_history, ptree, link, + struct config_tree); + +#ifdef SAVECONFIG + if (HAVE_OPT( SAVECONFIGQUIT )) { + FILE *dumpfile; + int err; + int dumpfailed; + + dumpfile = fopen(OPT_ARG( SAVECONFIGQUIT ), "w"); + if (NULL == dumpfile) { + err = errno; + fprintf(stderr, + "can not create save file %s, error %d %s\n", + OPT_ARG( SAVECONFIGQUIT ), err, + strerror(err)); + exit(err); + } + + dumpfailed = dump_all_config_trees(dumpfile, 0); + if (dumpfailed) + fprintf(stderr, + "--saveconfigquit %s error %d\n", + OPT_ARG( SAVECONFIGQUIT ), + dumpfailed); + else + fprintf(stderr, + "configuration saved to %s\n", + OPT_ARG( SAVECONFIGQUIT )); + + exit(dumpfailed); + } +#endif /* SAVECONFIG */ + + /* The actual configuration done depends on whether we are configuring the + * simulator or the daemon. Perform a check and call the appropriate + * function as needed. + */ + +#ifndef SIM + config_ntpd(ptree); +#else + config_ntpdsim(ptree); +#endif + + /* + * With configure --disable-saveconfig, there's no use keeping + * the config tree around after application, so free it. + */ +#ifndef SAVECONFIG + UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link, + struct config_tree); + NTP_INSIST(punlinked == ptree); + free_config_tree(ptree); +#endif +} + + +void +ntpd_set_tod_using( + const char *which + ) +{ + char line[128]; + + snprintf(line, sizeof(line), "settimeofday=\"%s\"", which); + set_sys_var(line, strlen(line) + 1, RO); +} + + +/* FUNCTIONS COPIED FROM THE OLDER ntp_config.c + * -------------------------------------------- + */ + + +/* + * get_pfxmatch - find value for prefixmatch + * and update char * accordingly + */ +static u_int32 +get_pfxmatch( + const char ** pstr, + struct masks * m + ) +{ + while (m->name != NULL) { + if (strncmp(*pstr, m->name, strlen(m->name)) == 0) { + *pstr += strlen(m->name); + return m->mask; + } else { + m++; + } + } + return 0; +} + +/* + * get_match - find logmask value + */ +static u_int32 +get_match( + const char * str, + struct masks * m + ) +{ + while (m->name != NULL) { + if (strcmp(str, m->name) == 0) + return m->mask; + else + m++; + } + return 0; +} + +/* + * get_logmask - build bitmask for ntp_syslogmask + */ +static u_int32 +get_logmask( + const char * str + ) +{ + const char * t; + u_int32 offset; + u_int32 mask; + + mask = get_match(str, logcfg_noclass_items); + if (mask != 0) + return mask; + + t = str; + offset = get_pfxmatch(&t, logcfg_class); + mask = get_match(t, logcfg_class_items); + + if (mask) + return mask << offset; + else + msyslog(LOG_ERR, "logconfig: '%s' not recognized - ignored", + str); + + return 0; +} + + #ifdef HAVE_NETINFO -/* +/* * get_netinfo_config - find the nearest NetInfo domain with an ntp * configuration and initialize the configuration state. */ static struct netinfo_config_state * -get_netinfo_config() +get_netinfo_config(void) { ni_status status; void *domain; ni_id config_dir; - struct netinfo_config_state *config; + struct netinfo_config_state *config; if (ni_open(NULL, ".", &domain) != NI_OK) return NULL; @@ -1942,12 +4128,12 @@ get_netinfo_config() return NULL; } - config = (struct netinfo_config_state *)malloc(sizeof(struct netinfo_config_state)); - config->domain = domain; - config->config_dir = config_dir; - config->prop_index = 0; - config->val_index = 0; - config->val_list = NULL; + config = emalloc(sizeof(*config)); + config->domain = domain; + config->config_dir = config_dir; + config->prop_index = 0; + config->val_index = 0; + config->val_list = NULL; return config; } @@ -1958,7 +4144,9 @@ get_netinfo_config() * free_netinfo_config - release NetInfo configuration state */ static void -free_netinfo_config(struct netinfo_config_state *config) +free_netinfo_config( + struct netinfo_config_state *config + ) { ni_free(config->domain); free(config); @@ -1983,35 +4171,39 @@ gettokens_netinfo ( /* * Iterate through each keyword and look for a property that matches it. */ - again: + again: if (!val_list) { - for (; prop_index < (sizeof(keywords)/sizeof(keywords[0])); prop_index++) - { - ni_namelist namelist; + for (; prop_index < COUNTOF(keywords); prop_index++) + { + ni_namelist namelist; struct keyword current_prop = keywords[prop_index]; + ni_index index; /* * For each value associated in the property, we're going to return * a separate line. We squirrel away the values in the config state * so the next time through, we don't need to do this lookup. */ - NI_INIT(&namelist); - if (ni_lookupprop(config->domain, &config->config_dir, current_prop.text, &namelist) == NI_OK) { - ni_index index; + NI_INIT(&namelist); + if (NI_OK == ni_lookupprop(config->domain, + &config->config_dir, current_prop.text, + &namelist)) { /* Found the property, but it has no values */ if (namelist.ni_namelist_len == 0) continue; - if (! (val_list = config->val_list = (char**)malloc(sizeof(char*) * (namelist.ni_namelist_len + 1)))) - { msyslog(LOG_ERR, "out of memory while configuring"); break; } + config->val_list = + emalloc(sizeof(char*) * + (namelist.ni_namelist_len + 1)); + val_list = config->val_list; - for (index = 0; index < namelist.ni_namelist_len; index++) { - char *value = namelist.ni_namelist_val[index]; - - if (! (val_list[index] = (char*)malloc(strlen(value)+1))) - { msyslog(LOG_ERR, "out of memory while configuring"); break; } - - strcpy(val_list[index], value); + for (index = 0; + index < namelist.ni_namelist_len; + index++) { + char *value; + + value = namelist.ni_namelist_val[index]; + val_list[index] = estrdup(value); } val_list[index] = NULL; @@ -2023,14 +4215,14 @@ gettokens_netinfo ( } /* No list; we're done here. */ - if (!val_list) return CONFIG_UNKNOWN; + if (!val_list) + return CONFIG_UNKNOWN; /* * We have a list of values for the current property. * Iterate through them and return each in order. */ - if (val_list[val_index]) - { + if (val_list[val_index]) { int ntok = 1; int quoted = 0; char *tokens = val_list[val_index]; @@ -2048,16 +4240,18 @@ gettokens_netinfo ( break; } else { /* must be space */ *tokens++ = '\0'; - while (ISSPACE(*tokens)) tokens++; - if (ISEOL(*tokens)) break; + while (ISSPACE(*tokens)) + tokens++; + if (ISEOL(*tokens)) + break; } } if (ntok == MAXTOKENS) { /* HMS: chomp it to lose the EOL? */ msyslog(LOG_ERR, - "gettokens_netinfo: too many tokens. Ignoring: %s", - tokens); + "gettokens_netinfo: too many tokens. Ignoring: %s", + tokens); } else { *ntokens = ntok + 1; } @@ -2073,220 +4267,144 @@ gettokens_netinfo ( /* Free val_list and reset counters. */ for (val_index = 0; val_list[val_index]; val_index++) free(val_list[val_index]); - free(val_list); val_list = config->val_list = NULL; val_index = config->val_index = 0; + free(val_list); + val_list = config->val_list = NULL; + val_index = config->val_index = 0; goto again; } #endif /* HAVE_NETINFO */ - /* - * gettokens - read a line and return tokens + * getnetnum - return a net number (this is crude, but careful) + * + * returns 1 for success, and mysteriously, 0 or -1 for failure */ static int -gettokens ( - FILE *fp, - char *line, - char **tokenlist, - int *ntokens +getnetnum( + const char *num, + sockaddr_u *addr, + int complain, + enum gnn_type a_type ) { - register char *cp; - register int ntok; - register int quoted = 0; - - /* - * Find start of first token - */ - again: - while ((cp = fgets(line, MAXLINE, fp)) != NULL) { - cp = line; - while (ISSPACE(*cp)) - cp++; - if (!ISEOL(*cp)) - break; - } - if (cp == NULL) { - *ntokens = 0; - return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */ - } - - /* - * Now separate out the tokens - */ - for (ntok = 0; ntok < MAXTOKENS; ntok++) { - tokenlist[ntok] = cp; - while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted)) - quoted ^= (*cp++ == '"'); - - if (ISEOL(*cp)) { - *cp = '\0'; - break; - } else { /* must be space */ - *cp++ = '\0'; - while (ISSPACE(*cp)) - cp++; - if (ISEOL(*cp)) - break; - } - } + int retval; + struct addrinfo *res; - /* Heiko: Remove leading and trailing quotes around tokens */ - { - int i,j = 0; - - - for (i = 0; i < ntok; i++) { - /* Now check if the first char is a quote and remove that */ - if ( tokenlist[ntok][0] == '"' ) - tokenlist[ntok]++; - - /* Now check the last char ... */ - j = strlen(tokenlist[ntok])-1; - if ( tokenlist[ntok][j] == '"' ) - tokenlist[ntok][j] = '\0'; - } - - } + /* Get all the addresses that resolve to this name */ + retval = get_multiple_netnums(num, addr, &res, complain, a_type); - if (ntok == MAXTOKENS) { - --ntok; - /* HMS: chomp it to lose the EOL? */ - msyslog(LOG_ERR, - "gettokens: too many tokens on the line. Ignoring %s", - cp); - } else { - /* - * Return the match - */ - *ntokens = ntok + 1; - ntok = matchkey(tokenlist[0], keywords, 1); - if (ntok == CONFIG_UNKNOWN) - goto again; + if (retval != 1) { + /* Name resolution failed */ + return retval; } - return ntok; -} - + memcpy(addr, res->ai_addr, res->ai_addrlen); + DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr))); -/* - * matchkey - match a keyword to a list - */ -static int -matchkey( - register char *word, - register struct keyword *keys, - int complain - ) -{ - for (;;) { - if (keys->keytype == CONFIG_UNKNOWN) { - if (complain) - msyslog(LOG_ERR, - "configure: keyword \"%s\" unknown, line ignored", - word); - return CONFIG_UNKNOWN; - } - if (STRSAME(word, keys->text)) - return keys->keytype; - keys++; - } + freeaddrinfo(res); + return 1; } /* - * getnetnum - return a net number (this is crude, but careful) + * get_multiple_netnums + * + * returns 1 for success, and mysteriously, 0 or -1 for failure */ static int -getnetnum( - const char *num, - struct sockaddr_storage *addr, +get_multiple_netnums( + const char *nameornum, + sockaddr_u *addr, + struct addrinfo **res, int complain, enum gnn_type a_type ) { + char lookbuf[1024]; + const char *lookup; + char *pch; struct addrinfo hints; struct addrinfo *ptr; int retval; + sockaddr_u ipaddr; -#if 0 - printf("getnetnum: <%s> is a %s (%d)\n", - num, - (a_type == t_UNK) - ? "t_UNK" - : (a_type == t_REF) - ? "t_REF" - : (a_type == t_MSK) - ? "t_MSK" - : "???", - a_type); -#endif - - /* Get host address. Looking for UDP datagram connection */ - memset(&hints, 0, sizeof (hints)); - if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6) - hints.ai_family = addr->ss_family; - else - hints.ai_family = AF_UNSPEC; - /* - * If we don't have an IPv6 stack, just look up IPv4 addresses - */ - if (isc_net_probeipv6() != ISC_R_SUCCESS) - hints.ai_family = AF_INET; + memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; + if (strlen(nameornum) >= sizeof(lookbuf)) { + NTP_INSIST(strlen(nameornum) < sizeof(lookbuf)); + return 0; + } - if (a_type != t_UNK) { + lookup = nameornum; + if (is_ip_address(nameornum, &ipaddr)) { hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF(&ipaddr); + if ('[' == nameornum[0]) { + lookup = lookbuf; + strncpy(lookbuf, &nameornum[1], + sizeof(lookbuf)); + pch = strchr(lookbuf, ']'); + if (pch != NULL) + *pch = '\0'; + } + pch = strchr(lookup, '%'); + if (pch != NULL) { + if (lookup != lookbuf) { + lookup = lookbuf; + strncpy(lookbuf, nameornum, + sizeof(lookbuf)); + pch = strchr(lookup, '%'); + } + *pch = '\0'; + } } -#ifdef DEBUG - if (debug > 3) - printf("getnetnum: calling getaddrinfo(%s,...)\n", num); -#endif - retval = getaddrinfo(num, "ntp", &hints, &ptr); - if (retval != 0 || - (ptr->ai_family == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) { + if (AF_INET6 == hints.ai_family && !ipv6_works) + return 0; + + if (AF_UNSPEC == hints.ai_family) { + if (!ipv6_works) + hints.ai_family = AF_INET; + else if (!ipv4_works) + hints.ai_family = AF_INET6; + else if (IS_IPV4(addr) || IS_IPV6(addr)) + hints.ai_family = AF(addr); + } + + /* Get host address. Looking for UDP datagram connection */ + hints.ai_socktype = SOCK_DGRAM; + + DPRINTF(4, ("getaddrinfo %s%s\n", + (AF_UNSPEC == hints.ai_family) + ? "" + : (AF_INET == hints.ai_family) + ? "v4 " + : "v6 ", + lookup)); + + retval = getaddrinfo(lookup, "ntp", &hints, &ptr); + + if (retval || (AF_INET6 == ptr->ai_family && !ipv6_works)) { if (complain) msyslog(LOG_ERR, "getaddrinfo: \"%s\" invalid host address, ignored", - num); -#ifdef DEBUG - if (debug > 0) - printf( - "getaddrinfo: \"%s\" invalid host address%s.\n", - num, (complain) - ? ", ignored" - : ""); -#endif - if (retval == 0 && - ptr->ai_family == AF_INET6 && - isc_net_probeipv6() != ISC_R_SUCCESS) - { + lookup); + else + DPRINTF(1, ("getaddrinfo: \"%s\" invalid host address.\n", + lookup)); + + if (!retval) { + freeaddrinfo(ptr); return -1; - } - else { + } else { return 0; } } + *res = ptr; - memcpy(addr, ptr->ai_addr, ptr->ai_addrlen); -#ifdef DEBUG - if (debug > 1) - printf("getnetnum given %s, got %s (%s/%d)\n", - num, stoa(addr), - (a_type == t_UNK) - ? "t_UNK" - : (a_type == t_REF) - ? "t_REF" - : (a_type == t_MSK) - ? "t_MSK" - : "???", - a_type); -#endif - freeaddrinfo(ptr); return 1; } @@ -2318,6 +4436,8 @@ catchchild( static void save_resolve( char *name, + int no_needed, + int type, int mode, int version, int minpoll, @@ -2331,16 +4451,26 @@ save_resolve( #ifndef SYS_VXWORKS if (res_fp == NULL) { #ifndef SYS_WINNT - (void) strcpy(res_file, RES_TEMPFILE); + strcpy(res_file, RES_TEMPFILE); #else + int len; + /* no /tmp directory under NT */ - { - if(!(GetTempPath((DWORD)MAX_PATH, (LPTSTR)res_file))) { - msyslog(LOG_ERR, "cannot get pathname for temporary directory: %m"); - return; - } - (void) strcat(res_file, "ntpdXXXXXX"); + if (!GetTempPath(sizeof res_file, res_file)) { + msyslog(LOG_ERR, "can not get temp dir: %m"); + exit(1); } + + len = strlen(res_file); + if (sizeof res_file < len + sizeof "ntpdXXXXXX") { + msyslog(LOG_ERR, + "temporary directory path %s too long", + res_file); + exit(1); + } + + memmove(res_file + len, "ntpdXXXXXX", + sizeof "ntpdXXXXXX"); #endif /* SYS_WINNT */ #ifdef HAVE_MKSTEMP { @@ -2351,7 +4481,7 @@ save_resolve( res_fp = fdopen(fd, "r+"); } #else - (void) mktemp(res_file); + mktemp(res_file); res_fp = fopen(res_file, "w"); #endif if (res_fp == NULL) { @@ -2365,12 +4495,15 @@ save_resolve( } #endif - (void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %s\n", name, - mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); + (void)fprintf(res_fp, "%s %d %d %d %d %d %d %d %d %u %s\n", + name, no_needed, type, + mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); #ifdef DEBUG if (debug > 1) - printf("config: %s %d %d %d %d %x %d %u %s\n", name, mode, - version, minpoll, maxpoll, flags, ttl, keyid, keystr); + printf("config: %s %d %d %d %d %d %d %x %d %u %s\n", + name, no_needed, type, + mode, version, minpoll, maxpoll, flags, + ttl, keyid, keystr); #endif #else /* SYS_VXWORKS */ @@ -2397,7 +4530,10 @@ abort_resolve(void) #ifndef SYS_VXWORKS /* we don't open the file to begin with */ #if !defined(VMS) - (void) unlink(res_file); + if (unlink(res_file)) + msyslog(LOG_WARNING, + "Unable to remove temporary resolver file %s, %m", + res_file); #else (void) delete(res_file); #endif /* VMS */ @@ -2407,9 +4543,9 @@ abort_resolve(void) /* * do_resolve_internal - start up the resolver function (not program) - */ -/* - * On VMS, this routine will simply refuse to resolve anything. + * + * On VMS, VxWorks, and Unix-like systems lacking fork(), this routine + * will simply refuse to resolve anything. * * Possible implementation: keep `res_file' in memory, do async * name resolution via QIO, update from within completion AST. @@ -2418,7 +4554,9 @@ abort_resolve(void) static void do_resolve_internal(void) { +#ifndef SYS_WINNT int i; +#endif if (res_fp == NULL) { /* belch */ @@ -2431,12 +4569,11 @@ do_resolve_internal(void) (void) fclose(res_fp); res_fp = NULL; -#if !defined(VMS) && !defined (SYS_VXWORKS) +#ifndef NO_INTRES req_file = res_file; /* set up pointer to res file */ #ifndef SYS_WINNT (void) signal_no_reset(SIGCHLD, catchchild); -#ifndef SYS_VXWORKS /* the parent process will write to the pipe * in order to wake up to child process * which may be waiting in a select() call @@ -2487,36 +4624,19 @@ do_resolve_internal(void) * THUS: */ - /* This is the child process who will read the pipe, - * so we close the write fd */ - close(resolver_pipe_fd[1]); + /* + msyslog(LOG_INFO, "do_resolve_internal: pre-closelog"); + */ closelog(); kill_asyncio(0); (void) signal_no_reset(SIGCHLD, SIG_DFL); -#ifdef DEBUG - if (0) - debug = 2; -#endif - -# ifndef LOG_DAEMON - openlog("ntpd_initres", LOG_PID); -# else /* LOG_DAEMON */ - -# ifndef LOG_NTP -# define LOG_NTP LOG_DAEMON -# endif - openlog("ntpd_initres", LOG_PID | LOG_NDELAY, LOG_NTP); -#ifndef SYS_CYGWIN32 -# ifdef DEBUG - if (debug) - setlogmask(LOG_UPTO(LOG_DEBUG)); - else -# endif /* DEBUG */ - setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ -# endif /* LOG_DAEMON */ -#endif + init_logging("ntpd_intres", 0); + setup_logfile(); + /* + msyslog(LOG_INFO, "do_resolve_internal: post-closelog"); + */ ntp_intres(); @@ -2528,52 +4648,47 @@ do_resolve_internal(void) abort_resolve(); exit(1); } -#else - /* vxWorks spawns a thread... -casey */ - i = sp (ntp_intres); - /*i = taskSpawn("ntp_intres",100,VX_FP_TASK,20000,ntp_intres);*/ -#endif if (i == -1) { msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m"); (void) signal_no_reset(SIGCHLD, SIG_DFL); abort_resolve(); - } - else { + } else /* This is the parent process who will write to the pipe, * so we close the read fd */ close(resolver_pipe_fd[0]); - } #else /* SYS_WINNT */ { /* NT's equivalent of fork() is _spawn(), but the start point * of the new process is an executable filename rather than * a function name as desired here. */ - DWORD dwThreadId; + unsigned thread_id; + uintptr_t res_thd_handle; + fflush(stdout); ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL); if (ResolverEventHandle == NULL) { msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres"); abort_resolve(); } - ResolverThreadHandle = CreateThread( - NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE) ntp_intres, /* thread function */ - NULL, /* argument to thread function */ - 0, /* use default creation flags */ - &dwThreadId); /* returns the thread identifier */ - if (ResolverThreadHandle == NULL) { - msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres"); + res_thd_handle = _beginthreadex( + NULL, /* no security attributes */ + 0, /* use default stack size */ + ntp_intres_thread, /* thread function */ + NULL, /* argument to thread function */ + 0, /* use default creation flags */ + &thread_id); /* receives thread identifier */ + if (!res_thd_handle) { + msyslog(LOG_ERR, "_beginthreadex ntp_intres_thread failed %m"); CloseHandle(ResolverEventHandle); ResolverEventHandle = NULL; abort_resolve(); } } #endif /* SYS_WINNT */ -#else /* VMS VX_WORKS */ +#else /* NO_INTRES follows */ msyslog(LOG_ERR, - "Name resolution not implemented for VMS - use numeric addresses"); + "Deferred DNS not implemented - use numeric addresses"); abort_resolve(); -#endif /* VMS VX_WORKS */ +#endif } |