/* $NetBSD: ntp_parser.y,v 1.20 2024/08/18 20:47:17 christos Exp $ */ /* ntp_parser.y * * The parser for the NTP configuration file. * * Written By: Sachin Kamboj * University of Delaware * Newark, DE 19711 * Copyright (c) 2006 */ %{ #ifdef HAVE_CONFIG_H # include #endif #include "ntp.h" #include "ntpd.h" #include "ntp_machine.h" #include "ntp_stdlib.h" #include "ntp_filegen.h" #include "ntp_scanner.h" #include "ntp_config.h" #include "ntp_crypto.h" #include "ntp_calendar.h" #include "ntpsim.h" /* HMS: Do we really want this all the time? */ /* SK: It might be a good idea to always include the simulator code. That way someone can use the same configuration file for both the simulator and the daemon */ #define YYMALLOC emalloc #define YYFREE free #define YYERROR_VERBOSE #define YYMAXDEPTH 1000 /* stop the madness sooner */ void yyerror(const char *msg); #ifdef SIM # define ONLY_SIM(a) (a) #else # define ONLY_SIM(a) NULL #endif %} /* * Enable generation of token names array even without YYDEBUG. * We access via token_name() defined below. */ %token-table %union { char * String; double Double; int Integer; unsigned U_int; gen_fifo * Generic_fifo; attr_val * Attr_val; attr_val_fifo * Attr_val_fifo; int_fifo * Int_fifo; string_fifo * String_fifo; address_node * Address_node; address_fifo * Address_fifo; setvar_node * Set_var; server_info * Sim_server; server_info_fifo * Sim_server_fifo; script_info * Sim_script; script_info_fifo * Sim_script_fifo; } /* TERMINALS (do not appear left of colon) */ %token T_Abbrev %token T_Age %token T_All %token T_Allan %token T_Allpeers %token T_Auth %token T_Autokey %token T_Automax %token T_Average %token T_Basedate %token T_Bclient %token T_Bcpollbstep %token T_Beacon %token T_Broadcast %token T_Broadcastclient %token T_Broadcastdelay %token T_Burst %token T_Calibrate %token T_Ceiling %token T_Checkhash %token T_Clockstats %token T_Cohort %token T_ControlKey %token T_Crypto %token T_Cryptostats %token T_Ctl %token T_Day %token T_Default %token T_Delrestrict %token T_Device %token T_Digest %token T_Disable %token T_Discard %token T_Dispersion %token T_Double /* not a token */ %token T_Driftfile %token T_Drop %token T_Dscp %token T_Ellipsis /* "..." not "ellipsis" */ %token T_Enable %token T_End %token T_Epeer %token T_False %token T_File %token T_Filegen %token T_Filenum %token T_Flag1 %token T_Flag2 %token T_Flag3 %token T_Flag4 %token T_Flake %token T_Floor %token T_Freq %token T_Fudge %token T_Fuzz %token T_Host %token T_Huffpuff %token T_Iburst %token T_Ident %token T_Ignore %token T_Ignorehash %token T_Incalloc %token T_Incmem %token T_Initalloc %token T_Initmem %token T_Includefile %token T_Integer /* not a token */ %token T_Interface %token T_Intrange /* not a token */ %token T_Io %token T_Ippeerlimit %token T_Ipv4 %token T_Ipv4_flag %token T_Ipv6 %token T_Ipv6_flag %token T_Kernel %token T_Key %token T_Keys %token T_Keysdir %token T_Kod %token T_Leapfile %token T_Leapsmearinterval %token T_Limited %token T_Link %token T_Listen %token T_Logconfig %token T_Logfile %token T_Loopstats %token T_Lowpriotrap %token T_Manycastclient %token T_Manycastserver %token T_Mask %token T_Maxage %token T_Maxclock %token T_Maxdepth %token T_Maxdist %token T_Maxmem %token T_Maxpoll %token T_Mdnstries %token T_Mem %token T_Memlock %token T_Minclock %token T_Mindepth %token T_Mindist %token T_Minimum %token T_Minjitter %token T_Minpoll %token T_Minsane %token T_Mode %token T_Mode7 %token T_Monitor %token T_Month %token T_Mru %token T_Mssntp %token T_Multicastclient %token T_Nic %token T_Nolink %token T_Nomodify %token T_Nomrulist %token T_None %token T_Nonvolatile %token T_Noepeer %token T_Nopeer %token T_Noquery %token T_Noselect %token T_Noserve %token T_Notrap %token T_Notrust %token T_Ntp %token T_Ntpport %token T_NtpSignDsocket %token T_Orphan %token T_Orphanwait %token T_PCEdigest %token T_Panic %token T_Peer %token T_Peerstats %token T_Phone %token T_Pid %token T_Pidfile %token T_Poll %token T_PollSkewList %token T_Pool %token T_Port %token T_PpsData %token T_Preempt %token T_Prefer %token T_Protostats %token T_Pw %token T_Randfile %token T_Rawstats %token T_Refid %token T_Requestkey %token T_Reset %token T_Restrict %token T_Revoke %token T_Rlimit %token T_Saveconfigdir %token T_Server %token T_Serverresponse %token T_ServerresponseFuzz /* Not a token */ %token T_Setvar %token T_Source %token T_Stacksize %token T_Statistics %token T_Stats %token T_Statsdir %token T_Step %token T_Stepback %token T_Stepfwd %token T_Stepout %token T_Stratum %token T_String /* not a token */ %token T_Sys %token T_Sysstats %token T_Tick %token T_Time1 %token T_Time2 %token T_TimeData %token T_Timer %token T_Timingstats %token T_Tinker %token T_Tos %token T_Trap %token T_True %token T_Trustedkey %token T_Ttl %token T_Type %token T_U_int /* Not a token */ %token T_UEcrypto %token T_UEcryptonak %token T_UEdigest %token T_Unconfig %token T_Unpeer %token T_Version %token T_WanderThreshold /* Not a token */ %token T_Week %token T_Wildcard %token T_Xleave %token T_Xmtnonce %token T_Year %token T_Flag /* Not a token */ %token T_EOC /* NTP Simulator Tokens */ %token T_Simulate %token T_Beep_Delay %token T_Sim_Duration %token T_Server_Offset %token T_Duration %token T_Freq_Offset %token T_Wander %token T_Jitter %token T_Prop_Delay %token T_Proc_Delay /*** NON-TERMINALS ***/ %type access_control_flag %type ac_flag_list %type address %type address_fam %type address_list %type basedate %type boolean %type client_type %type counter_set_keyword %type counter_set_list %type crypto_command %type crypto_command_list %type crypto_str_keyword %type device_item %type device_item_path_keyword %type device_item_list %type discard_option %type discard_option_keyword %type discard_option_list %type enable_disable %type filegen_option %type filegen_option_list %type filegen_type %type fudge_factor %type fudge_factor_bool_keyword %type fudge_factor_dbl_keyword %type fudge_factor_list %type integer_list %type integer_list_range %type integer_list_range_elt %type integer_range %type nic_rule_action %type interface_command %type interface_nic %type ip_address %type res_ippeerlimit %type link_nolink %type log_config_command %type log_config_list %type misc_cmd_dbl_keyword %type misc_cmd_int_keyword %type misc_cmd_str_keyword %type misc_cmd_str_lcl_keyword %type mru_option %type mru_option_keyword %type mru_option_list %type nic_rule_class %type number %type opt_hash_check %type option %type option_flag %type option_flag_keyword %type option_list %type option_int %type option_int_keyword %type option_str %type option_str_keyword %type pollskew_list %type pollskew_cycle %type pollskew_spec %type reset_command %type restrict_mask %type rlimit_option_keyword %type rlimit_option %type rlimit_option_list %type stat %type stats_list %type string_list %type system_option %type system_option_flag_keyword %type system_option_local_flag_keyword %type system_option_list %type t_default_or_zero %type tinker_option_keyword %type tinker_option %type tinker_option_list %type tos_option %type tos_option_dbl_keyword %type tos_option_int_keyword %type tos_option_list %type trap_option %type trap_option_list %type unpeer_keyword %type variable_assign /* NTP Simulator non-terminals */ %type sim_init_statement %type sim_init_statement_list %type sim_init_keyword %type sim_server_list %type sim_server %type sim_server_offset %type sim_server_name %type sim_act %type sim_act_list %type sim_act_keyword %type sim_act_stmt_list %type sim_act_stmt %% /* ntp.conf * Configuration File Grammar * -------------------------- */ configuration : command_list ; command_list : command_list command T_EOC | command T_EOC | error T_EOC { /* I will need to incorporate much more fine grained * error messages. The following should suffice for * the time being. */ struct FILE_INFO * ip_ctx = lex_current(); msyslog(LOG_ERR, "syntax error in %s line %d, column %d", ip_ctx->fname, ip_ctx->errpos.nline, ip_ctx->errpos.ncol); } ; command : /* NULL STATEMENT */ | server_command | unpeer_command | other_mode_command | authentication_command | monitoring_command | access_control_command | orphan_mode_command | fudge_command | rlimit_command | system_option_command | tinker_command | miscellaneous_command | simulate_command | device_command ; /* Server Commands * --------------- */ server_command : client_type address option_list { peer_node *my_node; my_node = create_peer_node($1, $2, $3); APPEND_G_FIFO(cfgt.peers, my_node); } ; client_type : T_Server | T_Pool | T_Peer | T_Broadcast | T_Manycastclient ; address : ip_address | address_fam T_String { $$ = create_address_node($2, $1); } ; ip_address : T_String { $$ = create_address_node($1, AF_UNSPEC); } ; address_fam : T_Ipv4_flag { $$ = AF_INET; } | T_Ipv6_flag { $$ = AF_INET6; } ; option_list : /* empty list */ { $$ = NULL; } | option_list option { $$ = $1; APPEND_G_FIFO($$, $2); } ; option : option_flag | option_int | option_str ; option_flag : option_flag_keyword { $$ = create_attr_ival(T_Flag, $1); } ; option_flag_keyword : T_Autokey | T_Burst | T_Iburst | T_Noselect | T_Preempt | T_Prefer | T_True | T_Xleave | T_Xmtnonce ; option_int : option_int_keyword T_Integer { $$ = create_attr_ival($1, $2); } | option_int_keyword T_U_int { $$ = create_attr_uval($1, $2); } ; option_int_keyword : T_Key | T_Minpoll | T_Maxpoll | T_Ttl | T_Mode | T_Version ; option_str : option_str_keyword T_String { $$ = create_attr_sval($1, $2); } ; option_str_keyword : T_Ident ; /* unpeer commands * --------------- */ unpeer_command : unpeer_keyword address { unpeer_node *my_node; my_node = create_unpeer_node($2); if (my_node) APPEND_G_FIFO(cfgt.unpeers, my_node); } ; unpeer_keyword : T_Unconfig | T_Unpeer ; /* Other Modes * (broadcastclient manycastserver multicastclient) * ------------------------------------------------ */ other_mode_command : T_Broadcastclient { cfgt.broadcastclient = 1; } | T_Manycastserver address_list { CONCAT_G_FIFOS(cfgt.manycastserver, $2); } | T_Multicastclient address_list { CONCAT_G_FIFOS(cfgt.multicastclient, $2); } | T_Mdnstries T_Integer { cfgt.mdnstries = $2; } ; /* Authentication Commands * ----------------------- */ authentication_command : T_Automax T_Integer { attr_val *atrv; atrv = create_attr_ival($1, $2); APPEND_G_FIFO(cfgt.vars, atrv); } | T_ControlKey T_Integer { cfgt.auth.control_key = $2; } | T_Crypto crypto_command_list { cfgt.auth.cryptosw++; CONCAT_G_FIFOS(cfgt.auth.crypto_cmd_list, $2); } | T_Keys T_String { cfgt.auth.keys = $2; } | T_Keysdir T_String { cfgt.auth.keysdir = $2; } | T_Requestkey T_Integer { cfgt.auth.request_key = $2; } | T_Revoke T_Integer { cfgt.auth.revoke = $2; } | T_Trustedkey integer_list_range { /* [Bug 948] leaves it open if appending or * replacing the trusted key list is the right * way. In any case, either alternative should * be coded correctly! */ DESTROY_G_FIFO(cfgt.auth.trusted_key_list, destroy_attr_val); /* remove for append */ CONCAT_G_FIFOS(cfgt.auth.trusted_key_list, $2); } | T_NtpSignDsocket T_String { cfgt.auth.ntp_signd_socket = $2; } ; crypto_command_list : /* empty list */ { $$ = NULL; } | crypto_command_list crypto_command { $$ = $1; APPEND_G_FIFO($$, $2); } ; crypto_command : crypto_str_keyword T_String { $$ = create_attr_sval($1, $2); } | T_Revoke T_Integer { $$ = NULL; cfgt.auth.revoke = $2; msyslog(LOG_WARNING, "'crypto revoke %d' is deprecated, " "please use 'revoke %d' instead.", cfgt.auth.revoke, cfgt.auth.revoke); } ; crypto_str_keyword : T_Host | T_Ident | T_Pw | T_Randfile | T_Digest ; /* Orphan Mode Commands * -------------------- */ orphan_mode_command : T_Tos tos_option_list { CONCAT_G_FIFOS(cfgt.orphan_cmds, $2); } ; tos_option_list : tos_option_list tos_option { $$ = $1; APPEND_G_FIFO($$, $2); } | tos_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; tos_option : tos_option_int_keyword T_Integer { $$ = create_attr_dval($1, (double)$2); } | tos_option_dbl_keyword number { $$ = create_attr_dval($1, $2); } | T_Cohort boolean { $$ = create_attr_dval($1, (double)$2); } | basedate { $$ = create_attr_ival(T_Basedate, $1); } ; tos_option_int_keyword : T_Bcpollbstep | T_Beacon | T_Ceiling | T_Floor | T_Maxclock | T_Minclock | T_Minsane | T_Orphan | T_Orphanwait ; tos_option_dbl_keyword : T_Mindist | T_Maxdist ; /* Monitoring Commands * ------------------- */ monitoring_command : T_Statistics stats_list { CONCAT_G_FIFOS(cfgt.stats_list, $2); } | T_Statsdir T_String { if (lex_from_file()) { cfgt.stats_dir = $2; } else { YYFREE($2); yyerror("statsdir remote configuration ignored"); } } | T_Filegen stat filegen_option_list { filegen_node *fgn; fgn = create_filegen_node($2, $3); APPEND_G_FIFO(cfgt.filegen_opts, fgn); } ; stats_list : stats_list stat { $$ = $1; APPEND_G_FIFO($$, create_int_node($2)); } | stat { $$ = NULL; APPEND_G_FIFO($$, create_int_node($1)); } ; stat : T_Clockstats | T_Cryptostats | T_Loopstats | T_Peerstats | T_Rawstats | T_Sysstats | T_Timingstats | T_Protostats ; filegen_option_list : /* empty list */ { $$ = NULL; } | filegen_option_list filegen_option { $$ = $1; APPEND_G_FIFO($$, $2); } ; filegen_option : T_File T_String { if (lex_from_file()) { $$ = create_attr_sval($1, $2); } else { $$ = NULL; YYFREE($2); yyerror("filegen file remote config ignored"); } } | T_Type filegen_type { if (lex_from_file()) { $$ = create_attr_ival($1, $2); } else { $$ = NULL; yyerror("filegen type remote config ignored"); } } | link_nolink { const char *err; if (lex_from_file()) { $$ = create_attr_ival(T_Flag, $1); } else { $$ = NULL; if (T_Link == $1) err = "filegen link remote config ignored"; else err = "filegen nolink remote config ignored"; yyerror(err); } } | enable_disable { $$ = create_attr_ival(T_Flag, $1); } ; link_nolink : T_Link | T_Nolink ; enable_disable : T_Enable | T_Disable ; filegen_type : T_None | T_Pid | T_Day | T_Week | T_Month | T_Year | T_Age ; /* Access Control Commands * ----------------------- */ access_control_command : T_Discard discard_option_list { CONCAT_G_FIFOS(cfgt.discard_opts, $2); } | T_Mru mru_option_list { CONCAT_G_FIFOS(cfgt.mru_opts, $2); } | T_Restrict address restrict_mask res_ippeerlimit ac_flag_list { restrict_node *rn; rn = create_restrict_node($2, $3, $4, $5, FALSE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Restrict T_Default res_ippeerlimit ac_flag_list { restrict_node *rn; rn = create_restrict_node(NULL, NULL, $3, $4, FALSE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Restrict T_Ipv4_flag T_Default res_ippeerlimit ac_flag_list { restrict_node *rn; rn = create_restrict_node( create_address_node( estrdup("0.0.0.0"), AF_INET), create_address_node( estrdup("0.0.0.0"), AF_INET), $4, $5, FALSE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Restrict T_Ipv6_flag T_Default res_ippeerlimit ac_flag_list { restrict_node *rn; rn = create_restrict_node( create_address_node( estrdup("::"), AF_INET6), create_address_node( estrdup("::"), AF_INET6), $4, $5, FALSE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Restrict T_Source res_ippeerlimit ac_flag_list { restrict_node * rn; APPEND_G_FIFO($4, create_attr_ival($2, 1)); rn = create_restrict_node(NULL, NULL, $3, $4, FALSE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Delrestrict ip_address restrict_mask { restrict_node * rn; rn = create_restrict_node($2, $3, -1, NULL, TRUE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } | T_Delrestrict T_Source ip_address { restrict_node * rn; attr_val_fifo * avf; avf = NULL; APPEND_G_FIFO(avf, create_attr_ival($2, 1)); rn = create_restrict_node($3, NULL, -1, avf, TRUE, lex_current()->curpos.nline, lex_current()->curpos.ncol); APPEND_G_FIFO(cfgt.restrict_opts, rn); } ; restrict_mask : /* no mask is allowed */ { $$ = NULL; } | T_Mask ip_address { $$ = $2; } ; res_ippeerlimit : /* empty ippeerlimit defaults to -1 (unlimited) */ { $$ = -1; } | T_Ippeerlimit T_Integer { if (($2 < -1) || ($2 > 100)) { struct FILE_INFO * ip_ctx; ip_ctx = lex_current(); msyslog(LOG_ERR, "Unreasonable ippeerlimit value (%d) in %s line %d, column %d. Using 0.", $2, ip_ctx->fname, ip_ctx->curpos.nline, ip_ctx->curpos.ncol); $2 = 0; } $$ = $2; } ; ac_flag_list : /* empty list is allowed */ { $$ = NULL; } | ac_flag_list access_control_flag { attr_val *av; $$ = $1; av = create_attr_ival($2, 1); APPEND_G_FIFO($$, av); } | ac_flag_list T_Serverresponse T_Fuzz { attr_val *av; $$ = $1; av = create_attr_ival(T_ServerresponseFuzz, 1); APPEND_G_FIFO($$, av); } ; access_control_flag : T_Epeer | T_Flake | T_Ignore | T_Kod | T_Limited | T_Lowpriotrap | T_Mssntp | T_Noepeer | T_Nomodify | T_Nomrulist | T_Nopeer | T_Noquery | T_Noserve | T_Notrap | T_Notrust | T_Ntpport | T_Version ; discard_option_list : discard_option_list discard_option { $$ = $1; APPEND_G_FIFO($$, $2); } | discard_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; discard_option : discard_option_keyword T_Integer { $$ = create_attr_ival($1, $2); } ; discard_option_keyword : T_Average | T_Minimum | T_Monitor ; mru_option_list : mru_option_list mru_option { $$ = $1; APPEND_G_FIFO($$, $2); } | mru_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; mru_option : mru_option_keyword T_Integer { $$ = create_attr_ival($1, $2); } ; mru_option_keyword : T_Incalloc | T_Incmem | T_Initalloc | T_Initmem | T_Maxage | T_Maxdepth | T_Maxmem | T_Mindepth ; /* Fudge Commands * -------------- */ fudge_command : T_Fudge address fudge_factor_list { addr_opts_node *aon; aon = create_addr_opts_node($2, $3); APPEND_G_FIFO(cfgt.fudge, aon); } ; fudge_factor_list : fudge_factor_list fudge_factor { $$ = $1; APPEND_G_FIFO($$, $2); } | fudge_factor { $$ = NULL; APPEND_G_FIFO($$, $1); } ; fudge_factor : fudge_factor_dbl_keyword number { $$ = create_attr_dval($1, $2); } | fudge_factor_bool_keyword boolean { $$ = create_attr_ival($1, $2); } | T_Stratum T_Integer { if ($2 >= 0 && $2 <= 16) { $$ = create_attr_ival($1, $2); } else { $$ = NULL; yyerror("fudge factor: stratum value not in [0..16], ignored"); } } | T_Abbrev T_String { $$ = create_attr_sval($1, $2); } | T_Refid T_String { $$ = create_attr_sval($1, $2); } ; fudge_factor_dbl_keyword : T_Time1 | T_Time2 | T_Minjitter ; fudge_factor_bool_keyword : T_Flag1 | T_Flag2 | T_Flag3 | T_Flag4 ; /* Device Commands * -------------- */ device_command : T_Device address device_item_list { addr_opts_node *aon; aon = create_addr_opts_node($2, $3); APPEND_G_FIFO(cfgt.device, aon); } ; device_item_list : device_item_list device_item { $$ = $1; APPEND_G_FIFO($$, $2); } | device_item { $$ = NULL; APPEND_G_FIFO($$, $1); } ; device_item : device_item_path_keyword T_String { $$ = create_attr_sval($1, $2); } ; device_item_path_keyword : T_TimeData | T_PpsData ; /* rlimit Commands * --------------- */ rlimit_command : T_Rlimit rlimit_option_list { CONCAT_G_FIFOS(cfgt.rlimit, $2); } ; rlimit_option_list : rlimit_option_list rlimit_option { $$ = $1; APPEND_G_FIFO($$, $2); } | rlimit_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; rlimit_option : rlimit_option_keyword T_Integer { $$ = create_attr_ival($1, $2); } ; rlimit_option_keyword : T_Memlock | T_Stacksize | T_Filenum ; /* Command for System Options * -------------------------- */ system_option_command : T_Enable system_option_list { CONCAT_G_FIFOS(cfgt.enable_opts, $2); } | T_Disable system_option_list { CONCAT_G_FIFOS(cfgt.disable_opts, $2); } ; system_option_list : system_option_list system_option { $$ = $1; APPEND_G_FIFO($$, $2); } | system_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; system_option : system_option_flag_keyword { $$ = create_attr_ival(T_Flag, $1); } | system_option_local_flag_keyword { if (lex_from_file()) { $$ = create_attr_ival(T_Flag, $1); } else { char err_str[128]; $$ = NULL; snprintf(err_str, sizeof(err_str), "enable/disable %s remote configuration ignored", keyword($1)); yyerror(err_str); } } ; system_option_flag_keyword : T_Auth | T_Bclient | T_Calibrate | T_Kernel | T_Monitor | T_Ntp ; system_option_local_flag_keyword : T_Mode7 | T_PCEdigest | T_Stats | T_UEcrypto | T_UEcryptonak | T_UEdigest ; /* Tinker Commands * --------------- */ tinker_command : T_Tinker tinker_option_list { CONCAT_G_FIFOS(cfgt.tinker, $2); } ; tinker_option_list : tinker_option_list tinker_option { $$ = $1; APPEND_G_FIFO($$, $2); } | tinker_option { $$ = NULL; APPEND_G_FIFO($$, $1); } ; tinker_option : tinker_option_keyword number { $$ = create_attr_dval($1, $2); } ; tinker_option_keyword : T_Allan | T_Dispersion | T_Freq | T_Huffpuff | T_Panic | T_Step | T_Stepback | T_Stepfwd | T_Stepout | T_Tick ; /* Miscellaneous Commands * ---------------------- */ miscellaneous_command : interface_command | reset_command | misc_cmd_dbl_keyword number { attr_val *av; av = create_attr_dval($1, $2); APPEND_G_FIFO(cfgt.vars, av); } | misc_cmd_int_keyword T_Integer { attr_val *av; av = create_attr_ival($1, $2); APPEND_G_FIFO(cfgt.vars, av); } | misc_cmd_str_keyword T_String { attr_val *av; av = create_attr_sval($1, $2); APPEND_G_FIFO(cfgt.vars, av); } | misc_cmd_str_lcl_keyword T_String { char error_text[64]; attr_val *av; if (lex_from_file()) { av = create_attr_sval($1, $2); APPEND_G_FIFO(cfgt.vars, av); } else { YYFREE($2); snprintf(error_text, sizeof(error_text), "%s remote config ignored", keyword($1)); yyerror(error_text); } } | T_Includefile T_String command { if (!lex_from_file()) { YYFREE($2); /* avoid leak */ yyerror("remote includefile ignored"); break; } if (lex_level() > MAXINCLUDELEVEL) { fprintf(stderr, "getconfig: Maximum include file level exceeded.\n"); msyslog(LOG_ERR, "getconfig: Maximum include file level exceeded."); } else { const char * path = FindConfig($2); /* might return $2! */ if (!lex_push_file(path, "r")) { fprintf(stderr, "getconfig: Couldn't open <%s>\n", path); msyslog(LOG_ERR, "getconfig: Couldn't open <%s>", path); } } YYFREE($2); /* avoid leak */ } | T_Leapfile T_String opt_hash_check { attr_val *av; av = create_attr_sval($1, $2); av->flag = $3; APPEND_G_FIFO(cfgt.vars, av); } | T_End { lex_flush_stack(); } | T_Driftfile drift_parm { /* see drift_parm below for actions */ } | T_Logconfig log_config_list { CONCAT_G_FIFOS(cfgt.logconfig, $2); } | T_Phone string_list { CONCAT_G_FIFOS(cfgt.phone, $2); } | T_PollSkewList pollskew_list { CONCAT_G_FIFOS(cfgt.pollskewlist, $2); } | T_Setvar variable_assign { APPEND_G_FIFO(cfgt.setvar, $2); } | T_Trap ip_address trap_option_list { addr_opts_node *aon; aon = create_addr_opts_node($2, $3); APPEND_G_FIFO(cfgt.trap, aon); } | T_Ttl integer_list { CONCAT_G_FIFOS(cfgt.ttl, $2); } ; misc_cmd_dbl_keyword : T_Broadcastdelay | T_Nonvolatile | T_Tick ; misc_cmd_int_keyword : T_Dscp ; misc_cmd_int_keyword : T_Leapsmearinterval { #ifndef LEAP_SMEAR yyerror("Built without LEAP_SMEAR support."); #endif } ; opt_hash_check : T_Ignorehash { $$ = FALSE; } | T_Checkhash { $$ = TRUE; } | /*EMPTY*/ { $$ = TRUE; } ; misc_cmd_str_keyword : T_Ident ; misc_cmd_str_lcl_keyword : T_Logfile | T_Pidfile | T_Saveconfigdir ; drift_parm : T_String { if (lex_from_file()) { attr_val *av; av = create_attr_sval(T_Driftfile, $1); APPEND_G_FIFO(cfgt.vars, av); } else { YYFREE($1); yyerror("driftfile remote configuration ignored"); } } | T_String T_Double { if (lex_from_file()) { attr_val *av; av = create_attr_sval(T_Driftfile, $1); APPEND_G_FIFO(cfgt.vars, av); av = create_attr_dval(T_WanderThreshold, $2); APPEND_G_FIFO(cfgt.vars, av); msyslog(LOG_WARNING, "'driftfile FILENAME WanderValue' is deprecated, " "please use separate 'driftfile FILENAME' and " "'nonvolatile WanderValue' lines instead."); } else { YYFREE($1); yyerror("driftfile remote configuration ignored"); } } | /* Null driftfile, indicated by empty string "" */ { if (lex_from_file()) { attr_val *av; av = create_attr_sval(T_Driftfile, estrdup("")); APPEND_G_FIFO(cfgt.vars, av); } else { yyerror("driftfile remote configuration ignored"); } } ; pollskew_list : /* empty */ { $$ = NULL; } | pollskew_list pollskew_spec { $$ = append_gen_fifo($1, $2); } ; pollskew_spec : pollskew_cycle T_Integer '|' T_Integer { if ($2 < 0 || $4 < 0) { /* bad numbers */ yyerror("pollskewlist: skew values must be >=0"); destroy_attr_val($1); $1 = NULL; } else if ($1 == NULL) { yyerror("pollskewlist: poll value must be 3-17, inclusive"); } else if ($1->attr <= 0) { /* process default range */ $1->value.r.first = $2; $1->value.r.last = $4; } else if ($2 < (1 << ($1->attr - 1)) && $4 < (1 << ($1->attr - 1))) { $1->value.r.first = $2; $1->value.r.last = $4; } else { yyerror("pollskewlist: randomization limit must be <= half the poll interval"); destroy_attr_val($1); $1 = NULL; } $$ = $1; } ; pollskew_cycle : T_Integer { $$ = ($1 >= NTP_MINPOLL && $1 <= NTP_MAXPOLL) ? create_attr_rval($1, 0, 0) : NULL; } | T_Default { $$ = create_attr_rval(-1, 0, 0); } ; variable_assign : T_String '=' T_String t_default_or_zero { $$ = create_setvar_node($1, $3, $4); } ; t_default_or_zero : T_Default | /* empty, no "default" modifier */ { $$ = 0; } ; trap_option_list : /* empty list */ { $$ = NULL; } | trap_option_list trap_option { $$ = $1; APPEND_G_FIFO($$, $2); } ; trap_option : T_Port T_Integer { $$ = create_attr_ival($1, $2); } | T_Interface ip_address { $$ = create_attr_sval($1, estrdup($2->address)); destroy_address_node($2); } ; log_config_list : log_config_list log_config_command { $$ = $1; APPEND_G_FIFO($$, $2); } | log_config_command { $$ = NULL; APPEND_G_FIFO($$, $1); } ; log_config_command : T_String { char prefix; char * type; switch ($1[0]) { case '+': case '-': case '=': prefix = $1[0]; type = $1 + 1; break; default: prefix = '='; type = $1; } $$ = create_attr_sval(prefix, estrdup(type)); YYFREE($1); } ; interface_command : interface_nic nic_rule_action nic_rule_class { nic_rule_node *nrn; nrn = create_nic_rule_node($3, NULL, $2); APPEND_G_FIFO(cfgt.nic_rules, nrn); } | interface_nic nic_rule_action T_String { nic_rule_node *nrn; nrn = create_nic_rule_node(0, $3, $2); APPEND_G_FIFO(cfgt.nic_rules, nrn); } ; interface_nic : T_Interface | T_Nic ; nic_rule_class : T_All | T_Ipv4 | T_Ipv6 | T_Wildcard ; nic_rule_action : T_Listen | T_Ignore | T_Drop ; reset_command : T_Reset counter_set_list { CONCAT_G_FIFOS(cfgt.reset_counters, $2); } ; counter_set_list : counter_set_list counter_set_keyword { $$ = $1; APPEND_G_FIFO($$, create_int_node($2)); } | counter_set_keyword { $$ = NULL; APPEND_G_FIFO($$, create_int_node($1)); } ; counter_set_keyword : T_Allpeers | T_Auth | T_Ctl | T_Io | T_Mem | T_Sys | T_Timer ; /* Miscellaneous Rules * ------------------- */ integer_list : integer_list T_Integer { $$ = $1; APPEND_G_FIFO($$, create_int_node($2)); } | T_Integer { $$ = NULL; APPEND_G_FIFO($$, create_int_node($1)); } ; integer_list_range : integer_list_range integer_list_range_elt { $$ = $1; APPEND_G_FIFO($$, $2); } | integer_list_range_elt { $$ = NULL; APPEND_G_FIFO($$, $1); } ; integer_list_range_elt : T_Integer { $$ = create_attr_ival('i', $1); } | integer_range ; integer_range : '(' T_Integer T_Ellipsis T_Integer ')' { $$ = create_attr_rval('-', $2, $4); } ; string_list : string_list T_String { $$ = $1; APPEND_G_FIFO($$, create_string_node($2)); } | T_String { $$ = NULL; APPEND_G_FIFO($$, create_string_node($1)); } ; address_list : address_list address { $$ = $1; APPEND_G_FIFO($$, $2); } | address { $$ = NULL; APPEND_G_FIFO($$, $1); } ; boolean : T_Integer { if ($1 != 0 && $1 != 1) { yyerror("Integer value is not boolean (0 or 1). Assuming 1"); $$ = 1; } else { $$ = $1; } } | T_True { $$ = 1; } | T_False { $$ = 0; } ; number : T_Integer { $$ = (double)$1; } | T_Double ; basedate : T_Basedate T_String { $$ = basedate_eval_string($2); YYFREE($2); } /* Simulator Configuration Commands * -------------------------------- */ simulate_command : sim_conf_start '{' sim_init_statement_list sim_server_list '}' { sim_node *sn; sn = create_sim_node($3, $4); APPEND_G_FIFO(cfgt.sim_details, sn); /* Revert from ; to \n for end-of-command */ old_config_style = 1; } ; /* The following is a terrible hack to get the configuration file to * treat newlines as whitespace characters within the simulation. * This is needed because newlines are significant in the rest of the * configuration file. */ sim_conf_start : T_Simulate { old_config_style = 0; } ; sim_init_statement_list : sim_init_statement_list sim_init_statement T_EOC { $$ = $1; APPEND_G_FIFO($$, $2); } | sim_init_statement T_EOC { $$ = NULL; APPEND_G_FIFO($$, $1); } ; sim_init_statement : sim_init_keyword '=' number { $$ = create_attr_dval($1, $3); } ; sim_init_keyword : T_Beep_Delay | T_Sim_Duration ; sim_server_list : sim_server_list sim_server { $$ = $1; APPEND_G_FIFO($$, $2); } | sim_server { $$ = NULL; APPEND_G_FIFO($$, $1); } ; sim_server : sim_server_name '{' sim_server_offset sim_act_list '}' { $$ = ONLY_SIM(create_sim_server($1, $3, $4)); } ; sim_server_offset : T_Server_Offset '=' number T_EOC { $$ = $3; } ; sim_server_name : T_Server '=' address { $$ = $3; } ; sim_act_list : sim_act_list sim_act { $$ = $1; APPEND_G_FIFO($$, $2); } | sim_act { $$ = NULL; APPEND_G_FIFO($$, $1); } ; sim_act : T_Duration '=' number '{' sim_act_stmt_list '}' { $$ = ONLY_SIM(create_sim_script_info($3, $5)); } ; sim_act_stmt_list : sim_act_stmt_list sim_act_stmt T_EOC { $$ = $1; APPEND_G_FIFO($$, $2); } | sim_act_stmt T_EOC { $$ = NULL; APPEND_G_FIFO($$, $1); } ; sim_act_stmt : sim_act_keyword '=' number { $$ = create_attr_dval($1, $3); } ; sim_act_keyword : T_Freq_Offset | T_Wander | T_Jitter | T_Prop_Delay | T_Proc_Delay ; %% void yyerror( const char *msg ) { int retval; struct FILE_INFO * ip_ctx; ip_ctx = lex_current(); ip_ctx->errpos = ip_ctx->tokpos; msyslog(LOG_ERR, "line %d column %d %s", ip_ctx->errpos.nline, ip_ctx->errpos.ncol, msg); if (!lex_from_file()) { /* Save the error message in the correct buffer */ retval = snprintf(remote_config.err_msg + remote_config.err_pos, sizeof remote_config.err_msg - remote_config.err_pos, "column %d %s", ip_ctx->errpos.ncol, msg); /* Increment the value of err_pos */ if (retval > 0) remote_config.err_pos += retval; /* Increment the number of errors */ ++remote_config.no_errors; } } /* * token_name - convert T_ token integers to text * example: token_name(T_Server) returns "T_Server" */ const char * token_name( int token ) { return yytname[YYTRANSLATE(token)]; } /* Initial Testing function -- ignore */ #if 0 int main(int argc, char *argv[]) { ip_file = FOPEN(argv[1], "r"); if (!ip_file) fprintf(stderr, "ERROR!! Could not open file: %s\n", argv[1]); yyparse(); return 0; } #endif