diff options
Diffstat (limited to 'ntpd/ntp_config.c')
-rw-r--r-- | ntpd/ntp_config.c | 4357 |
1 files changed, 2310 insertions, 2047 deletions
diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index db9682a74cbd..0f48983f82e5 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -17,26 +17,6 @@ # 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 @@ -46,31 +26,43 @@ #ifndef SIGCHLD # define SIGCHLD SIGCLD #endif -#if !defined(VMS) -# ifdef HAVE_SYS_WAIT_H -# include <sys/wait.h> -# endif -#endif /* VMS */ +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif -#ifdef SYS_WINNT -# include <io.h> -HANDLE ResolverEventHandle; -#else -int resolver_pipe_fd[2]; /* used to let the resolver process alert the parent process */ -#endif /* SYS_WINNT */ +#include <isc/net.h> +#include <isc/result.h> +#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 "lib_strbuf.h" +#include "ntp_assert.h" +#include "ntp_random.h" /* * [Bug 467]: Some linux headers collide with CONFIG_PHONE and CONFIG_KEYS * so #include these later. */ - #include "ntp_config.h" #include "ntp_cmdargs.h" - #include "ntp_scanner.h" #include "ntp_parser.h" -#include "ntp_data_structures.h" +#include "ntpd-opts.h" + + +/* Bison still(!) does not emit usable prototypes for the calling code */ +int yyparse (struct FILE_INFO *ip_file); + +/* list of servers from command line for config_peers() */ +int cmdline_server_count; +char ** cmdline_servers; +/* set to zero if admin doesn't want memory locked */ +int do_memlock = 1; /* * "logconfig" building blocks @@ -113,6 +105,19 @@ static struct masks logcfg_class_items[] = { { NULL, 0 } }; +typedef struct peer_resolved_ctx_tag { + int flags; + int host_mode; /* T_* token identifier */ + u_short family; + keyid_t keyid; + u_char hmode; /* MODE_* */ + u_char version; + u_char minpoll; + u_char maxpoll; + u_int32 ttl; + const char * group; +} peer_resolved_ctx; + /* Limits */ #define MAXPHONE 10 /* maximum number of phone strings */ #define MAXPPS 20 /* maximum length of PPS device string */ @@ -120,22 +125,8 @@ static struct masks logcfg_class_items[] = { /* * Miscellaneous macros */ -#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) #define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0') #define ISSPACE(c) ((c) == ' ' || (c) == '\t') -#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) - -/* - * File descriptor used by the resolver save routines, and temporary file - * name. - */ -int call_resolver = 1; /* ntp-genkeys sets this to 0, for example */ -#ifndef SYS_WINNT -static char res_file[20]; /* enough for /tmp/ntpXXXXXX\0 */ -#define RES_TEMPFILE "/tmp/ntpXXXXXX" -#else -static char res_file[MAX_PATH]; -#endif /* SYS_WINNT */ /* * Definitions of things either imported from or exported to outside @@ -143,9 +134,8 @@ static char res_file[MAX_PATH]; 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 */ +config_tree cfgt; /* Parser output stored here */ +struct config_tree_tag *cfg_tree_history; /* History of configs */ char *sys_phone[MAXPHONE] = {NULL}; /* ACTS phone numbers */ char default_keysdir[] = NTP_KEYSDIR; char *keysdir = default_keysdir; /* crypto keys directory */ @@ -156,7 +146,7 @@ int config_priority; #endif const char *config_file; -char default_ntp_signd_socket[] = +static char default_ntp_signd_socket[] = #ifdef NTP_SIGND_PATH NTP_SIGND_PATH; #else @@ -183,7 +173,7 @@ struct netinfo_config_state { ni_id config_dir; /* ID config dir */ int prop_index; /* current property */ int val_index; /* current value */ - char **val_list; /* value list */ + char **val_list; /* value list */ }; #endif @@ -201,12 +191,7 @@ int old_config_style = 1; /* A boolean flag, which when set, */ 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 /* @@ -228,72 +213,132 @@ int *p_bcXXXX_enabled = &bc_list[0].enabled; /* FUNCTION PROTOTYPES */ -static void apply_enable_disable(queue *q, int enable); -static void init_syntax_tree(struct config_tree *); +static void init_syntax_tree(config_tree *); +static void apply_enable_disable(attr_val_fifo *q, int enable); #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 *); +static void free_auth_node(config_tree *); +static void free_all_config_trees(void); + +static void free_config_access(config_tree *); +static void free_config_auth(config_tree *); +static void free_config_fudge(config_tree *); +static void free_config_logconfig(config_tree *); +static void free_config_monitor(config_tree *); +static void free_config_nic_rules(config_tree *); +static void free_config_other_modes(config_tree *); +static void free_config_peers(config_tree *); +static void free_config_phone(config_tree *); +static void free_config_reset_counters(config_tree *); +static void free_config_rlimit(config_tree *); +static void free_config_setvar(config_tree *); +static void free_config_system_opts(config_tree *); +static void free_config_tinker(config_tree *); +static void free_config_tos(config_tree *); +static void free_config_trap(config_tree *); +static void free_config_ttl(config_tree *); +static void free_config_unpeers(config_tree *); +static void free_config_vars(config_tree *); + #ifdef SIM -static void free_config_sim(struct config_tree *); +static void free_config_sim(config_tree *); #endif - +static void destroy_address_fifo(address_fifo *); +#define FREE_ADDRESS_FIFO(pf) \ + do { \ + destroy_address_fifo(pf); \ + (pf) = NULL; \ + } while (0) void free_all_config_trees(void); /* atexit() */ -static void free_config_tree(struct config_tree *ptree); +static void free_config_tree(config_tree *ptree); #endif /* FREE_CFG_T */ -double *create_dval(double val); -void destroy_restrict_node(struct restrict_node *my_node); +static void destroy_restrict_node(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 *); +static void destroy_int_fifo(int_fifo *); +#define FREE_INT_FIFO(pf) \ + do { \ + destroy_int_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_string_fifo(string_fifo *); +#define FREE_STRING_FIFO(pf) \ + do { \ + destroy_string_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_attr_val_fifo(attr_val_fifo *); +#define FREE_ATTR_VAL_FIFO(pf) \ + do { \ + destroy_attr_val_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_filegen_fifo(filegen_fifo *); +#define FREE_FILEGEN_FIFO(pf) \ + do { \ + destroy_filegen_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_restrict_fifo(restrict_fifo *); +#define FREE_RESTRICT_FIFO(pf) \ + do { \ + destroy_restrict_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_setvar_fifo(setvar_fifo *); +#define FREE_SETVAR_FIFO(pf) \ + do { \ + destroy_setvar_fifo(pf); \ + (pf) = NULL; \ + } while (0) +static void destroy_addr_opts_fifo(addr_opts_fifo *); +#define FREE_ADDR_OPTS_FIFO(pf) \ + do { \ + destroy_addr_opts_fifo(pf); \ + (pf) = NULL; \ + } while (0) + +static void config_logconfig(config_tree *); +static void config_monitor(config_tree *); +static void config_rlimit(config_tree *); +static void config_system_opts(config_tree *); +static void config_tinker(config_tree *); +static void config_tos(config_tree *); +static void config_vars(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 *); +static sockaddr_u *get_next_address(address_node *addr); +static void config_sim(config_tree *); +static void config_ntpdsim(config_tree *); +#else /* !SIM follows */ +static void config_ntpd(config_tree *); +static void config_other_modes(config_tree *); +static void config_auth(config_tree *); +static void config_access(config_tree *); +static void config_phone(config_tree *); +static void config_setvar(config_tree *); +static void config_ttl(config_tree *); +static void config_trap(config_tree *); +static void config_fudge(config_tree *); +static void config_peers(config_tree *); +static void config_unpeers(config_tree *); +static void config_nic_rules(config_tree *); +static void config_reset_counters(config_tree *); +static u_char get_correct_host_mode(int token); +static int peerflag_bits(peer_node *); +#endif /* !SIM */ + +#ifdef WORKER +static void peer_name_resolved(int, int, void *, const char *, const char *, + const struct addrinfo *, + const struct addrinfo *); +static void unpeer_name_resolved(int, int, void *, const char *, const char *, + const struct addrinfo *, + const struct addrinfo *); +static void trap_name_resolved(int, int, void *, const char *, const char *, + const struct addrinfo *, + const struct addrinfo *); #endif enum gnn_type { @@ -302,29 +347,15 @@ enum gnn_type { t_MSK /* Network Mask */ }; -#define DESTROY_QUEUE(q) \ -do { \ - if (q) { \ - destroy_queue(q); \ - (q) = NULL; \ - } \ -} while (0) - -void ntpd_set_tod_using(const char *); +static void ntpd_set_tod_using(const char *); +static char * normal_dtoa(double); 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, +#ifndef SIM +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); - +#endif /* FUNCTIONS FOR INITIALIZATION @@ -334,7 +365,7 @@ static void do_resolve_internal(void); #ifdef FREE_CFG_T static void free_auth_node( - struct config_tree *ptree + config_tree *ptree ) { if (ptree->auth.keys) { @@ -357,43 +388,19 @@ free_auth_node( static void init_syntax_tree( - struct config_tree *ptree + config_tree *ptree ) { - 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(); + ZERO(*ptree); } #ifdef FREE_CFG_T -void +static void free_all_config_trees(void) { - struct config_tree *ptree; - struct config_tree *pnext; + config_tree *ptree; + config_tree *pnext; ptree = cfg_tree_history; @@ -407,7 +414,7 @@ free_all_config_trees(void) static void free_config_tree( - struct config_tree *ptree + config_tree *ptree ) { #if defined(_MSC_VER) && defined (_DEBUG) @@ -423,10 +430,10 @@ free_config_tree( free_config_monitor(ptree); free_config_access(ptree); free_config_tinker(ptree); + free_config_rlimit(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); @@ -435,36 +442,10 @@ free_config_tree( free_config_peers(ptree); free_config_unpeers(ptree); free_config_nic_rules(ptree); + free_config_reset_counters(ptree); #ifdef SIM free_config_sim(ptree); #endif - /* - * 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. - */ - 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); @@ -482,14 +463,15 @@ int dump_all_config_trees( FILE *df, int comment - ) + ) { - struct config_tree *cfg_ptr = cfg_tree_history; - int return_value = 0; + config_tree * cfg_ptr; + int return_value; + return_value = 0; for (cfg_ptr = cfg_tree_history; - cfg_ptr != NULL; - cfg_ptr = cfg_ptr->link) + cfg_ptr != NULL; + cfg_ptr = cfg_ptr->link) return_value |= dump_config_tree(cfg_ptr, df, comment); return return_value; @@ -499,33 +481,30 @@ dump_all_config_trees( /* The config dumper */ int dump_config_tree( - struct config_tree *ptree, + 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; + peer_node *peern; + unpeer_node *unpeern; + attr_val *atrv; + address_node *addr; + address_node *peer_addr; + address_node *fudge_addr; + filegen_node *fgen_node; + restrict_node *rest_node; + addr_opts_node *addr_opts; + setvar_node *setv_node; nic_rule_node *rule_node; + int_node *i_n; + int_node *flags; + int_node *counter_set; + string_node *str_node; - char **pstr = NULL; + const char *s; 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; @@ -546,139 +525,103 @@ dump_config_tree( } /* 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)) { - - atrv = (struct attr_val *) list_ptr; - - switch (atrv->attr) { - + atrv = HEAD_PFIFO(ptree->vars); + for ( ; atrv != NULL; atrv = atrv->link) { + switch (atrv->type) { +#ifdef DEBUG default: fprintf(df, "\n# dump error:\n" - "# unknown vars token %s\n", + "# unknown vars type %d (%s) for %s\n", + atrv->type, token_name(atrv->type), token_name(atrv->attr)); break; - - /* 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), + case T_Double: + fprintf(df, "%s %s\n", keyword(atrv->attr), + normal_dtoa(atrv->value.d)); + break; + + case T_Integer: + fprintf(df, "%s %d\n", keyword(atrv->attr), atrv->value.i); break; - /* strings */ - case T_Driftfile: - case T_Leapfile: - case T_Logfile: - case T_Pidfile: - case T_Saveconfigdir: - fprintf(df, "%s \"%s\"\n", - keyword(atrv->attr), + case T_String: + fprintf(df, "%s \"%s\"", keyword(atrv->attr), atrv->value.s); + if (T_Driftfile == atrv->attr && + atrv->link != NULL && + T_WanderThreshold == atrv->link->attr) { + atrv = atrv->link; + fprintf(df, " %s\n", + normal_dtoa(atrv->value.d)); + } else { + fprintf(df, "\n"); + } break; } } - list_ptr = queue_head(ptree->logconfig); - if (list_ptr != NULL) { - + atrv = HEAD_PFIFO(ptree->logconfig); + if (atrv != NULL) { fprintf(df, "logconfig"); - - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - atrv = list_ptr; + for ( ; atrv != NULL; atrv = atrv->link) fprintf(df, " %c%s", atrv->attr, atrv->value.s); - } fprintf(df, "\n"); } if (ptree->stats_dir) fprintf(df, "statsdir \"%s\"\n", ptree->stats_dir); - list_ptr = queue_head(ptree->stats_list); - if (list_ptr != NULL) { - + i_n = HEAD_PFIFO(ptree->stats_list); + if (i_n != NULL) { fprintf(df, "statistics"); - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - intp = list_ptr; - - fprintf(df, " %s", keyword(*intp)); - } - + for ( ; i_n != NULL; i_n = i_n->link) + fprintf(df, " %s", keyword(i_n->i)); 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", + fgen_node = HEAD_PFIFO(ptree->filegen_opts); + for ( ; fgen_node != NULL; fgen_node = fgen_node->link) { + atrv = HEAD_PFIFO(fgen_node->options); + if (atrv != NULL) { + fprintf(df, "filegen %s", keyword(fgen_node->filegen_token)); + for ( ; atrv != NULL; atrv = atrv->link) { + switch (atrv->attr) { +#ifdef DEBUG + 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; +#endif + case T_File: + fprintf(df, " file %s", + atrv->value.s); + break; - 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; - - case T_File: - fprintf(df, " file %s", - atrv->value.s); - break; - - case T_Type: - fprintf(df, " type %s", - keyword(atrv->value.i)); - break; + case T_Type: + fprintf(df, " type %s", + keyword(atrv->value.i)); + break; - case T_Flag: - fprintf(df, " %s", - keyword(atrv->value.i)); - break; + case T_Flag: + fprintf(df, " %s", + keyword(atrv->value.i)); + break; + } } - + fprintf(df, "\n"); } - - fprintf(df, "\n"); } - list_ptr = queue_head(ptree->auth.crypto_cmd_list); - if (list_ptr != NULL) { + atrv = HEAD_PFIFO(ptree->auth.crypto_cmd_list); + if (atrv != NULL) { fprintf(df, "crypto"); - - for (; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - atrv = list_ptr; + for ( ; atrv != NULL; atrv = atrv->link) { fprintf(df, " %s %s", keyword(atrv->attr), atrv->value.s); } @@ -688,27 +631,29 @@ dump_config_tree( if (ptree->auth.revoke != 0) fprintf(df, "revoke %d\n", ptree->auth.revoke); - if (NULL != ptree->auth.keysdir) + if (ptree->auth.keysdir != NULL) fprintf(df, "keysdir \"%s\"\n", ptree->auth.keysdir); - if (NULL != ptree->auth.keys) + if (ptree->auth.keys != NULL) fprintf(df, "keys \"%s\"\n", ptree->auth.keys); - atrv = queue_head(ptree->auth.trusted_key_list); + atrv = HEAD_PFIFO(ptree->auth.trusted_key_list); if (atrv != NULL) { fprintf(df, "trustedkey"); - do { - if ('i' == atrv->attr) + for ( ; atrv != NULL; atrv = atrv->link) { + if (T_Integer == atrv->type) fprintf(df, " %d", atrv->value.i); - else if ('-' == atrv->attr) - fprintf(df, " (%u ... %u)", - atrv->value.u >> 16, - atrv->value.u & 0xffff); + else if (T_Intrange == atrv->type) + fprintf(df, " (%d ... %d)", + atrv->value.r.first, + atrv->value.r.last); +#ifdef DEBUG else fprintf(df, "\n# dump error:\n" - "# unknown trustedkey attr %d\n" - "trustedkey", atrv->attr); - } while (NULL != (atrv = next_node(atrv))); + "# unknown trustedkey attr type %d\n" + "trustedkey", atrv->type); +#endif + } fprintf(df, "\n"); } @@ -720,104 +665,81 @@ dump_config_tree( /* 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) + atrv = (enable) + ? HEAD_PFIFO(ptree->enable_opts) + : HEAD_PFIFO(ptree->disable_opts); + if (atrv != NULL) { + fprintf(df, "%s", (enable) ? "enable" : "disable"); - - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - atrv = (struct attr_val *) list_ptr; - + for ( ; atrv != NULL; atrv = atrv->link) fprintf(df, " %s", keyword(atrv->value.i)); - } fprintf(df, "\n"); } } - list_ptr = queue_head(ptree->orphan_cmds); - if (list_ptr != NULL) + atrv = HEAD_PFIFO(ptree->orphan_cmds); + if (atrv != NULL) { fprintf(df, "tos"); + for ( ; atrv != NULL; atrv = atrv->link) { + switch (atrv->type) { +#ifdef DEBUG + default: + fprintf(df, "\n# dump error:\n" + "# unknown tos attr type %d %s\n" + "tos", atrv->type, + token_name(atrv->type)); + break; +#endif + case T_Double: + fprintf(df, " %s %s", + keyword(atrv->attr), + normal_dtoa(atrv->value.d)); + break; + } + } + fprintf(df, "\n"); + } - 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: + atrv = HEAD_PFIFO(ptree->rlimit); + if (atrv != NULL) { + fprintf(df, "rlimit"); + for ( ; atrv != NULL; atrv = atrv->link) { + INSIST(T_Integer == atrv->type); 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; + atrv->value.i); } - } - if (queue_head(ptree->orphan_cmds) != NULL) fprintf(df, "\n"); + } - list_ptr = queue_head(ptree->tinker); - if (list_ptr != NULL) { - + atrv = HEAD_PFIFO(ptree->tinker); + if (atrv != 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); + for ( ; atrv != NULL; atrv = atrv->link) { + INSIST(T_Double == atrv->type); + fprintf(df, " %s %s", keyword(atrv->attr), + normal_dtoa(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)); - + peern = HEAD_PFIFO(ptree->peers); + for ( ; peern != NULL; peern = peern->link) { + addr = peern->addr; + fprintf(df, "%s", keyword(peern->host_mode)); switch (addr->type) { - +#ifdef DEBUG default: fprintf(df, "# dump error:\n" "# unknown peer family %d for:\n" - "peer", addr->type); + "%s", addr->type, + keyword(peern->host_mode)); break; - +#endif case AF_UNSPEC: break; @@ -830,179 +752,157 @@ dump_config_tree( 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 (peern->minpoll != 0) + fprintf(df, " minpoll %u", peern->minpoll); + + if (peern->maxpoll != 0) + fprintf(df, " maxpoll %u", peern->maxpoll); - if (peer->ttl != 0) { + if (peern->ttl != 0) { if (strlen(addr->address) > 8 && !memcmp(addr->address, "127.127.", 8)) - fprintf(df, " mode %d", peer->ttl); + fprintf(df, " mode %u", peern->ttl); else - fprintf(df, " ttl %d", peer->ttl); + fprintf(df, " ttl %u", peern->ttl); } - if (peer->peerversion != NTP_VERSION) - fprintf(df, " version %d", peer->peerversion); + if (peern->peerversion != NTP_VERSION) + fprintf(df, " version %u", peern->peerversion); - if (peer->peerkey != 0) - fprintf(df, " key %d", peer->peerkey); + if (peern->peerkey != 0) + fprintf(df, " key %u", peern->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); + if (peern->group != NULL) + fprintf(df, " ident \"%s\"", peern->group); + atrv = HEAD_PFIFO(peern->peerflags); + for ( ; atrv != NULL; atrv = atrv->link) { + INSIST(T_Flag == atrv->attr); + 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; + addr_opts = HEAD_PFIFO(ptree->fudge); + for ( ; addr_opts != NULL; addr_opts = addr_opts->link) { + peer_addr = peern->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; - - /* 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; - } + if (strcmp(s1, s2)) + continue; + + fprintf(df, "fudge %s", s1); + + for (atrv = HEAD_PFIFO(addr_opts->options); + atrv != NULL; + atrv = atrv->link) { + + switch (atrv->type) { +#ifdef DEBUG + default: + fprintf(df, "\n# dump error:\n" + "# unknown fudge atrv->type %d\n" + "fudge %s", atrv->type, + s1); + break; +#endif + case T_Double: + fprintf(df, " %s %s", + keyword(atrv->attr), + normal_dtoa(atrv->value.d)); + break; + + case T_Integer: + fprintf(df, " %s %d", + keyword(atrv->attr), + atrv->value.i); + break; + + case T_String: + fprintf(df, " %s %s", + keyword(atrv->attr), + atrv->value.s); + break; } - fprintf(df, "\n"); } + fprintf(df, "\n"); } } - 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)) + addr = HEAD_PFIFO(ptree->manycastserver); + if (addr != NULL) { + fprintf(df, "manycastserver"); + for ( ; addr != NULL; addr = addr->link) fprintf(df, " %s", addr->address); fprintf(df, "\n"); } - 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)) + addr = HEAD_PFIFO(ptree->multicastclient); + if (addr != NULL) { + fprintf(df, "multicastclient"); + for ( ; addr != NULL; addr = addr->link) fprintf(df, " %s", addr->address); fprintf(df, "\n"); } - 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); - } - - list_ptr = queue_head(ptree->discard_opts); - if (list_ptr != NULL) { - - fprintf(df, "discard"); - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { + for (unpeern = HEAD_PFIFO(ptree->unpeers); + unpeern != NULL; + unpeern = unpeern->link) + fprintf(df, "unpeer %s\n", unpeern->addr->address); - atrv = list_ptr; + atrv = HEAD_PFIFO(ptree->mru_opts); + if (atrv != NULL) { + fprintf(df, "mru"); + for ( ; atrv != NULL; atrv = atrv->link) 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)) { + atrv = HEAD_PFIFO(ptree->discard_opts); + if (atrv != NULL) { + fprintf(df, "discard"); + for ( ; atrv != NULL; atrv = atrv->link) + fprintf(df, " %s %d", keyword(atrv->attr), + atrv->value.i); + fprintf(df, "\n"); + } - rest_node = list_ptr; - if (NULL == rest_node->addr) - s1 = "default"; - else - s1 = rest_node->addr->address; - fprintf(df, "restrict %s", s1); + for (rest_node = HEAD_PFIFO(ptree->restrict_opts); + rest_node != NULL; + rest_node = rest_node->link) { + if (NULL == rest_node->addr) { + s = "default"; + flags = HEAD_PFIFO(rest_node->flags); + for ( ; flags != NULL; flags = flags->link) + if (T_Source == flags->i) { + s = "source"; + break; + } + } else { + s = rest_node->addr->address; + } + fprintf(df, "restrict %s", s); 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)); - + flags = HEAD_PFIFO(rest_node->flags); + for ( ; flags != NULL; flags = flags->link) + if (T_Source != flags->i) + fprintf(df, " %s", keyword(flags->i)); fprintf(df, "\n"); } - list_ptr = queue_head(ptree->nic_rules); - for (; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - rule_node = list_ptr; + rule_node = HEAD_PFIFO(ptree->nic_rules); + for ( ; rule_node != NULL; rule_node = rule_node->link) { fprintf(df, "interface %s %s\n", keyword(rule_node->action), (rule_node->match_class) @@ -1010,253 +910,259 @@ dump_config_tree( : rule_node->if_name); } - list_ptr = queue_head(ptree->phone); - if (list_ptr != NULL) { - + str_node = HEAD_PFIFO(ptree->phone); + if (str_node != 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); - } - + for ( ; str_node != NULL; str_node = str_node->link) + fprintf(df, " \"%s\"", str_node->s); fprintf(df, "\n"); } - list_ptr = queue_head(ptree->setvar); - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - setv_node = list_ptr; + setv_node = HEAD_PFIFO(ptree->setvar); + for ( ; setv_node != NULL; setv_node = setv_node->link) { 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) { - + i_n = HEAD_PFIFO(ptree->ttl); + if (i_n != NULL) { fprintf(df, "ttl"); - - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - - intp = list_ptr; - fprintf(df, " %d", *intp); - } - + for( ; i_n != NULL; i_n = i_n->link) + fprintf(df, " %d", i_n->i); fprintf(df, "\n"); } - - list_ptr = queue_head(ptree->trap); - for(; list_ptr != NULL; - list_ptr = next_node(list_ptr)) { - addr_opts = list_ptr; + addr_opts = HEAD_PFIFO(ptree->trap); + for ( ; addr_opts != NULL; addr_opts = addr_opts->link) { 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; - + atrv = HEAD_PFIFO(addr_opts->options); + for ( ; atrv != NULL; atrv = atrv->link) { switch (atrv->attr) { - +#ifdef DEBUG default: fprintf(df, "\n# dump error:\n" "# unknown trap token %d\n" "trap %s", atrv->attr, addr->address); break; - +#endif 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); + fprintf(df, " interface %s", + atrv->value.s); break; } } + fprintf(df, "\n"); + } + counter_set = HEAD_PFIFO(ptree->reset_counters); + if (counter_set != NULL) { + fprintf(df, "reset"); + for ( ; counter_set != NULL; + counter_set = counter_set->link) + fprintf(df, " %s", keyword(counter_set->i)); fprintf(df, "\n"); } return 0; } #endif /* SAVECONFIG */ - -/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE - * ----------------------------------------------- - */ -queue * -enqueue_in_new_queue( - void *my_node + +/* generic fifo routines for structs linked by 1st member */ +void * +append_gen_fifo( + void *fifo, + void *entry + ) +{ + gen_fifo *pf; + gen_node *pe; + + pf = fifo; + pe = entry; + if (NULL == pf) + pf = emalloc_zero(sizeof(*pf)); + else + CHECK_FIFO_CONSISTENCY(*pf); + if (pe != NULL) + LINK_FIFO(*pf, pe, link); + CHECK_FIFO_CONSISTENCY(*pf); + + return pf; +} + + +void * +concat_gen_fifos( + void *first, + void *second ) { - queue *my_queue = create_queue(); + gen_fifo *pf1; + gen_fifo *pf2; + + pf1 = first; + pf2 = second; + if (NULL == pf1) + return pf2; + if (NULL == pf2) + return pf1; - enqueue(my_queue, my_node); - return my_queue; + CONCAT_FIFO(*pf1, *pf2, link); + free(pf2); + + return pf1; } -struct attr_val * + +/* FUNCTIONS FOR CREATING NODES ON THE SYNTAX TREE + * ----------------------------------------------- + */ + +attr_val * create_attr_dval( int attr, double value ) { - struct attr_val *my_val; + attr_val *my_val; - my_val = get_node(sizeof *my_val); + my_val = emalloc_zero(sizeof(*my_val)); my_val->attr = attr; my_val->value.d = value; my_val->type = T_Double; + return my_val; } -struct attr_val * + +attr_val * create_attr_ival( int attr, int value ) { - struct attr_val *my_val; + attr_val *my_val; - my_val = get_node(sizeof *my_val); + my_val = emalloc_zero(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 + +attr_val * +create_attr_uval( + int attr, + u_int value ) { - struct attr_val *my_val; + attr_val *my_val; - my_val = get_node(sizeof *my_val); + my_val = emalloc_zero(sizeof(*my_val)); my_val->attr = attr; - my_val->value.u = (val1 << 16) | val2; - my_val->type = T_Integer; + my_val->value.u = value; + my_val->type = T_U_int; + return my_val; } -struct attr_val * -create_attr_sval( - int attr, - char *s + +attr_val * +create_attr_rangeval( + int attr, + int first, + int last ) { - struct attr_val *my_val; + attr_val *my_val; - my_val = get_node(sizeof *my_val); + my_val = emalloc_zero(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; + my_val->value.r.first = first; + my_val->value.r.last = last; + my_val->type = T_Intrange; + return my_val; } -struct attr_val * -create_attr_pval( + +attr_val * +create_attr_sval( int attr, - void *p + char *s ) { - struct attr_val *my_val; + attr_val *my_val; - my_val = get_node(sizeof *my_val); + my_val = emalloc_zero(sizeof(*my_val)); my_val->attr = attr; - my_val->value.p = p; - my_val->type = T_Void; + if (NULL == s) /* free() hates NULL */ + s = estrdup(""); + my_val->value.s = s; + my_val->type = T_String; + return my_val; } -int * -create_ival( + +int_node * +create_int_node( int val ) { - int *p = get_node(sizeof *p); - - *p = val; - return p; -} + int_node *i_n; -double * -create_dval( - double val - ) -{ - double *p = get_node(sizeof *p); + i_n = emalloc_zero(sizeof(*i_n)); + i_n->i = val; - *p = val; - return p; + return i_n; } -void ** -create_pval( - void *val + +string_node * +create_string_node( + char *str ) { - void **p = get_node(sizeof *p); + string_node *sn; - *p = val; - return p; + sn = emalloc_zero(sizeof(*sn)); + sn->s = str; + + return sn; } -struct address_node * + +address_node * create_address_node( - char *addr, - int type + char * addr, + int type ) { - struct address_node *my_node; + address_node *my_node; NTP_REQUIRE(NULL != addr); - - my_node = get_node(sizeof *my_node); - + NTP_REQUIRE(AF_INET == type || + AF_INET6 == type || AF_UNSPEC == type); + my_node = emalloc_zero(sizeof(*my_node)); my_node->address = addr; - my_node->type = type; + my_node->type = (u_short)type; return my_node; } @@ -1264,139 +1170,158 @@ create_address_node( void destroy_address_node( - struct address_node *my_node + address_node *my_node ) { - NTP_REQUIRE(NULL != my_node); + if (NULL == my_node) + return; NTP_REQUIRE(NULL != my_node->address); free(my_node->address); - free_node(my_node); + free(my_node); } -struct peer_node * +peer_node * create_peer_node( - int hmode, - struct address_node *addr, - queue *options + int hmode, + address_node * addr, + attr_val_fifo * options ) { - struct peer_node *my_node; - struct attr_val *option; + peer_node *my_node; + attr_val *option; int freenode; int errflag = 0; - my_node = get_node(sizeof(*my_node)); + my_node = emalloc_zero(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 + * the options FIFO 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. + * those that are moved intact to the peer_node's peerflags + * FIFO. The options FIFO is consumed and reclaimed here. */ - while (options && NULL != (option = dequeue(options))) { + if (options != NULL) + CHECK_FIFO_CONSISTENCY(*options); + while (options != NULL) { + UNLINK_FIFO(option, *options, link); + if (NULL == option) { + free(options); + break; + } freenode = 1; /* Check the kind of option being set */ switch (option->attr) { case T_Flag: - enqueue(my_node->peerflags, option); + APPEND_G_FIFO(my_node->peerflags, option); freenode = 0; break; case T_Minpoll: - if (option->value.i < NTP_MINPOLL) { + if (option->value.i < NTP_MINPOLL || + option->value.i > UCHAR_MAX) { msyslog(LOG_INFO, - "minpoll: provided value (%d) is below minimum (%d)", - option->value.i, NTP_MINPOLL); + "minpoll: provided value (%d) is out of range [%d-%d])", + option->value.i, NTP_MINPOLL, + UCHAR_MAX); my_node->minpoll = NTP_MINPOLL; + } else { + my_node->minpoll = + (u_char)option->value.u; } - else - my_node->minpoll = option->value.i; break; case T_Maxpoll: - if (option->value.i > NTP_MAXPOLL) { + if (option->value.i < 0 || + option->value.i > NTP_MAXPOLL) { msyslog(LOG_INFO, - "maxpoll: provided value (%d) is above maximum (%d)", + "maxpoll: provided value (%d) is out of range [0-%d])", option->value.i, NTP_MAXPOLL); my_node->maxpoll = NTP_MAXPOLL; + } else { + my_node->maxpoll = + (u_char)option->value.u; } - else - my_node->maxpoll = option->value.i; break; case T_Ttl: - if (my_node->ttl >= MAX_TTL) { + if (option->value.u >= MAX_TTL) { msyslog(LOG_ERR, "ttl: invalid argument"); errflag = 1; + } else { + my_node->ttl = (u_char)option->value.u; } - else - my_node->ttl = option->value.i; break; case T_Mode: - my_node->ttl = option->value.i; + my_node->ttl = option->value.u; break; case T_Key: - my_node->peerkey = option->value.i; + if (option->value.u >= KEYID_T_MAX) { + msyslog(LOG_ERR, "key: invalid argument"); + errflag = 1; + } else { + my_node->peerkey = + (keyid_t)option->value.u; + } break; case T_Version: - my_node->peerversion = option->value.i; + if (option->value.u >= UCHAR_MAX) { + msyslog(LOG_ERR, "version: invalid argument"); + errflag = 1; + } else { + my_node->peerversion = + (u_char)option->value.u; + } break; - case T_Bias: - my_node->bias = option->value.d; + case T_Ident: + my_node->group = option->value.s; break; default: - msyslog(LOG_ERR, + msyslog(LOG_ERR, "Unknown peer/server option token %s", token_name(option->attr)); errflag = 1; } if (freenode) - free_node(option); + free(option); } - DESTROY_QUEUE(options); /* Check if errors were reported. If yes, ignore the node */ if (errflag) { - free_node(my_node); + free(my_node); my_node = NULL; } + return my_node; } -struct unpeer_node * +unpeer_node * create_unpeer_node( - struct address_node *addr + address_node *addr ) { - struct unpeer_node * my_node; - char * pch; + unpeer_node * my_node; + u_int u; + char * pch; - my_node = get_node(sizeof(*my_node)); + my_node = emalloc_zero(sizeof(*my_node)); /* * From the parser's perspective an association ID fits into @@ -1407,10 +1332,10 @@ create_unpeer_node( while (*pch && isdigit(*pch)) pch++; - if (!*pch - && 1 == sscanf(addr->address, "%u", &my_node->assocID) - && my_node->assocID <= USHRT_MAX) { - + if (!*pch + && 1 == sscanf(addr->address, "%u", &u) + && u <= ASSOCID_MAX) { + my_node->assocID = (associd_t)u; destroy_address_node(addr); my_node->addr = NULL; } else { @@ -1421,15 +1346,15 @@ create_unpeer_node( return my_node; } -struct filegen_node * +filegen_node * create_filegen_node( - int filegen_token, - queue * options + int filegen_token, + attr_val_fifo * options ) { - struct filegen_node *my_node; - - my_node = get_node(sizeof *my_node); + filegen_node *my_node; + + my_node = emalloc_zero(sizeof(*my_node)); my_node->filegen_token = filegen_token; my_node->options = options; @@ -1437,18 +1362,17 @@ create_filegen_node( } -struct restrict_node * +restrict_node * create_restrict_node( - struct address_node *addr, - struct address_node *mask, - queue *flags, - int line_no + address_node * addr, + address_node * mask, + int_fifo * flags, + int line_no ) { - struct restrict_node *my_node; - - my_node = get_node(sizeof *my_node); + restrict_node *my_node; + my_node = emalloc_zero(sizeof(*my_node)); my_node->addr = addr; my_node->mask = mask; my_node->flags = flags; @@ -1457,39 +1381,180 @@ create_restrict_node( return my_node; } -void + +static void destroy_restrict_node( - struct restrict_node *my_node + 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); + destroy_address_node(my_node->addr); + destroy_address_node(my_node->mask); + destroy_int_fifo(my_node->flags); + free(my_node); +} + + +static void +destroy_int_fifo( + int_fifo * fifo + ) +{ + int_node * i_n; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(i_n, *fifo, link); + if (i_n == NULL) + break; + free(i_n); + } + free(fifo); + } +} + + +static void +destroy_string_fifo( + string_fifo * fifo + ) +{ + string_node * sn; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(sn, *fifo, link); + if (sn == NULL) + break; + free(sn->s); + free(sn); + } + free(fifo); + } +} + + +static void +destroy_attr_val_fifo( + attr_val_fifo * av_fifo + ) +{ + attr_val * av; + + if (av_fifo != NULL) { + for (;;) { + UNLINK_FIFO(av, *av_fifo, link); + if (av == NULL) + break; + if (T_String == av->type) + free(av->value.s); + free(av); + } + free(av_fifo); + } } -struct setvar_node * +static void +destroy_filegen_fifo( + filegen_fifo * fifo + ) +{ + filegen_node * fg; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(fg, *fifo, link); + if (fg == NULL) + break; + destroy_attr_val_fifo(fg->options); + free(fg); + } + free(fifo); + } +} + + +static void +destroy_restrict_fifo( + restrict_fifo * fifo + ) +{ + restrict_node * rn; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(rn, *fifo, link); + if (rn == NULL) + break; + destroy_restrict_node(rn); + } + free(fifo); + } +} + + +static void +destroy_setvar_fifo( + setvar_fifo * fifo + ) +{ + setvar_node * sv; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(sv, *fifo, link); + if (sv == NULL) + break; + free(sv->var); + free(sv->val); + free(sv); + } + free(fifo); + } +} + + +static void +destroy_addr_opts_fifo( + addr_opts_fifo * fifo + ) +{ + addr_opts_node * aon; + + if (fifo != NULL) { + for (;;) { + UNLINK_FIFO(aon, *fifo, link); + if (aon == NULL) + break; + destroy_address_node(aon->addr); + destroy_attr_val_fifo(aon->options); + free(aon); + } + free(fifo); + } +} + + +setvar_node * create_setvar_node( char * var, char * val, int isdefault ) { - char * pch; - struct setvar_node *my_node; + setvar_node * my_node; + char * pch; /* do not allow = in the variable name */ - if (NULL != (pch = strchr(var, '='))) + pch = strchr(var, '='); + if (NULL != pch) *pch = '\0'; /* Now store the string into a setvar_node */ - my_node = get_node(sizeof *my_node); + my_node = emalloc_zero(sizeof(*my_node)); my_node->var = var; my_node->val = val; my_node->isdefault = isdefault; @@ -1506,10 +1571,10 @@ create_nic_rule_node( ) { nic_rule_node *my_node; - + NTP_REQUIRE(match_class != 0 || if_name != NULL); - my_node = get_node(sizeof(*my_node)); + my_node = emalloc_zero(sizeof(*my_node)); my_node->match_class = match_class; my_node->if_name = if_name; my_node->action = action; @@ -1518,45 +1583,45 @@ create_nic_rule_node( } -struct addr_opts_node * +addr_opts_node * create_addr_opts_node( - struct address_node *addr, - queue *options + address_node * addr, + attr_val_fifo * options ) { - struct addr_opts_node *my_node; + addr_opts_node *my_node; - my_node = get_node(sizeof *my_node); + my_node = emalloc_zero(sizeof(*my_node)); my_node->addr = addr; my_node->options = options; + return my_node; } + +#ifdef SIM script_info * create_sim_script_info( - double duration, - queue *script_queue + double duration, + attr_val_fifo * script_queue ) { -#ifdef SIM - return NULL; -#else script_info *my_info; - struct attr_val *my_attr_val; + attr_val *my_attr_val; - my_info = get_node(sizeof *my_info); + my_info = emalloc_zero(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) { + + for (my_attr_val = HEAD_PFIFO(script_queue); + my_attr_val != NULL; + my_attr_val = my_attr_val->link) { + /* Set the desired value */ switch (my_attr_val->attr) { @@ -1581,89 +1646,88 @@ create_sim_script_info( break; default: - msyslog(LOG_ERR, - "Unknown script token %d", + msyslog(LOG_ERR, "Unknown script token %d", my_attr_val->attr); } } - return (my_info); -#endif -} + return my_info; +} +#endif /* SIM */ -#if !defined(SIM) - -#define ADDR_LENGTH 16 + 1 +#ifdef SIM static sockaddr_u * get_next_address( - struct address_node *addr + address_node *addr ) { const char addr_prefix[] = "192.168.0."; - static int curr_addr_no = 1; + static int curr_addr_num = 1; +#define ADDR_LENGTH 16 + 1 /* room for 192.168.1.255 */ char addr_string[ADDR_LENGTH]; sockaddr_u *final_addr; struct addrinfo *ptr; - int retval; - - final_addr = emalloc(sizeof *final_addr); + int gai_err; - 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); + final_addr = emalloc(sizeof(*final_addr)); - 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)); + if (addr->type == T_String) { + snprintf(addr_string, sizeof(addr_string), "%s%d", + addr_prefix, curr_addr_num++); + printf("Selecting ip address %s for hostname %s\n", + addr_string, addr->address); + gai_err = getaddrinfo(addr_string, "ntp", NULL, &ptr); + } else { + gai_err = getaddrinfo(addr->address, "ntp", NULL, &ptr); } - else { + + if (gai_err) { fprintf(stderr, "ERROR!! Could not get a new address\n"); exit(1); } + 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)); freeaddrinfo(ptr); + return final_addr; } -#endif /* !SIM */ +#endif /* SIM */ +#ifdef SIM server_info * create_sim_server( - struct address_node *addr, - double server_offset, - queue *script + address_node * addr, + double server_offset, + script_info_fifo * script ) { -#ifdef SIM - return NULL; -#else server_info *my_info; - my_info = get_node(sizeof *my_info); - + my_info = emalloc_zero(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); + UNLINK_FIFO(my_info->curr_script, *my_info->script, link); + return my_info; -#endif /* SIM */ } +#endif /* SIM */ -struct sim_node * +sim_node * create_sim_node( - queue *init_opts, - queue *servers + attr_val_fifo * init_opts, + server_info_fifo * servers ) { - struct sim_node *my_node; - - my_node = get_node(sizeof *my_node); + sim_node *my_node; + my_node = emalloc(sizeof(*my_node)); my_node->init_opts = init_opts; my_node->servers = servers; + return my_node; } @@ -1674,93 +1738,106 @@ create_sim_node( * ------------------------------------------ */ +#ifndef SIM static void config_other_modes( - struct config_tree *ptree + config_tree * ptree ) { - sockaddr_u addr_sock; - struct address_node *addr_node; + sockaddr_u addr_sock; + 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; + proto_config(PROTO_BROADCLIENT, ptree->broadcastclient, + 0., NULL); - 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; + addr_node = HEAD_PFIFO(ptree->manycastserver); + while (addr_node != NULL) { + ZERO_SOCK(&addr_sock); + AF(&addr_sock) = addr_node->type; + if (1 == getnetnum(addr_node->address, &addr_sock, 1, + t_UNK)) { + proto_config(PROTO_MULTICAST_ADD, + 0, 0., &addr_sock); + sys_manycastserver = 1; + } + addr_node = addr_node->link; } /* Configure the multicast clients */ - addr_node = queue_head(ptree->multicastclient); + addr_node = HEAD_PFIFO(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); + AF(&addr_sock) = addr_node->type; + if (1 == getnetnum(addr_node->address, + &addr_sock, 1, t_UNK)) { + proto_config(PROTO_MULTICAST_ADD, 0, 0., + &addr_sock); + } + addr_node = addr_node->link; } while (addr_node != NULL); proto_config(PROTO_MULTICAST_ADD, 1, 0., NULL); } } +#endif /* !SIM */ #ifdef FREE_CFG_T static void -free_config_other_modes( - struct config_tree *ptree +destroy_address_fifo( + address_fifo * pfifo ) { - struct address_node *addr_node; + address_node * addr_node; + + if (pfifo != NULL) { + for (;;) { + UNLINK_FIFO(addr_node, *pfifo, link); + if (addr_node == NULL) + break; + destroy_address_node(addr_node); + } + free(pfifo); + } +} - while (NULL != (addr_node = dequeue(ptree->manycastserver))) - destroy_address_node(addr_node); - while (NULL != (addr_node = dequeue(ptree->multicastclient))) - destroy_address_node(addr_node); +static void +free_config_other_modes( + config_tree *ptree + ) +{ + FREE_ADDRESS_FIFO(ptree->manycastserver); + FREE_ADDRESS_FIFO(ptree->multicastclient); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_auth( - struct config_tree *ptree + 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 + attr_val * my_val; + int first; + int last; + int i; + int count; +#ifdef AUTOKEY int item; #endif /* Crypto Command */ -#ifdef OPENSSL +#ifdef AUTOKEY item = -1; /* quiet warning */ - my_val = queue_head(ptree->auth.crypto_cmd_list); - while (my_val != NULL) { + my_val = HEAD_PFIFO(ptree->auth.crypto_cmd_list); + for (; my_val != NULL; my_val = my_val->link) { switch (my_val->attr) { default: - NTP_INSIST(0); + INSIST(0); break; case T_Host: @@ -1779,18 +1856,13 @@ config_auth( item = CRYPTO_CONF_RAND; break; - case T_Sign: - item = CRYPTO_CONF_SIGN; - break; - case T_Digest: item = CRYPTO_CONF_NID; break; } crypto_config(item, my_val->value.s); - my_val = next_node(my_val); } -#endif /* OPENSSL */ +#endif /* AUTOKEY */ /* Keysdir Command */ if (ptree->auth.keysdir) { @@ -1807,12 +1879,35 @@ config_auth( ntp_signd_socket = estrdup(ptree->auth.ntp_signd_socket); } -#ifdef OPENSSL +#ifdef AUTOKEY if (ptree->auth.cryptosw && !cryptosw) { crypto_setup(); cryptosw = 1; } -#endif /* OPENSSL */ +#endif /* AUTOKEY */ + + /* + * Count the number of trusted keys to preallocate storage and + * size the hash table. + */ + count = 0; + my_val = HEAD_PFIFO(ptree->auth.trusted_key_list); + for (; my_val != NULL; my_val = my_val->link) { + if (T_Integer == my_val->type) { + first = my_val->value.i; + if (first > 1 && first <= NTP_MAXKEY) + count++; + } else { + REQUIRE(T_Intrange == my_val->type); + first = my_val->value.r.first; + last = my_val->value.r.last; + if (!(first > last || first < 1 || + last > NTP_MAXKEY)) { + count += 1 + last - first; + } + } + } + auth_prealloc_symkeys(count); /* Keys Command */ if (ptree->auth.keys) @@ -1830,98 +1925,82 @@ config_auth( } /* 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); + my_val = HEAD_PFIFO(ptree->auth.trusted_key_list); + for (; my_val != NULL; my_val = my_val->link) { + if (T_Integer == my_val->type) { + first = my_val->value.i; + if (first >= 1 && first <= NTP_MAXKEY) { + authtrust(first, TRUE); + } else { + msyslog(LOG_NOTICE, + "Ignoring invalid trustedkey %d, min 1 max %d.", + first, NTP_MAXKEY); + } + } else { + first = my_val->value.r.first; + last = my_val->value.r.last; + if (first > last || first < 1 || + last > NTP_MAXKEY) { + msyslog(LOG_NOTICE, + "Ignoring invalid trustedkey range %d ... %d, min 1 max %d.", + first, last, NTP_MAXKEY); + } else { + for (i = first; i <= last; i++) { + authtrust(i, TRUE); + } + } } } -#ifdef OPENSSL +#ifdef AUTOKEY /* crypto revoke command */ if (ptree->auth.revoke) - sys_revoke = ptree->auth.revoke; -#endif /* OPENSSL */ - -#ifndef NO_INTRES - /* find a keyid */ - if (info_auth_keyid == 0) - req_keyid = 65535; - else - req_keyid = info_auth_keyid; - - /* 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; - - 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); - } - - /* save keyid so we will accept config requests with it */ - info_auth_keyid = req_keyid; -#endif /* !NO_INTRES */ - + sys_revoke = 1UL << ptree->auth.revoke; +#endif /* AUTOKEY */ } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_auth( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *my_val; - - while (NULL != - (my_val = dequeue(ptree->auth.crypto_cmd_list))) { - - free(my_val->value.s); - free_node(my_val); - } - DESTROY_QUEUE(ptree->auth.crypto_cmd_list); - - DESTROY_QUEUE(ptree->auth.trusted_key_list); + destroy_attr_val_fifo(ptree->auth.crypto_cmd_list); + ptree->auth.crypto_cmd_list = NULL; + destroy_attr_val_fifo(ptree->auth.trusted_key_list); + ptree->auth.trusted_key_list = NULL; } #endif /* FREE_CFG_T */ static void config_tos( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *tos; - int item; + attr_val * tos; + int item; + double val; item = -1; /* quiet warning */ - tos = queue_head(ptree->orphan_cmds); - while (tos != NULL) { + tos = HEAD_PFIFO(ptree->orphan_cmds); + for (; tos != NULL; tos = tos->link) { + val = tos->value.d; switch(tos->attr) { default: - NTP_INSIST(0); + INSIST(0); break; case T_Ceiling: + if (val > STRATUM_UNSPEC - 1) { + msyslog(LOG_WARNING, + "Using maximum tos ceiling %d, %g requested", + STRATUM_UNSPEC - 1, val); + val = STRATUM_UNSPEC - 1; + } item = PROTO_CEILING; break; @@ -1937,6 +2016,10 @@ config_tos( item = PROTO_ORPHAN; break; + case T_Orphanwait: + item = PROTO_ORPHWAIT; + break; + case T_Mindist: item = PROTO_MINDISP; break; @@ -1961,8 +2044,7 @@ config_tos( item = PROTO_BEACON; break; } - proto_config(item, 0, tos->value.d, NULL); - tos = next_node(tos); + proto_config(item, 0, val, NULL); } } @@ -1970,30 +2052,25 @@ config_tos( #ifdef FREE_CFG_T static void free_config_tos( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *tos; - - while (!empty(ptree->orphan_cmds)) { - tos = dequeue(ptree->orphan_cmds); - free_node(tos); - } + FREE_ATTR_VAL_FIFO(ptree->orphan_cmds); } #endif /* FREE_CFG_T */ static void config_monitor( - struct config_tree *ptree + config_tree *ptree ) { - int *pfilegen_token; + int_node *pfilegen_token; const char *filegen_string; const char *filegen_file; FILEGEN *filegen; - struct filegen_node *my_node; - struct attr_val *my_opts; + filegen_node *my_node; + attr_val *my_opts; int filegen_type; int filegen_flag; @@ -2015,45 +2092,58 @@ config_monitor( */ /* Turn on the specified statistics */ - pfilegen_token = queue_head(ptree->stats_list); - while (pfilegen_token != NULL) { - filegen_string = keyword(*pfilegen_token); + pfilegen_token = HEAD_PFIFO(ptree->stats_list); + for (; pfilegen_token != NULL; pfilegen_token = pfilegen_token->link) { + filegen_string = keyword(pfilegen_token->i); filegen = filegen_get(filegen_string); - + if (NULL == filegen) { + msyslog(LOG_ERR, + "stats %s unrecognized", + filegen_string); + continue; + } 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); + filegen_string, filegen->dir, + filegen->fname)); + filegen_flag = filegen->flag; + filegen_flag |= FGEN_FLAG_ENABLED; + filegen_config(filegen, statsdir, filegen_string, + filegen->type, filegen_flag); } /* 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); + my_node = HEAD_PFIFO(ptree->filegen_opts); + for (; my_node != NULL; my_node = my_node->link) { + filegen_string = keyword(my_node->filegen_token); + filegen = filegen_get(filegen_string); + if (NULL == filegen) { + msyslog(LOG_ERR, + "filegen category '%s' unrecognized", + filegen_string); + continue; + } + filegen_file = filegen_string; - /* Initialize the filegen variables to their pre-configurtion states */ + /* Initialize the filegen variables to their pre-configuration 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) { - + my_opts = HEAD_PFIFO(my_node->options); + for (; my_opts != NULL; my_opts = my_opts->link) { switch (my_opts->attr) { case T_File: - filegen_file = my_opts->value.p; + filegen_file = my_opts->value.s; break; case T_Type: switch (my_opts->value.i) { default: - NTP_INSIST(0); + INSIST(0); break; case T_None: @@ -2106,23 +2196,22 @@ config_monitor( break; default: - msyslog(LOG_ERR, + 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); + filegen_config(filegen, statsdir, filegen_file, + filegen_type, filegen_flag); } } @@ -2130,46 +2219,40 @@ config_monitor( #ifdef FREE_CFG_T static void free_config_monitor( - struct config_tree *ptree + 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); - } + FREE_INT_FIFO(ptree->stats_list); + FREE_FILEGEN_FIFO(ptree->filegen_opts); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_access( - struct config_tree *ptree + 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; + attr_val * my_opt; + restrict_node * my_node; + int_node * curr_flag; + sockaddr_u addr; + sockaddr_u mask; + struct addrinfo hints; + struct addrinfo * ai_list; + struct addrinfo * pai; + int rc; + int restrict_default; u_short flags; u_short mflags; - int restrict_default; + int range_err; const char * signd_warning = #ifdef HAVE_NTP_SIGND "MS-SNTP signd operations currently block ntpd degrading service to all clients."; @@ -2177,95 +2260,139 @@ config_access( "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) { + /* Configure the mru options */ + my_opt = HEAD_PFIFO(ptree->mru_opts); + for (; my_opt != NULL; my_opt = my_opt->link) { - switch(my_opt->attr) { + range_err = FALSE; - case T_Average: - ntp_minpoll = my_opt->value.i; + switch (my_opt->attr) { + + case T_Incalloc: + if (0 <= my_opt->value.i) + mru_incalloc = my_opt->value.u; + else + range_err = TRUE; break; - case T_Minimum: - ntp_minpkt = my_opt->value.i; + case T_Incmem: + if (0 <= my_opt->value.i) + mru_incalloc = (my_opt->value.u * 1024U) + / sizeof(mon_entry); + else + range_err = TRUE; break; - case T_Monitor: - mon_age = my_opt->value.i; + case T_Initalloc: + if (0 <= my_opt->value.i) + mru_initalloc = my_opt->value.u; + else + range_err = TRUE; + break; + + case T_Initmem: + if (0 <= my_opt->value.i) + mru_initalloc = (my_opt->value.u * 1024U) + / sizeof(mon_entry); + else + range_err = TRUE; + break; + + case T_Mindepth: + if (0 <= my_opt->value.i) + mru_mindepth = my_opt->value.u; + else + range_err = TRUE; + break; + + case T_Maxage: + mru_maxage = my_opt->value.i; + break; + + case T_Maxdepth: + if (0 <= my_opt->value.i) + mru_maxdepth = my_opt->value.u; + else + mru_maxdepth = UINT_MAX; + break; + + case T_Maxmem: + if (0 <= my_opt->value.i) + mru_maxdepth = (my_opt->value.u * 1024U) / + sizeof(mon_entry); + else + mru_maxdepth = UINT_MAX; break; default: msyslog(LOG_ERR, - "Unknown discard option token %d", - my_opt->attr); + "Unknown mru option %s (%d)", + keyword(my_opt->attr), my_opt->attr); exit(1); } - my_opt = next_node(my_opt); + if (range_err) + msyslog(LOG_ERR, + "mru %s %d out of range, ignored.", + keyword(my_opt->attr), my_opt->value.i); } - /* 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; + /* Configure the discard options */ + my_opt = HEAD_PFIFO(ptree->discard_opts); + for (; my_opt != NULL; my_opt = my_opt->link) { - if (getnetnum(my_node->addr->address, - &addr_sock, 1, t_UNK) != 1) { + switch (my_opt->attr) { + case T_Average: + if (0 <= my_opt->value.i && + my_opt->value.i <= UCHAR_MAX) + ntp_minpoll = (u_char)my_opt->value.u; + else msyslog(LOG_ERR, - "restrict: error in address '%s' on line %d. Ignoring...", - my_node->addr->address, my_node->line_no); - continue; - } + "discard average %d out of range, ignored.", + my_opt->value.i); + break; - SET_HOSTMASK(&addr_mask, AF(&addr_sock)); + case T_Minimum: + ntp_minpkt = my_opt->value.i; + break; - /* 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) { + case T_Monitor: + mon_age = my_opt->value.i; + break; - msyslog(LOG_ERR, - "restrict: error in mask '%s' on line %d. Ignoring...", - my_node->mask->address, my_node->line_no); - continue; - } - } + default: + msyslog(LOG_ERR, + "Unknown discard option %s (%d)", + keyword(my_opt->attr), my_opt->attr); + exit(1); } + } + /* Configure the restrict options */ + my_node = HEAD_PFIFO(ptree->restrict_opts); + for (; my_node != NULL; my_node = my_node->link) { /* Parse the flags */ flags = 0; mflags = 0; - curr_flag = queue_head(my_node->flags); - while (curr_flag != NULL) { - switch (*curr_flag) { + curr_flag = HEAD_PFIFO(my_node->flags); + for (; curr_flag != NULL; curr_flag = curr_flag->link) { + switch (curr_flag->i) { default: - NTP_INSIST(0); + INSIST(0); break; case T_Ntpport: mflags |= RESM_NTPONLY; break; + case T_Source: + mflags |= RESM_SOURCE; + break; + case T_Flake: - flags |= RES_TIMEOUT; + flags |= RES_FLAKE; break; case T_Ignore: @@ -2292,6 +2419,10 @@ config_access( flags |= RES_NOMODIFY; break; + case T_Nomrulist: + flags |= RES_NOMRULIST; + break; + case T_Nopeer: flags |= RES_NOPEER; break; @@ -2316,68 +2447,233 @@ config_access( 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); + if ((RES_MSSNTP & flags) && !warned_signd) { + warned_signd = 1; + fprintf(stderr, "%s\n", signd_warning); + msyslog(LOG_WARNING, "%s", signd_warning); + } - AF(&addr_sock) = AF_INET6; + /* It would be swell if we could identify the line number */ + if ((RES_KOD & flags) && !(RES_LIMITED & flags)) { + char *kod_where = (my_node->addr) + ? my_node->addr->address + : (mflags & RESM_SOURCE) + ? "source" + : "default"; + char *kod_warn = "KOD does nothing without LIMITED."; + + fprintf(stderr, "restrict %s: %s\n", kod_where, kod_warn); + msyslog(LOG_WARNING, "restrict %s: %s", kod_where, kod_warn); } - hack_restrict(RESTRICT_FLAGS, &addr_sock, &addr_mask, - mflags, flags); + ZERO_SOCK(&addr); + ai_list = NULL; + pai = NULL; + restrict_default = 0; - if ((RES_MSSNTP & flags) && !warned_signd) { - warned_signd = 1; - fprintf(stderr, "%s\n", signd_warning); - msyslog(LOG_WARNING, signd_warning); + if (NULL == my_node->addr) { + ZERO_SOCK(&mask); + if (!(RESM_SOURCE & mflags)) { + /* + * The user specified a default rule + * without a -4 / -6 qualifier, add to + * both lists + */ + restrict_default = 1; + } else { + /* apply "restrict source ..." */ + DPRINTF(1, ("restrict source template mflags %x flags %x\n", + mflags, flags)); + hack_restrict(RESTRICT_FLAGS, NULL, + NULL, mflags, flags, 0); + continue; + } + } else { + /* Resolve the specified address */ + AF(&addr) = (u_short)my_node->addr->type; + + if (getnetnum(my_node->addr->address, + &addr, 1, t_UNK) != 1) { + /* + * Attempt a blocking lookup. This + * is in violation of the nonblocking + * design of ntpd's mainline code. The + * alternative of running without the + * restriction until the name resolved + * seems worse. + * Ideally some scheme could be used for + * restrict directives in the startup + * ntp.conf to delay starting up the + * protocol machinery until after all + * restrict hosts have been resolved. + */ + ai_list = NULL; + ZERO(hints); + hints.ai_protocol = IPPROTO_UDP; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = my_node->addr->type; + rc = getaddrinfo(my_node->addr->address, + "ntp", &hints, + &ai_list); + if (rc) { + msyslog(LOG_ERR, + "restrict: ignoring line %d, address/host '%s' unusable.", + my_node->line_no, + my_node->addr->address); + continue; + } + INSIST(ai_list != NULL); + pai = ai_list; + INSIST(pai->ai_addr != NULL); + INSIST(sizeof(addr) >= + pai->ai_addrlen); + memcpy(&addr, pai->ai_addr, + pai->ai_addrlen); + INSIST(AF_INET == AF(&addr) || + AF_INET6 == AF(&addr)); + } + + SET_HOSTMASK(&mask, AF(&addr)); + + /* Resolve the mask */ + if (my_node->mask) { + ZERO_SOCK(&mask); + AF(&mask) = my_node->mask->type; + if (getnetnum(my_node->mask->address, + &mask, 1, t_MSK) != 1) { + msyslog(LOG_ERR, + "restrict: ignoring line %d, mask '%s' unusable.", + my_node->line_no, + my_node->mask->address); + continue; + } + } } + + /* Set the flags */ + if (restrict_default) { + AF(&addr) = AF_INET; + AF(&mask) = AF_INET; + hack_restrict(RESTRICT_FLAGS, &addr, + &mask, mflags, flags, 0); + AF(&addr) = AF_INET6; + AF(&mask) = AF_INET6; + } + + do { + hack_restrict(RESTRICT_FLAGS, &addr, + &mask, mflags, flags, 0); + if (pai != NULL && + NULL != (pai = pai->ai_next)) { + INSIST(pai->ai_addr != NULL); + INSIST(sizeof(addr) >= + pai->ai_addrlen); + ZERO_SOCK(&addr); + memcpy(&addr, pai->ai_addr, + pai->ai_addrlen); + INSIST(AF_INET == AF(&addr) || + AF_INET6 == AF(&addr)); + SET_HOSTMASK(&mask, AF(&addr)); + } + } while (pai != NULL); + + if (ai_list != NULL) + freeaddrinfo(ai_list); } } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_access( - struct config_tree *ptree + config_tree *ptree + ) +{ + FREE_ATTR_VAL_FIFO(ptree->mru_opts); + FREE_ATTR_VAL_FIFO(ptree->discard_opts); + FREE_RESTRICT_FIFO(ptree->restrict_opts); +} +#endif /* FREE_CFG_T */ + + +static void +config_rlimit( + config_tree *ptree ) { - struct attr_val * my_opt; - struct restrict_node * my_node; - int * curr_flag; + attr_val * rlimit_av; + + rlimit_av = HEAD_PFIFO(ptree->rlimit); + for (; rlimit_av != NULL; rlimit_av = rlimit_av->link) { + switch (rlimit_av->attr) { + + default: + INSIST(0); + break; + + case T_Memlock: + if (rlimit_av->value.i != 0) { +#if defined(RLIMIT_MEMLOCK) + ntp_rlimit(RLIMIT_MEMLOCK, + (rlim_t)(rlimit_av->value.i * 1024 * 1024), + 1024 * 1024, + "MB"); +#else + /* STDERR as well would be fine... */ + msyslog(LOG_WARNING, "'rlimit memlock' specified but is not available on this system."); +#endif /* RLIMIT_MEMLOCK */ + } else { + do_memlock = 0; + } + break; - while (NULL != (my_opt = dequeue(ptree->discard_opts))) - free_node(my_opt); + case T_Stacksize: +#if defined(RLIMIT_STACK) + ntp_rlimit(RLIMIT_STACK, + (rlim_t)(rlimit_av->value.i * 4096), + 4096, + "4k"); +#else + /* STDERR as well would be fine... */ + msyslog(LOG_WARNING, "'rlimit stacksize' specified but is not available on this system."); +#endif /* RLIMIT_STACK */ + break; - while (NULL != (my_node = dequeue(ptree->restrict_opts))) { - while (NULL != (curr_flag = dequeue(my_node->flags))) - free_node(curr_flag); + case T_Filenum: +#if defined(RLIMIT_NOFILE) + ntp_rlimit(RLIMIT_NOFILE, + (rlim_t)(rlimit_av->value.i), + 1, + ""); +#else + /* STDERR as well would be fine... */ + msyslog(LOG_WARNING, "'rlimit filenum' specified but is not available on this system."); +#endif /* RLIMIT_NOFILE */ + break; - destroy_restrict_node(my_node); + } } } -#endif /* FREE_CFG_T */ static void config_tinker( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *tinker; - int item; + attr_val * tinker; + int item; item = -1; /* quiet warning */ - tinker = queue_head(ptree->tinker); - while (tinker != NULL) { + tinker = HEAD_PFIFO(ptree->tinker); + for (; tinker != NULL; tinker = tinker->link) { switch (tinker->attr) { default: - NTP_INSIST(0); + INSIST(0); break; case T_Allan: @@ -2407,23 +2703,31 @@ config_tinker( case T_Stepout: item = LOOP_MINSTEP; break; + + case T_Tick: + item = LOOP_TICK; + break; } loop_config(item, tinker->value.d); - tinker = next_node(tinker); } } #ifdef FREE_CFG_T static void -free_config_tinker( - struct config_tree *ptree +free_config_rlimit( + config_tree *ptree ) { - struct attr_val *tinker; + FREE_ATTR_VAL_FIFO(ptree->rlimit); +} - while (NULL != (tinker = dequeue(ptree->tinker))) - free_node(tinker); +static void +free_config_tinker( + config_tree *ptree + ) +{ + FREE_ATTR_VAL_FIFO(ptree->tinker); } #endif /* FREE_CFG_T */ @@ -2431,9 +2735,10 @@ free_config_tinker( /* * config_nic_rules - apply interface listen/ignore/drop items */ -void +#ifndef SIM +static void config_nic_rules( - struct config_tree *ptree + config_tree *ptree ) { nic_rule_node * curr_node; @@ -2445,7 +2750,7 @@ config_nic_rules( int prefixlen; int addrbits; - curr_node = queue_head(ptree->nic_rules); + curr_node = HEAD_PFIFO(ptree->nic_rules); if (curr_node != NULL && (HAVE_OPT( NOVIRTUALIPS ) || HAVE_OPT( INTERFACE ))) { @@ -2458,10 +2763,7 @@ config_nic_rules( return; } - for (; - curr_node != NULL; - curr_node = next_node(curr_node)) { - + for (; curr_node != NULL; curr_node = curr_node->link) { prefixlen = -1; if_name = curr_node->if_name; if (if_name != NULL) @@ -2476,7 +2778,7 @@ config_nic_rules( * other reason. */ match_type = MATCH_ALL; - NTP_INSIST(0); + INSIST(FALSE); break; case 0: @@ -2486,15 +2788,15 @@ config_nic_rules( * interface descriptor is either a name or * address, stored in if_name in either case. */ - NTP_INSIST(if_name != NULL); + INSIST(if_name != NULL); pchSlash = strchr(if_name, '/'); if (pchSlash != NULL) *pchSlash = '\0'; - if (is_ip_address(if_name, &addr)) { + if (is_ip_address(if_name, AF_UNSPEC, &addr)) { match_type = MATCH_IFADDR; - if (pchSlash != NULL) { - sscanf(pchSlash + 1, "%d", - &prefixlen); + if (pchSlash != NULL + && 1 == sscanf(pchSlash + 1, "%d", + &prefixlen)) { addrbits = 8 * SIZEOF_INADDR(AF(&addr)); prefixlen = max(-1, prefixlen); @@ -2534,7 +2836,7 @@ config_nic_rules( * other reason. */ action = ACTION_LISTEN; - NTP_INSIST(0); + INSIST(FALSE); break; case T_Listen: @@ -2557,41 +2859,47 @@ config_nic_rules( free(if_name); } } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_nic_rules( - struct config_tree *ptree + config_tree *ptree ) { nic_rule_node *curr_node; - while (NULL != (curr_node = dequeue(ptree->nic_rules))) { - if (curr_node->if_name != NULL) + if (ptree->nic_rules != NULL) { + for (;;) { + UNLINK_FIFO(curr_node, *ptree->nic_rules, link); + if (NULL == curr_node) + break; free(curr_node->if_name); - free_node(curr_node); + free(curr_node); + } + free(ptree->nic_rules); + ptree->nic_rules = NULL; } - DESTROY_QUEUE(ptree->nic_rules); } #endif /* FREE_CFG_T */ static void apply_enable_disable( - queue * q, - int enable + attr_val_fifo * fifo, + int enable ) { - struct attr_val *curr_flag; + attr_val *curr_flag; int option; #ifdef BC_LIST_FRAMEWORK_NOT_YET_USED bc_entry *pentry; #endif - for (curr_flag = queue_head(q); + for (curr_flag = HEAD_PFIFO(fifo); curr_flag != NULL; - curr_flag = next_node(curr_flag)) { + curr_flag = curr_flag->link) { option = curr_flag->value.i; switch (option) { @@ -2626,6 +2934,10 @@ apply_enable_disable( proto_config(PROTO_NTP, enable, 0., NULL); break; + case T_Mode7: + proto_config(PROTO_MODE7, enable, 0., NULL); + break; + case T_Stats: proto_config(PROTO_FILEGEN, enable, 0., NULL); break; @@ -2639,7 +2951,7 @@ apply_enable_disable( pentry++; } if (!pentry->token) { - msyslog(LOG_ERR, + msyslog(LOG_ERR, "compat token %d not in bc_list[]", option); continue; @@ -2654,7 +2966,7 @@ apply_enable_disable( static void config_system_opts( - struct config_tree *ptree + config_tree *ptree ) { apply_enable_disable(ptree->enable_opts, 1); @@ -2665,42 +2977,41 @@ config_system_opts( #ifdef FREE_CFG_T static void free_config_system_opts( - struct config_tree *ptree + 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); + FREE_ATTR_VAL_FIFO(ptree->enable_opts); + FREE_ATTR_VAL_FIFO(ptree->disable_opts); } #endif /* FREE_CFG_T */ static void config_logconfig( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *my_logconfig; + attr_val * my_lc; - my_logconfig = queue_head(ptree->logconfig); - while (my_logconfig != NULL) { + my_lc = HEAD_PFIFO(ptree->logconfig); + for (; my_lc != NULL; my_lc = my_lc->link) { + switch (my_lc->attr) { - switch (my_logconfig->attr) { case '+': - ntp_syslogmask |= get_logmask(my_logconfig->value.s); + ntp_syslogmask |= get_logmask(my_lc->value.s); break; + case '-': - ntp_syslogmask &= ~get_logmask(my_logconfig->value.s); + ntp_syslogmask &= ~get_logmask(my_lc->value.s); break; + case '=': - ntp_syslogmask = get_logmask(my_logconfig->value.s); + ntp_syslogmask = get_logmask(my_lc->value.s); + break; + default: + INSIST(0); break; } - my_logconfig = next_node(my_logconfig); } } @@ -2708,143 +3019,64 @@ config_logconfig( #ifdef FREE_CFG_T static void free_config_logconfig( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *my_logconfig; - - while (NULL != (my_logconfig = dequeue(ptree->logconfig))) { - free(my_logconfig->value.s); - free_node(my_logconfig); - } + FREE_ATTR_VAL_FIFO(ptree->logconfig); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_phone( - struct config_tree *ptree + config_tree *ptree ) { - int i = 0; - char **s; + int i; + string_node * sn; - s = queue_head(ptree->phone); - while (s != NULL) { + i = 0; + sn = HEAD_PFIFO(ptree->phone); + for (; sn != NULL; sn = sn->link) { + /* need to leave array entry for NULL terminator */ if (i < COUNTOF(sys_phone) - 1) { - sys_phone[i++] = estrdup(*s); + sys_phone[i++] = estrdup(sn->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); + (u_long)(COUNTOF(sys_phone) - 1), sn->s); } - s = next_node(s); } } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_phone( - struct config_tree *ptree + 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 - - 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); - } + FREE_STRING_FIFO(ptree->phone); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_setvar( - struct config_tree *ptree + config_tree *ptree ) { - struct setvar_node *my_node; + setvar_node *my_node; size_t varlen, vallen, octets; char * str; str = NULL; - my_node = queue_head(ptree->setvar); - while (my_node != NULL) { + my_node = HEAD_PFIFO(ptree->setvar); + for (; my_node != NULL; my_node = my_node->link) { varlen = strlen(my_node->var); vallen = strlen(my_node->val); octets = varlen + vallen + 1 + 1; @@ -2852,112 +3084,104 @@ config_setvar( snprintf(str, octets, "%s=%s", my_node->var, my_node->val); set_sys_var(str, octets, (my_node->isdefault) - ? DEF + ? DEF : 0); - my_node = next_node(my_node); } if (str != NULL) free(str); } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_setvar( - struct config_tree *ptree + 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); - } + FREE_SETVAR_FIFO(ptree->setvar); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_ttl( - struct config_tree *ptree + config_tree *ptree ) { int i = 0; - int *curr_ttl; + int_node *curr_ttl; - curr_ttl = queue_head(ptree->ttl); - while (curr_ttl != NULL) { + curr_ttl = HEAD_PFIFO(ptree->ttl); + for (; curr_ttl != NULL; curr_ttl = curr_ttl->link) { if (i < COUNTOF(sys_ttl)) - sys_ttl[i++] = (u_char)*curr_ttl; + sys_ttl[i++] = (u_char)curr_ttl->i; 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); + (u_long)COUNTOF(sys_ttl), curr_ttl->i); } sys_ttlmax = i - 1; } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_ttl( - struct config_tree *ptree + config_tree *ptree ) { - /* coming DESTROY_QUEUE(ptree->ttl) is enough */ + FREE_INT_FIFO(ptree->ttl); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_trap( - struct config_tree *ptree + config_tree *ptree ) { - struct addr_opts_node *curr_trap; - struct attr_val *curr_opt; + addr_opts_node *curr_trap; + attr_val *curr_opt; sockaddr_u addr_sock; sockaddr_u peeraddr; - struct address_node *addr_node; struct interface *localaddr; - u_short port_no; + struct addrinfo hints; + char port_text[8]; + settrap_parms *pstp; + u_short port; int err_flag; + int rc; /* 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)) { - + curr_trap = HEAD_PFIFO(ptree->trap); + for (; curr_trap != NULL; curr_trap = curr_trap->link) { err_flag = 0; - port_no = 0; + port = 0; localaddr = NULL; - curr_opt = queue_head(curr_trap->options); - while (curr_opt != NULL) { + curr_opt = HEAD_PFIFO(curr_trap->options); + for (; curr_opt != NULL; curr_opt = curr_opt->link) { if (T_Port == curr_opt->attr) { - if (curr_opt->value.i < 1 + if (curr_opt->value.i < 1 || curr_opt->value.i > USHRT_MAX) { msyslog(LOG_ERR, "invalid port number " - "%d, trap ignored", + "%d, trap ignored", curr_opt->value.i); err_flag = 1; } - port_no = (u_short)curr_opt->value.i; + port = (u_short)curr_opt->value.i; } 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, + if (getnetnum(curr_opt->value.s, &addr_sock, 1, t_UNK) != 1) { err_flag = 1; break; @@ -2972,20 +3196,57 @@ config_trap( err_flag = 1; } } - curr_opt = next_node(curr_opt); } /* Now process the trap for the specified interface * and port number */ if (!err_flag) { + if (!port) + port = TRAPPORT; ZERO_SOCK(&peeraddr); - if (1 != getnetnum(curr_trap->addr->address, - &peeraddr, 1, t_UNK)) + rc = getnetnum(curr_trap->addr->address, + &peeraddr, 1, t_UNK); + if (1 != rc) { +#ifndef WORKER + msyslog(LOG_ERR, + "trap: unable to use IP address %s.", + curr_trap->addr->address); +#else /* WORKER follows */ + /* + * save context and hand it off + * for name resolution. + */ + ZERO(hints); + hints.ai_protocol = IPPROTO_UDP; + hints.ai_socktype = SOCK_DGRAM; + snprintf(port_text, sizeof(port_text), + "%u", port); + hints.ai_flags = Z_AI_NUMERICSERV; + pstp = emalloc_zero(sizeof(*pstp)); + if (localaddr != NULL) { + hints.ai_family = localaddr->family; + pstp->ifaddr_nonnull = 1; + memcpy(&pstp->ifaddr, + &localaddr->sin, + sizeof(pstp->ifaddr)); + } + rc = getaddrinfo_sometime( + curr_trap->addr->address, + port_text, &hints, + INITIAL_DNS_RETRY, + &trap_name_resolved, + pstp); + if (!rc) + msyslog(LOG_ERR, + "config_trap: getaddrinfo_sometime(%s,%s): %m", + curr_trap->addr->address, + port_text); +#endif /* WORKER */ continue; - + } /* port is at same location for v4 and v6 */ - SET_PORT(&peeraddr, port_no ? port_no : TRAPPORT); + SET_PORT(&peeraddr, port); if (NULL == localaddr) localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); @@ -2995,54 +3256,89 @@ config_trap( if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION)) msyslog(LOG_ERR, - "can't set trap for %s", + "set trap %s -> %s failed.", + latoa(localaddr), stoa(&peeraddr)); } } } -#ifdef FREE_CFG_T +/* + * trap_name_resolved() + * + * Callback invoked when config_trap()'s DNS lookup completes. + */ +# ifdef WORKER static void -free_config_trap( - struct config_tree *ptree +trap_name_resolved( + int rescode, + int gai_errno, + void * context, + const char * name, + const char * service, + const struct addrinfo * hints, + const struct addrinfo * res ) { - 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))) { + settrap_parms *pstp; + struct interface *localaddr; + sockaddr_u peeraddr; - if (T_Interface == curr_opt->attr) { - addr_node = curr_opt->value.p; - destroy_address_node(addr_node); - } - free_node(curr_opt); - } - DESTROY_QUEUE(curr_trap->options); - free_node(curr_trap); + (void)gai_errno; + (void)service; + (void)hints; + pstp = context; + if (rescode) { + msyslog(LOG_ERR, + "giving up resolving trap host %s: %s (%d)", + name, gai_strerror(rescode), rescode); + free(pstp); + return; } + INSIST(sizeof(peeraddr) >= res->ai_addrlen); + ZERO(peeraddr); + memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); + localaddr = NULL; + if (pstp->ifaddr_nonnull) + localaddr = findinterface(&pstp->ifaddr); + if (NULL == localaddr) + localaddr = ANY_INTERFACE_CHOOSE(&peeraddr); + if (!ctlsettrap(&peeraddr, localaddr, 0, NTP_VERSION)) + msyslog(LOG_ERR, "set trap %s -> %s failed.", + latoa(localaddr), stoa(&peeraddr)); + free(pstp); +} +# endif /* WORKER */ +#endif /* !SIM */ + + +#ifdef FREE_CFG_T +static void +free_config_trap( + config_tree *ptree + ) +{ + FREE_ADDR_OPTS_FIFO(ptree->trap); } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_fudge( - struct config_tree *ptree + config_tree *ptree ) { - struct addr_opts_node *curr_fudge; - struct attr_val *curr_opt; + addr_opts_node *curr_fudge; + attr_val *curr_opt; sockaddr_u addr_sock; - struct address_node *addr_node; + address_node *addr_node; struct refclockstat clock_stat; int err_flag; - curr_fudge = queue_head(ptree->fudge); - while (curr_fudge != NULL) { + curr_fudge = HEAD_PFIFO(ptree->fudge); + for (; curr_fudge != NULL; curr_fudge = curr_fudge->link) { err_flag = 0; /* Get the reference clock address and @@ -3051,33 +3347,41 @@ config_fudge( addr_node = curr_fudge->addr; ZERO_SOCK(&addr_sock); if (getnetnum(addr_node->address, &addr_sock, 1, t_REF) - != 1) + != 1) { err_flag = 1; + msyslog(LOG_ERR, + "unrecognized fudge reference clock address %s, line ignored", + stoa(&addr_sock)); + } if (!ISREFCLOCKADR(&addr_sock)) { + err_flag = 1; 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) { + ZERO(clock_stat); + curr_opt = HEAD_PFIFO(curr_fudge->options); + for (; curr_opt != NULL; curr_opt = curr_opt->link) { 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 T_Refid: clock_stat.haveflags |= CLK_HAVEVAL2; clock_stat.fudgeval2 = 0; @@ -3085,6 +3389,7 @@ config_fudge( 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) @@ -3092,6 +3397,7 @@ config_fudge( else clock_stat.flags &= ~CLK_FLAG1; break; + case T_Flag2: clock_stat.haveflags |= CLK_HAVEFLAG2; if (curr_opt->value.i) @@ -3099,6 +3405,7 @@ config_fudge( else clock_stat.flags &= ~CLK_FLAG2; break; + case T_Flag3: clock_stat.haveflags |= CLK_HAVEFLAG3; if (curr_opt->value.i) @@ -3106,6 +3413,7 @@ config_fudge( else clock_stat.flags &= ~CLK_FLAG3; break; + case T_Flag4: clock_stat.haveflags |= CLK_HAVEFLAG4; if (curr_opt->value.i) @@ -3113,107 +3421,85 @@ config_fudge( else clock_stat.flags &= ~CLK_FLAG4; break; + default: msyslog(LOG_ERR, - "Unexpected fudge internal flag 0x%x for %s\n", + "Unexpected fudge flag %s (%d) for %s", + token_name(curr_opt->attr), curr_opt->attr, stoa(&addr_sock)); exit(curr_opt->attr ? curr_opt->attr : 1); } - - curr_opt = next_node(curr_opt); } - -#ifdef REFCLOCK +# ifdef REFCLOCK if (!err_flag) - refclock_control(&addr_sock, &clock_stat, - (struct refclockstat *)0); -#endif - - curr_fudge = next_node(curr_fudge); + refclock_control(&addr_sock, &clock_stat, NULL); +# endif } } +#endif /* !SIM */ #ifdef FREE_CFG_T static void free_config_fudge( - struct config_tree *ptree + 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); - } - - free_node(curr_opt); - } - - DESTROY_QUEUE(curr_fudge->options); - free_node(curr_fudge); - } + FREE_ADDR_OPTS_FIFO(ptree->fudge); } #endif /* FREE_CFG_T */ static void config_vars( - struct config_tree *ptree + config_tree *ptree ) { - struct attr_val *curr_var; - FILE *new_file; + attr_val *curr_var; int len; - curr_var = queue_head(ptree->vars); - while (curr_var != NULL) { + curr_var = HEAD_PFIFO(ptree->vars); + for (; curr_var != NULL; curr_var = curr_var->link) { /* 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); + loop_config(LOOP_TICK, curr_var->value.d); break; + case T_Driftfile: if ('\0' == curr_var->value.s[0]) { stats_drift_file = 0; - msyslog(LOG_INFO, "config: driftfile disabled\n"); + msyslog(LOG_INFO, "config: driftfile disabled"); } else stats_config(STATS_FREQ_FILE, curr_var->value.s); break; - case T_WanderThreshold: + + case T_Ident: + sys_ident = curr_var->value.s; + break; + + case T_WanderThreshold: /* FALLTHROUGH */ + case T_Nonvolatile: 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 + if (-1 == change_logfile(curr_var->value.s, TRUE)) msyslog(LOG_ERR, - "Cannot open log file %s", + "Cannot open logfile %s: %m", curr_var->value.s); break; @@ -3221,26 +3507,27 @@ config_vars( if (saveconfigdir != NULL) free(saveconfigdir); len = strlen(curr_var->value.s); - if (0 == len) + if (0 == len) { saveconfigdir = NULL; - else if (DIR_SEP != curr_var->value.s[len - 1] + } 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] + && '/' != 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 + } else { saveconfigdir = estrdup( curr_var->value.s); + } break; case T_Automax: -#ifdef OPENSSL +#ifdef AUTOKEY sys_automax = curr_var->value.i; #endif break; @@ -3250,7 +3537,6 @@ config_vars( "config_vars(): unexpected token %d", curr_var->attr); } - curr_var = next_node(curr_var); } } @@ -3258,22 +3544,10 @@ config_vars( #ifdef FREE_CFG_T static void free_config_vars( - struct config_tree *ptree + 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); - } + FREE_ATTR_VAL_FIFO(ptree->vars); } #endif /* FREE_CFG_T */ @@ -3319,326 +3593,579 @@ is_sane_resolved_address( return 1; } -static int + +#ifndef SIM +static u_char get_correct_host_mode( - int hmode + int token ) { - switch (hmode) { - case T_Server: - case T_Pool: - case T_Manycastclient: + switch (token) { + + case T_Server: + case T_Pool: + case T_Manycastclient: return MODE_CLIENT; - break; - case T_Peer: + + case T_Peer: return MODE_ACTIVE; - break; - case T_Broadcast: + + case T_Broadcast: return MODE_BROADCAST; - break; - default: - return -1; + + default: + return 0; } } -static void -config_peers( - struct config_tree *ptree + +/* + * peerflag_bits() get config_peers() peerflags value from a + * peer_node's queue of flag attr_val entries. + */ +static int +peerflag_bits( + peer_node *pn ) { - 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; + attr_val *option; - 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; + /* translate peerflags options to bits */ + peerflags = 0; + option = HEAD_PFIFO(pn->peerflags); + for (; option != NULL; option = option->link) { + switch (option->value.i) { - /* Find the correct host-mode */ - hmode = get_correct_host_mode(curr_peer->host_mode); - NTP_INSIST(hmode != -1); + default: + INSIST(0); + break; - /* translate peerflags options to bits */ - peerflags = 0; - option = queue_head(curr_peer->peerflags); - for (; option != NULL; option = next_node(option)) - switch (option->value.i) { + case T_Autokey: + peerflags |= FLAG_SKEY; + break; - default: - NTP_INSIST(0); - break; + case T_Burst: + peerflags |= FLAG_BURST; + break; - case T_Autokey: - peerflags |= FLAG_SKEY; - break; + case T_Iburst: + peerflags |= FLAG_IBURST; + break; - case T_Burst: - peerflags |= FLAG_BURST; - break; + case T_Noselect: + peerflags |= FLAG_NOSELECT; + break; - case T_Iburst: - peerflags |= FLAG_IBURST; - break; + case T_Preempt: + peerflags |= FLAG_PREEMPT; + break; - case T_Noselect: - peerflags |= FLAG_NOSELECT; - break; + case T_Prefer: + peerflags |= FLAG_PREFER; + break; - case T_Preempt: - peerflags |= FLAG_PREEMPT; - break; + case T_True: + peerflags |= FLAG_TRUE; + break; - case T_Prefer: - peerflags |= FLAG_PREFER; - break; + case T_Xleave: + peerflags |= FLAG_XLEAVE; + break; + } + } - case T_True: - peerflags |= FLAG_TRUE; - break; + return peerflags; +} - case T_Xleave: - peerflags |= FLAG_XLEAVE; - break; - } - /* Attempt to resolve the address */ - ZERO_SOCK(&peeraddr); - AF(&peeraddr) = (u_short)curr_peer->addr->type; +static void +config_peers( + config_tree *ptree + ) +{ + sockaddr_u peeraddr; + struct addrinfo hints; + peer_node * curr_peer; + peer_resolved_ctx * ctx; + u_char hmode; - status = get_multiple_netnums(curr_peer->addr->address, - &peeraddr, &res, 0, t_UNK); + /* add servers named on the command line with iburst implied */ + for (; + cmdline_server_count > 0; + cmdline_server_count--, cmdline_servers++) { -#ifdef FORCE_DEFER_DNS - /* Hack for debugging Deferred DNS - * Pretend working names didn't work. + ZERO_SOCK(&peeraddr); + /* + * If we have a numeric address, we can safely + * proceed in the mainline with it. Otherwise, hand + * the hostname off to the blocking child. */ - 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 + if (is_ip_address(*cmdline_servers, AF_UNSPEC, + &peeraddr)) { - /* 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 *)"*"); + SET_PORT(&peeraddr, NTP_PORT); + if (is_sane_resolved_address(&peeraddr, + T_Server)) + peer_config( + &peeraddr, + NULL, + NULL, + MODE_CLIENT, + NTP_VERSION, + 0, + 0, + FLAG_IBURST, + 0, + 0, + NULL); + } else { + /* we have a hostname to resolve */ +# ifdef WORKER + ctx = emalloc_zero(sizeof(*ctx)); + ctx->family = AF_UNSPEC; + ctx->host_mode = T_Server; + ctx->hmode = MODE_CLIENT; + ctx->version = NTP_VERSION; + ctx->flags = FLAG_IBURST; + + ZERO(hints); + hints.ai_family = (u_short)ctx->family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + getaddrinfo_sometime(*cmdline_servers, + "ntp", &hints, + INITIAL_DNS_RETRY, + &peer_name_resolved, + (void *)ctx); +# else /* !WORKER follows */ + msyslog(LOG_ERR, + "hostname %s can not be used, please use IP address instead.", + curr_peer->addr->address); +# endif } - /* 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 + } + + /* add associations from the configuration file */ + curr_peer = HEAD_PFIFO(ptree->peers); + for (; curr_peer != NULL; curr_peer = curr_peer->link) { + ZERO_SOCK(&peeraddr); + /* Find the correct host-mode */ + hmode = get_correct_host_mode(curr_peer->host_mode); + INSIST(hmode != 0); + + if (T_Pool == curr_peer->host_mode) { + AF(&peeraddr) = curr_peer->addr->type; + peer_config( + &peeraddr, + curr_peer->addr->address, + NULL, + hmode, + curr_peer->peerversion, + curr_peer->minpoll, + curr_peer->maxpoll, + peerflag_bits(curr_peer), + curr_peer->ttl, + curr_peer->peerkey, + curr_peer->group); + /* + * If we have a numeric address, we can safely + * proceed in the mainline with it. Otherwise, hand + * the hostname off to the blocking child. */ - else { - res_bak = res; + } else if (is_ip_address(curr_peer->addr->address, + curr_peer->addr->type, &peeraddr)) { - /* - * Loop to configure the desired number of - * associations - */ - 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( + SET_PORT(&peeraddr, NTP_PORT); + if (is_sane_resolved_address(&peeraddr, + curr_peer->host_mode)) + peer_config( &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 *)"*"); + NULL, + NULL, + hmode, + curr_peer->peerversion, + curr_peer->minpoll, + curr_peer->maxpoll, + peerflag_bits(curr_peer), + curr_peer->ttl, + curr_peer->peerkey, + curr_peer->group); + } else { + /* we have a hostname to resolve */ +# ifdef WORKER + ctx = emalloc_zero(sizeof(*ctx)); + ctx->family = curr_peer->addr->type; + ctx->host_mode = curr_peer->host_mode; + ctx->hmode = hmode; + ctx->version = curr_peer->peerversion; + ctx->minpoll = curr_peer->minpoll; + ctx->maxpoll = curr_peer->maxpoll; + ctx->flags = peerflag_bits(curr_peer); + ctx->ttl = curr_peer->ttl; + ctx->keyid = curr_peer->peerkey; + ctx->group = curr_peer->group; + + ZERO(hints); + hints.ai_family = ctx->family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + getaddrinfo_sometime(curr_peer->addr->address, + "ntp", &hints, + INITIAL_DNS_RETRY, + &peer_name_resolved, ctx); +# else /* !WORKER follows */ + msyslog(LOG_ERR, + "hostname %s can not be used, please use IP address instead.", + curr_peer->addr->address); +# endif + } + } +} +#endif /* !SIM */ + +/* + * peer_name_resolved() + * + * Callback invoked when config_peers()'s DNS lookup completes. + */ +#ifdef WORKER +static void +peer_name_resolved( + int rescode, + int gai_errno, + void * context, + const char * name, + const char * service, + const struct addrinfo * hints, + const struct addrinfo * res + ) +{ + sockaddr_u peeraddr; + peer_resolved_ctx * ctx; + u_short af; + const char * fam_spec; + + (void)gai_errno; + (void)service; + (void)hints; + ctx = context; + + DPRINTF(1, ("peer_name_resolved(%s) rescode %d\n", name, rescode)); + + if (rescode) { +#ifndef IGNORE_DNS_ERRORS + free(ctx); + msyslog(LOG_ERR, + "giving up resolving host %s: %s (%d)", + name, gai_strerror(rescode), rescode); +#else /* IGNORE_DNS_ERRORS follows */ + getaddrinfo_sometime(name, service, hints, + INITIAL_DNS_RETRY, + &peer_name_resolved, context); +#endif + return; + } + + /* Loop to configure a single association */ + for (; res != NULL; res = res->ai_next) { + memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); + if (is_sane_resolved_address(&peeraddr, + ctx->host_mode)) { + NLOG(NLOG_SYSINFO) { + af = ctx->family; + fam_spec = (AF_INET6 == af) + ? "(AAAA) " + : (AF_INET == af) + ? "(A) " + : ""; + msyslog(LOG_INFO, "DNS %s %s-> %s", + name, fam_spec, + stoa(&peeraddr)); } - freeaddrinfo(res_bak); + peer_config( + &peeraddr, + NULL, + NULL, + ctx->hmode, + ctx->version, + ctx->minpoll, + ctx->maxpoll, + ctx->flags, + ctx->ttl, + ctx->keyid, + ctx->group); + break; } - curr_peer = next_node(curr_peer); } + free(ctx); } +#endif /* WORKER */ #ifdef FREE_CFG_T static void free_config_peers( - struct config_tree *ptree + config_tree *ptree ) { - struct peer_node *curr_peer; + peer_node *curr_peer; - while (NULL != (curr_peer = dequeue(ptree->peers))) { - destroy_address_node(curr_peer->addr); - DESTROY_QUEUE(curr_peer->peerflags); - free_node(curr_peer); + if (ptree->peers != NULL) { + for (;;) { + UNLINK_FIFO(curr_peer, *ptree->peers, link); + if (NULL == curr_peer) + break; + destroy_address_node(curr_peer->addr); + destroy_attr_val_fifo(curr_peer->peerflags); + free(curr_peer); + } + free(ptree->peers); + ptree->peers = NULL; } } #endif /* FREE_CFG_T */ +#ifndef SIM static void config_unpeers( - struct config_tree *ptree + 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)) { - + sockaddr_u peeraddr; + struct addrinfo hints; + unpeer_node * curr_unpeer; + struct peer * p; + const char * name; + int rc; + + curr_unpeer = HEAD_PFIFO(ptree->unpeers); + for (; curr_unpeer != NULL; curr_unpeer = curr_unpeer->link) { /* * 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); - } + p = findpeerbyassoc(curr_unpeer->assocID); + if (p != NULL) { + msyslog(LOG_NOTICE, "unpeered %s", + stoa(&p->srcadr)); + peer_clear(p, "GONE"); + unpeer(p); + } 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); + ZERO(peeraddr); + AF(&peeraddr) = curr_unpeer->addr->type; + name = curr_unpeer->addr->address; + rc = getnetnum(name, &peeraddr, 0, t_UNK); + /* Do we have a numeric address? */ + if (rc > 0) { + DPRINTF(1, ("unpeer: searching for %s\n", + stoa(&peeraddr))); + p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0); + if (p != NULL) { + msyslog(LOG_NOTICE, "unpeered %s", + stoa(&peeraddr)); + peer_clear(p, "GONE"); + unpeer(p); + } - /* 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 */ + continue; } - /* Check if name resolution failed. If yes, throw - * up our hands. + /* + * It's not a numeric IP address, it's a hostname. + * Check for associations with a matching hostname. */ - else if (status != 1) { - /* Do nothing */ + for (p = peer_list; p != NULL; p = p->p_link) + if (p->hostname != NULL) + if (!strcasecmp(p->hostname, name)) + break; + if (p != NULL) { + msyslog(LOG_NOTICE, "unpeered %s", name); + peer_clear(p, "GONE"); + unpeer(p); } - /* Yippie!! Name resolution has succeeded!!! - */ - else { - res_bak = res; - - /* - * Loop through the addresses found - */ - while (res) { - memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); + /* Resolve the hostname to address(es). */ +# ifdef WORKER + ZERO(hints); + hints.ai_family = curr_unpeer->addr->type; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + getaddrinfo_sometime(name, "ntp", &hints, + INITIAL_DNS_RETRY, + &unpeer_name_resolved, NULL); +# else /* !WORKER follows */ + msyslog(LOG_ERR, + "hostname %s can not be used, please use IP address instead.", + name); +# endif + } +} +#endif /* !SIM */ - found = 0; - peer = NULL; - DPRINTF(1, ("searching for %s\n", stoa(&peeraddr))); +/* + * unpeer_name_resolved() + * + * Callback invoked when config_unpeers()'s DNS lookup completes. + */ +#ifdef WORKER +static void +unpeer_name_resolved( + int rescode, + int gai_errno, + void * context, + const char * name, + const char * service, + const struct addrinfo * hints, + const struct addrinfo * res + ) +{ + sockaddr_u peeraddr; + struct peer * peer; + u_short af; + const char * fam_spec; + + (void)context; + (void)hints; + DPRINTF(1, ("unpeer_name_resolved(%s) rescode %d\n", name, rescode)); + + if (rescode) { + msyslog(LOG_ERR, "giving up resolving unpeer %s: %s (%d)", + name, gai_strerror(rescode), rescode); + return; + } + /* + * Loop through the addresses found + */ + for (; res != NULL; res = res->ai_next) { + INSIST(res->ai_addrlen <= sizeof(peeraddr)); + memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); + DPRINTF(1, ("unpeer: searching for peer %s\n", + stoa(&peeraddr))); + peer = findexistingpeer(&peeraddr, NULL, NULL, -1, 0); + if (peer != NULL) { + af = AF(&peeraddr); + fam_spec = (AF_INET6 == af) + ? "(AAAA) " + : (AF_INET == af) + ? "(A) " + : ""; + msyslog(LOG_NOTICE, "unpeered %s %s-> %s", name, + fam_spec, stoa(&peeraddr)); + peer_clear(peer, "GONE"); + unpeer(peer); + } + } +} +#endif /* WORKER */ - while (!found) { - peer = findexistingpeer(&peeraddr, peer, -1, 0); - if (!peer) - break; - if (peer->flags & FLAG_CONFIG) - found = 1; - } - if (found) { - peer_clear(peer, "GONE"); - unpeer(peer); - } +#ifdef FREE_CFG_T +static void +free_config_unpeers( + config_tree *ptree + ) +{ + unpeer_node *curr_unpeer; - res = res->ai_next; - } - freeaddrinfo(res_bak); + if (ptree->unpeers != NULL) { + for (;;) { + UNLINK_FIFO(curr_unpeer, *ptree->unpeers, link); + if (NULL == curr_unpeer) + break; + destroy_address_node(curr_unpeer->addr); + free(curr_unpeer); } + free(ptree->unpeers); } } +#endif /* FREE_CFG_T */ -#ifdef FREE_CFG_T +#ifndef SIM static void -free_config_unpeers( - struct config_tree *ptree +config_reset_counters( + config_tree *ptree ) { - struct unpeer_node *curr_unpeer; + int_node *counter_set; + + for (counter_set = HEAD_PFIFO(ptree->reset_counters); + counter_set != NULL; + counter_set = counter_set->link) { + switch (counter_set->i) { + default: + DPRINTF(1, ("config_reset_counters %s (%d) invalid\n", + keyword(counter_set->i), counter_set->i)); + break; + + case T_Allpeers: + peer_all_reset(); + break; + + case T_Auth: + reset_auth_stats(); + break; + + case T_Ctl: + ctl_clr_stats(); + break; - while (NULL != (curr_unpeer = dequeue(ptree->unpeers))) { - destroy_address_node(curr_unpeer->addr); - free_node(curr_unpeer); + case T_Io: + io_clr_stats(); + break; + + case T_Mem: + peer_clr_stats(); + break; + + case T_Sys: + proto_clr_stats(); + break; + + case T_Timer: + timer_clr_stats(); + break; + } } } +#endif /* !SIM */ + + +#ifdef FREE_CFG_T +static void +free_config_reset_counters( + config_tree *ptree + ) +{ + FREE_INT_FIFO(ptree->reset_counters); +} #endif /* FREE_CFG_T */ #ifdef SIM static void config_sim( - struct config_tree *ptree + config_tree *ptree ) { int i; server_info *serv_info; - struct attr_val *init_stmt; + attr_val *init_stmt; + sim_node *sim_n; /* Check if a simulate block was found in the configuration code. * If not, return an error and exit */ - if (NULL == ptree->sim_details) { + sim_n = HEAD_PFIFO(ptree->sim_details); + if (NULL == sim_n) { fprintf(stderr, "ERROR!! I couldn't find a \"simulate\" block for configuring the simulator.\n"); fprintf(stderr, "\tCheck your configuration file.\n"); exit(1); @@ -3647,9 +4174,8 @@ config_sim( /* Process the initialization statements * ------------------------------------- */ - init_stmt = queue_head(ptree->sim_details->init_opts); - while (init_stmt != NULL) { - + init_stmt = HEAD_PFIFO(sim_n->init_opts); + for (; init_stmt != NULL; init_stmt = init_stmt->link) { switch(init_stmt->attr) { case T_Beep_Delay: @@ -3666,29 +4192,31 @@ config_sim( 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++) { + simulation.num_of_servers = 0; + serv_info = HEAD_PFIFO(sim_n->servers); + for (; serv_info != NULL; serv_info = serv_info->link) + simulation.num_of_servers++; + simulation.servers = emalloc(simulation.num_of_servers * + sizeof(simulation.servers[0])); + + i = 0; + serv_info = HEAD_PFIFO(sim_n->servers); + for (; serv_info != NULL; serv_info = serv_info->link) { 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); + } else { + simulation.servers[i] = *serv_info; + simulation.servers[i].link = NULL; + i++; + } } - /* Create server associations */ printf("Creating server associations\n"); create_server_associations(); fprintf(stderr,"\tServer associations successfully created!!\n"); @@ -3698,18 +4226,40 @@ config_sim( #ifdef FREE_CFG_T static void free_config_sim( - struct config_tree *ptree + config_tree *ptree ) { + sim_node *sim_n; + server_info *serv_n; + script_info *script_n; + 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); + sim_n = HEAD_PFIFO(ptree->sim_details); + free(ptree->sim_details); ptree->sim_details = NULL; + if (NULL == sim_n) + return; + + FREE_ATTR_VAL_FIFO(sim_n->init_opts); + for (;;) { + UNLINK_FIFO(serv_n, *sim_n->servers, link); + if (NULL == serv_n) + break; + free(serv_n->curr_script); + if (serv_n->script != NULL) { + for (;;) { + UNLINK_FIFO(script_n, *serv_n->script, + link); + if (script_n == NULL) + break; + free(script_n); + } + free(serv_n->script); + } + free(serv_n); + } + free(sim_n); } #endif /* FREE_CFG_T */ #endif /* SIM */ @@ -3722,7 +4272,7 @@ free_config_sim( #ifndef SIM static void config_ntpd( - struct config_tree *ptree + config_tree *ptree ) { config_nic_rules(ptree); @@ -3732,6 +4282,7 @@ config_ntpd( config_tos(ptree); config_access(ptree); config_tinker(ptree); + config_rlimit(ptree); config_system_opts(ptree); config_logconfig(ptree); config_phone(ptree); @@ -3743,7 +4294,24 @@ config_ntpd( config_peers(ptree); config_unpeers(ptree); config_fudge(ptree); - config_qos(ptree); + config_reset_counters(ptree); + +#ifdef TEST_BLOCKING_WORKER + { + struct addrinfo hints; + + ZERO(hints); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + getaddrinfo_sometime("www.cnn.com", "ntp", &hints, + INITIAL_DNS_RETRY, + gai_test_callback, (void *)1); + hints.ai_family = AF_INET6; + getaddrinfo_sometime("ipv6.google.com", "ntp", &hints, + INITIAL_DNS_RETRY, + gai_test_callback, (void *)0x600); + } +#endif } #endif /* !SIM */ @@ -3751,7 +4319,7 @@ config_ntpd( #ifdef SIM static void config_ntpdsim( - struct config_tree *ptree + config_tree *ptree ) { printf("Configuring Simulator...\n"); @@ -3760,6 +4328,8 @@ config_ntpdsim( config_tos(ptree); config_monitor(ptree); config_tinker(ptree); + if (0) + config_rlimit(ptree); /* not needed for the simulator */ config_system_opts(ptree); config_logconfig(ptree); config_vars(ptree); @@ -3781,15 +4351,14 @@ config_remotely( snprintf(origin, sizeof(origin), "remote config from %s", stoa(remote_addr)); - memset(&remote_cuckoo, 0, sizeof(remote_cuckoo)); + ZERO(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(); + yyparse(&remote_cuckoo); cfgt.source.attr = CONF_SOURCE_NTPQ; cfgt.timestamp = time(NULL); cfgt.source.value.s = estrdup(stoa(remote_addr)); @@ -3807,11 +4376,11 @@ config_remotely( */ void getconfig( - int argc, - char *argv[] + int argc, + char ** argv ) { - char line[MAXLINE]; + char line[256]; #ifdef DEBUG atexit(free_all_config_trees); @@ -3820,28 +4389,27 @@ getconfig( 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"); + if (!ExpandEnvironmentStringsA(temp, config_file_storage, + sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m"); 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"); + if (!ExpandEnvironmentStringsA(temp, alt_config_file_storage, + sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m"); 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_sys_var(line, strlen(line) + 1, RO); /* * Set up for the first time step to install a variable showing @@ -3849,24 +4417,8 @@ getconfig( */ 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 @@ -3904,12 +4456,11 @@ getconfig( #ifdef DEBUG yydebug = !!(debug >= 5); #endif - ip_file = fp[curr_include_level]; - yyparse(); - + yyparse(fp[curr_include_level]); + DPRINTF(1, ("Finished Parsing!!\n")); - cfgt.source.attr = CONF_SOURCE_FILE; + cfgt.source.attr = CONF_SOURCE_FILE; cfgt.timestamp = time(NULL); save_and_apply_config_tree(); @@ -3921,28 +4472,15 @@ getconfig( 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) { - /* - * Need name resolution - */ - do_resolve_internal(); - } - } } void save_and_apply_config_tree(void) { - struct config_tree *ptree; + config_tree *ptree; #ifndef SAVECONFIG - struct config_tree *punlinked; + config_tree *punlinked; #endif /* @@ -3952,10 +4490,9 @@ save_and_apply_config_tree(void) */ 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); + ZERO(cfgt); + + LINK_TAIL_SLIST(cfg_tree_history, ptree, link, config_tree); #ifdef SAVECONFIG if (HAVE_OPT( SAVECONFIGQUIT )) { @@ -3966,13 +4503,12 @@ save_and_apply_config_tree(void) 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)); + mfprintf(stderr, + "can not create save file %s, error %d %m\n", + OPT_ARG(SAVECONFIGQUIT), err); exit(err); } - + dumpfailed = dump_all_config_trees(dumpfile, 0); if (dumpfailed) fprintf(stderr, @@ -4005,14 +4541,14 @@ save_and_apply_config_tree(void) */ #ifndef SAVECONFIG UNLINK_SLIST(punlinked, cfg_tree_history, ptree, link, - struct config_tree); - NTP_INSIST(punlinked == ptree); + config_tree); + INSIST(punlinked == ptree); free_config_tree(ptree); #endif } -void +static void ntpd_set_tod_using( const char *which ) @@ -4024,6 +4560,40 @@ ntpd_set_tod_using( } +static char * +normal_dtoa( + double d + ) +{ + char * buf; + char * pch_e; + char * pch_nz; + + LIB_GETBUF(buf); + snprintf(buf, LIB_BUFLENGTH, "%g", d); + + /* use lowercase 'e', strip any leading zeroes in exponent */ + pch_e = strchr(buf, 'e'); + if (NULL == pch_e) { + pch_e = strchr(buf, 'E'); + if (NULL == pch_e) + return buf; + *pch_e = 'e'; + } + pch_e++; + if ('-' == *pch_e) + pch_e++; + pch_nz = pch_e; + while ('0' == *pch_nz) + pch_nz++; + if (pch_nz == pch_e) + return buf; + strlcpy(pch_e, pch_nz, LIB_BUFLENGTH - (pch_e - buf)); + + return buf; +} + + /* FUNCTIONS COPIED FROM THE OLDER ntp_config.c * -------------------------------------------- */ @@ -4139,7 +4709,6 @@ get_netinfo_config(void) } - /* * free_netinfo_config - release NetInfo configuration state */ @@ -4153,7 +4722,6 @@ free_netinfo_config( } - /* * gettokens_netinfo - return tokens from NetInfo */ @@ -4192,7 +4760,7 @@ gettokens_netinfo ( /* Found the property, but it has no values */ if (namelist.ni_namelist_len == 0) continue; - config->val_list = + config->val_list = emalloc(sizeof(char*) * (namelist.ni_namelist_len + 1)); val_list = config->val_list; @@ -4201,7 +4769,7 @@ gettokens_netinfo ( index < namelist.ni_namelist_len; index++) { char *value; - + value = namelist.ni_namelist_val[index]; val_list[index] = estrdup(value); } @@ -4273,422 +4841,117 @@ gettokens_netinfo ( goto again; } - #endif /* HAVE_NETINFO */ + /* * getnetnum - return a net number (this is crude, but careful) * - * returns 1 for success, and mysteriously, 0 or -1 for failure + * returns 1 for success, and mysteriously, 0 for most failures, and + * -1 if the address found is IPv6 and we believe IPv6 isn't working. */ +#ifndef SIM static int getnetnum( const char *num, sockaddr_u *addr, int complain, - enum gnn_type a_type - ) -{ - int retval; - struct addrinfo *res; - - /* Get all the addresses that resolve to this name */ - retval = get_multiple_netnums(num, addr, &res, complain, a_type); - - if (retval != 1) { - /* Name resolution failed */ - return retval; - } - - memcpy(addr, res->ai_addr, res->ai_addrlen); - - DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr))); - - freeaddrinfo(res); - return 1; -} - - -/* - * get_multiple_netnums - * - * returns 1 for success, and mysteriously, 0 or -1 for failure - */ -static int -get_multiple_netnums( - const char *nameornum, - sockaddr_u *addr, - struct addrinfo **res, - int complain, - enum gnn_type a_type + enum gnn_type a_type /* ignored */ ) { - char lookbuf[1024]; - const char *lookup; - char *pch; - struct addrinfo hints; - struct addrinfo *ptr; - int retval; - sockaddr_u ipaddr; - - memset(&hints, 0, sizeof(hints)); - - if (strlen(nameornum) >= sizeof(lookbuf)) { - NTP_INSIST(strlen(nameornum) < sizeof(lookbuf)); - return 0; - } + NTP_REQUIRE(AF_UNSPEC == AF(addr) || + AF_INET == AF(addr) || + AF_INET6 == AF(addr)); - 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'; - } - } - - if (AF_INET6 == hints.ai_family && !ipv6_works) + if (!is_ip_address(num, AF(addr), addr)) 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 (IS_IPV6(addr) && !ipv6_works) + return -1; - if (retval || (AF_INET6 == ptr->ai_family && !ipv6_works)) { - if (complain) - msyslog(LOG_ERR, - "getaddrinfo: \"%s\" invalid host address, ignored", - lookup); - else - DPRINTF(1, ("getaddrinfo: \"%s\" invalid host address.\n", - lookup)); +# ifdef ISC_PLATFORM_HAVESALEN + addr->sa.sa_len = SIZEOF_SOCKADDR(AF(addr)); +# endif + SET_PORT(addr, NTP_PORT); - if (!retval) { - freeaddrinfo(ptr); - return -1; - } else { - return 0; - } - } - *res = ptr; + DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr))); return 1; } +#endif /* !SIM */ - -#if !defined(VMS) && !defined(SYS_WINNT) -/* - * catchchild - receive the resolver's exit status - */ -static RETSIGTYPE -catchchild( - int sig - ) -{ - /* - * We only start up one child, and if we're here - * it should have already exited. Hence the following - * shouldn't hang. If it does, please tell me. - */ -#if !defined (SYS_WINNT) && !defined(SYS_VXWORKS) - (void) wait(0); -#endif /* SYS_WINNT && VXWORKS*/ -} -#endif /* VMS */ - - -/* - * save_resolve - save configuration info into a file for later name resolution - */ -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 +#if defined(HAVE_SETRLIMIT) +void +ntp_rlimit( + int rl_what, + rlim_t rl_value, + int rl_scale, + char * rl_sstr ) { -#ifndef SYS_VXWORKS - if (res_fp == NULL) { -#ifndef SYS_WINNT - strcpy(res_file, RES_TEMPFILE); -#else - int len; - - /* no /tmp directory under NT */ - 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); - } + struct rlimit rl; - memmove(res_file + len, "ntpdXXXXXX", - sizeof "ntpdXXXXXX"); -#endif /* SYS_WINNT */ -#ifdef HAVE_MKSTEMP - { - int fd; - - res_fp = NULL; - if ((fd = mkstemp(res_file)) != -1) - res_fp = fdopen(fd, "r+"); - } -#else - mktemp(res_file); - res_fp = fopen(res_file, "w"); -#endif - if (res_fp == NULL) { - msyslog(LOG_ERR, "open failed for %s: %m", res_file); - return; - } - } -#ifdef DEBUG - if (debug) { - printf("resolving %s\n", name); - } -#endif - - (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 %d %d %x %d %u %s\n", - name, no_needed, type, - mode, version, minpoll, maxpoll, flags, - ttl, keyid, keystr); -#endif - -#else /* SYS_VXWORKS */ - /* save resolve info to a struct */ -#endif /* SYS_VXWORKS */ -} - - -/* - * abort_resolve - terminate the resolver stuff and delete the file - */ -static void -abort_resolve(void) -{ - /* - * In an ideal world we would might reread the file and - * log the hosts which aren't getting configured. Since - * this is too much work, however, just close and delete - * the temp file. - */ - if (res_fp != NULL) - (void) fclose(res_fp); - res_fp = NULL; - -#ifndef SYS_VXWORKS /* we don't open the file to begin with */ -#if !defined(VMS) - if (unlink(res_file)) - msyslog(LOG_WARNING, - "Unable to remove temporary resolver file %s, %m", - res_file); -#else - (void) delete(res_file); -#endif /* VMS */ -#endif /* SYS_VXWORKS */ -} - - -/* - * do_resolve_internal - start up the resolver function (not program) - * - * 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. - * I'm unlikely to find the time for doing this, though. -wjm - */ -static void -do_resolve_internal(void) -{ -#ifndef SYS_WINNT - int i; -#endif - - if (res_fp == NULL) { - /* belch */ - msyslog(LOG_ERR, - "do_resolve_internal: Fatal: res_fp == NULL"); - exit(1); - } - - /* we are done with this now */ - (void) fclose(res_fp); - res_fp = NULL; - -#ifndef NO_INTRES - req_file = res_file; /* set up pointer to res file */ -#ifndef SYS_WINNT - (void) signal_no_reset(SIGCHLD, catchchild); - - /* the parent process will write to the pipe - * in order to wake up to child process - * which may be waiting in a select() call - * on the read fd */ - if (pipe(resolver_pipe_fd) < 0) { - msyslog(LOG_ERR, - "unable to open resolver pipe"); - exit(1); - } - - i = fork(); - /* Shouldn't the code below be re-ordered? - * I.e. first check if the fork() returned an error, then - * check whether we're parent or child. - * Martin Burnicki - */ - if (i == 0) { - /* - * this used to close everything - * I don't think this is necessary - */ + switch (rl_what) { +# ifdef RLIMIT_MEMLOCK + case RLIMIT_MEMLOCK: /* - * To the unknown commenter above: - * Well, I think it's better to clean up - * after oneself. I have had problems with - * refclock-io when intres was running - things - * where fine again when ntpintres was gone. - * So some systems react erratic at least. - * - * Frank Kardel - * - * 94-11-16: - * Further debugging has proven that the above is - * absolutely harmful. The internal resolver - * is still in the SIGIO process group and the lingering - * async io information causes it to process requests from - * all file decriptor causing a race between the NTP daemon - * and the resolver. which then eats data when it wins 8-(. - * It is absolutly necessary to kill any IO associations - * shared with the NTP daemon. - * - * We also block SIGIO (currently no ports means to - * disable the signal handle for IO). - * - * Thanks to wgstuken@informatik.uni-erlangen.de to notice - * that it is the ntp-resolver child running into trouble. - * - * THUS: + * The default RLIMIT_MEMLOCK is very low on Linux systems. + * Unless we increase this limit malloc calls are likely to + * fail if we drop root privilege. To be useful the value + * has to be larger than the largest ntpd resident set size. */ + DPRINTF(2, ("ntp_rlimit: MEMLOCK: %d %s\n", + (int)(rl_value / rl_scale), rl_sstr)); + rl.rlim_cur = rl.rlim_max = rl_value; + if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) + msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m"); + break; +# endif /* RLIMIT_MEMLOCK */ +# ifdef RLIMIT_NOFILE + case RLIMIT_NOFILE: /* - msyslog(LOG_INFO, "do_resolve_internal: pre-closelog"); - */ - closelog(); - kill_asyncio(0); - - (void) signal_no_reset(SIGCHLD, SIG_DFL); - - init_logging("ntpd_intres", 0); - setup_logfile(); - /* - msyslog(LOG_INFO, "do_resolve_internal: post-closelog"); - */ - - ntp_intres(); + * For large systems the default file descriptor limit may + * not be enough. + */ + DPRINTF(2, ("ntp_rlimit: NOFILE: %d %s\n", + (int)(rl_value / rl_scale), rl_sstr)); + rl.rlim_cur = rl.rlim_max = rl_value; + if (setrlimit(RLIMIT_NOFILE, &rl) == -1) + msyslog(LOG_ERR, "Cannot set RLIMIT_NOFILE: %m"); + break; +# endif /* RLIMIT_NOFILE */ +# ifdef RLIMIT_STACK + case RLIMIT_STACK: /* - * If we got here, the intres code screwed up. - * Print something so we don't die without complaint + * Provide a way to set the stack limit to something + * smaller, so that we don't lock a lot of unused + * stack memory. */ - msyslog(LOG_ERR, "call to ntp_intres lost"); - abort_resolve(); - exit(1); - } - if (i == -1) { - msyslog(LOG_ERR, "fork() failed, can't start ntp_intres: %m"); - (void) signal_no_reset(SIGCHLD, SIG_DFL); - abort_resolve(); - } 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. - */ - 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(); - } - 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(); + DPRINTF(2, ("ntp_rlimit: STACK: %d %s pages\n", + (int)(rl_value / rl_scale), rl_sstr)); + if (-1 == getrlimit(RLIMIT_STACK, &rl)) { + msyslog(LOG_ERR, "getrlimit() failed: %m"); + } else { + if (rl_value > rl.rlim_max) { + msyslog(LOG_WARNING, + "ntp_rlimit: using maximum allowed stack limit %lu instead of %lu.", + (u_long)rl.rlim_max, + (u_long)rl_value); + rl_value = rl.rlim_max; + } + if (-1 == setrlimit(RLIMIT_STACK, &rl)) { + msyslog(LOG_ERR, + "ntp_rlimit: Cannot adjust stack limit: %m"); + } } + break; +# endif /* RLIMIT_STACK */ + + default: + INSIST(!"Unexpected setrlimit() case!"); + break; } -#endif /* SYS_WINNT */ -#else /* NO_INTRES follows */ - msyslog(LOG_ERR, - "Deferred DNS not implemented - use numeric addresses"); - abort_resolve(); -#endif } +#endif /* HAVE_SETRLIMIT */ |