%skeleton "lalr1.cc" /* -*- C++ -*- */ %require "3.0" %defines %define parser_class_name {seclang_parser} %define api.token.constructor %define api.value.type variant //%define api.namespace {ModSecurity::yy} %define parse.assert %code requires { # include namespace ModSecurity { namespace Parser { class Driver; } } #include "modsecurity/modsecurity.h" #include "actions/action.h" #include "actions/audit_log.h" #include "actions/ctl_audit_log_parts.h" #include "actions/set_var.h" #include "actions/severity.h" #include "actions/skip_after.h" #include "actions/msg.h" #include "actions/phase.h" #include "actions/log_data.h" #include "actions/redirect.h" #include "actions/rev.h" #include "actions/tag.h" #include "actions/transformations/transformation.h" #include "actions/transformations/none.h" #include "operators/operator.h" #include "src/rule.h" #include "utils/geo_lookup.h" #include "audit_log.h" #include "utils.h" #include "variables/variations/count.h" #include "variables/variations/exclusion.h" #include "variables/duration.h" #include "variables/env.h" #include "variables/highest_severity.h" #include "variables/modsec_build.h" #include "variables/time_day.h" #include "variables/time_epoch.h" #include "variables/time.h" #include "variables/time_hour.h" #include "variables/time_min.h" #include "variables/time_mon.h" #include "variables/time_sec.h" #include "variables/time_wday.h" #include "variables/time_year.h" using ModSecurity::ModSecurity; using ModSecurity::actions::Action; using ModSecurity::actions::CtlAuditLogParts; using ModSecurity::actions::SetVar; using ModSecurity::actions::Severity; using ModSecurity::actions::Tag; using ModSecurity::actions::Redirect; using ModSecurity::actions::Rev; using ModSecurity::actions::Msg; using ModSecurity::actions::Phase; using ModSecurity::actions::transformations::None; using ModSecurity::actions::LogData; using ModSecurity::actions::transformations::Transformation; using ModSecurity::operators::Operator; using ModSecurity::Rule; using ModSecurity::Utils::GeoLookup; using ModSecurity::Variables::Variations::Count; using ModSecurity::Variables::Variations::Exclusion; using ModSecurity::Variables::Duration; using ModSecurity::Variables::Env; using ModSecurity::Variables::HighestSeverity; using ModSecurity::Variables::ModsecBuild; using ModSecurity::Variables::Time; using ModSecurity::Variables::TimeDay; using ModSecurity::Variables::TimeEpoch; using ModSecurity::Variables::TimeHour; using ModSecurity::Variables::TimeMin; using ModSecurity::Variables::TimeMon; using ModSecurity::Variables::TimeSec; using ModSecurity::Variables::TimeWDay; using ModSecurity::Variables::TimeYear; using ModSecurity::Variables::Variable; #define CHECK_VARIATION_DECL \ Variable *var = NULL; \ bool t = false; #define CHECK_VARIATION(a) \ if (var == NULL) { \ if (name.at(0) == std::string(#a).at(0)) { \ name.erase(0, 1); \ t = true ; \ } \ } else { \ t = false; \ } \ if (t) /** * %destructor { code } THING * * %destructor is not working as expected. Apparently it was fixed on a most recent, * version of Bison. We are not interested to limit the usage to this newest version, * thus, we have to deal with memory leak when rules failed to load. Not that big * problem, as we don't really continue when it fails (only for SecRemoteRules). * * Information about destructor: * http://www.gnu.org/software/bison/manual/html_node/Destructor-Decl.html * * Patch: * https://www.mail-archive.com/search?l=bug-bison@gnu.org&q=subject:%22Destructor+miscompilation+with+C%2B%2B+variants%3F%22&o=newest&f=1 */ } // The parsing context. %param { ModSecurity::Parser::Driver& driver } %locations %initial-action { // Initialize the initial location. @$.begin.filename = @$.end.filename = &driver.file; }; %define parse.trace %define parse.error verbose %code { #include "parser/driver.h" } %define api.token.prefix {TOK_} %token END 0 "end of file" COMMA "," SPACE PIPE ; %left SPACE CONFIG_VALUE_RELEVANT_ONLY CONFIG_VALUE_ON CONFIG_VALUE_OFF %token QUOTATION_MARK %token DIRECTIVE %token CONFIG_DIR_REQ_BODY_LIMIT %token CONFIG_DIR_REQ_BODY_NO_FILES_LIMIT %token CONFIG_DIR_REQ_BODY_IN_MEMORY_LIMIT %token CONFIG_DIR_RES_BODY_LIMIT %token CONFIG_DIR_REQ_BODY_LIMIT_ACTION %token CONFIG_DIR_RES_BODY_LIMIT_ACTION %token CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION %token CONFIG_DIR_PCRE_MATCH_LIMIT %token CONGIG_DIR_RESPONSE_BODY_MP %token CONGIG_DIR_SEC_TMP_DIR %token CONGIG_DIR_SEC_DATA_DIR %token CONGIG_DIR_SEC_ARG_SEP %token CONGIG_DIR_SEC_COOKIE_FORMAT %token CONGIG_DIR_SEC_STATUS_ENGINE %token CONFIG_DIR_UNICODE_MAP_FILE %token CONFIG_DIR_RULE_ENG %token CONFIG_DIR_REQ_BODY %token CONFIG_DIR_RES_BODY %token CONFIG_VALUE_ON %token CONFIG_VALUE_OFF %token CONFIG_VALUE_DETC %token CONFIG_VALUE_SERIAL %token CONFIG_VALUE_PARALLEL %token CONFIG_VALUE_RELEVANT_ONLY %token CONFIG_VALUE_PROCESS_PARTIAL %token CONFIG_VALUE_REJECT %token CONFIG_VALUE_ABORT %token CONFIG_VALUE_WARN %token CONFIG_DIR_AUDIT_DIR %token CONFIG_DIR_AUDIT_DIR_MOD %token CONFIG_DIR_AUDIT_ENG %token CONFIG_DIR_AUDIT_FLE_MOD %token CONFIG_DIR_AUDIT_LOG %token CONFIG_DIR_AUDIT_LOG2 %token CONFIG_DIR_AUDIT_LOG_P %token CONFIG_DIR_AUDIT_STS %token CONFIG_DIR_AUDIT_TPE %token CONFIG_COMPONENT_SIG %token CONFIG_DIR_DEBUG_LOG %token CONFIG_DIR_DEBUG_LVL %token CONFIG_DIR_SEC_ACTION %token CONFIG_DIR_SEC_DEFAULT_ACTION %token CONFIG_DIR_SEC_MARKER %token VARIABLE %token RUN_TIME_VAR_DUR %token RUN_TIME_VAR_ENV %token RUN_TIME_VAR_BLD %token RUN_TIME_VAR_HSV %token RUN_TIME_VAR_TIME %token RUN_TIME_VAR_TIME_DAY %token RUN_TIME_VAR_TIME_EPOCH %token RUN_TIME_VAR_TIME_HOUR %token RUN_TIME_VAR_TIME_MIN %token RUN_TIME_VAR_TIME_MON %token RUN_TIME_VAR_TIME_SEC %token RUN_TIME_VAR_TIME_WDAY %token RUN_TIME_VAR_TIME_YEAR %token CONFIG_SEC_REMOTE_RULES_FAIL_ACTION %token CONFIG_DIR_GEO_DB %token OPERATOR %token FREE_TEXT %token ACTION %token ACTION_ACCURACY %token ACTION_REDIRECT %token ACTION_SKIP_AFTER %token ACTION_AUDIT_LOG %token ACTION_SEVERITY %token ACTION_SETVAR %token ACTION_EXPIREVAR %token ACTION_INITCOL %token ACTION_MSG %token ACTION_TAG %token ACTION_REV %token ACTION_VER %token ACTION_MATURITY %token LOG_DATA %token TRANSFORMATION %token ACTION_CTL_AUDIT_ENGINE %token ACTION_CTL_AUDIT_LOG_PARTS %token ACTION_CTL_BDY_JSON %token ACTION_CTL_BDY_XML %token ACTION_CTL_RULE_ENGINE %token ACTION_CTL_FORCE_REQ_BODY_VAR %token CONFIG_SEC_COLLECTION_TIMEOUT %type *> actions %type *> variables %type var %type act %printer { yyoutput << $$; } <*>; %% %start input; input: %empty | input line | SPACE ; line: expression | SPACE expression | expression SPACE ; audit_log: /* SecAuditLogDirMode */ CONFIG_DIR_AUDIT_DIR_MOD { driver.audit_log->setStorageDirMode(strtol($1.c_str(), NULL, 8)); } /* SecAuditLogStorageDir */ | CONFIG_DIR_AUDIT_DIR { driver.audit_log->setStorageDir($1); } /* SecAuditEngine */ | CONFIG_DIR_AUDIT_ENG SPACE CONFIG_VALUE_RELEVANT_ONLY { driver.audit_log->setStatus(ModSecurity::AuditLog::RelevantOnlyAuditLogStatus); } | CONFIG_DIR_AUDIT_ENG SPACE CONFIG_VALUE_OFF { driver.audit_log->setStatus(ModSecurity::AuditLog::OffAuditLogStatus); } | CONFIG_DIR_AUDIT_ENG SPACE CONFIG_VALUE_ON { driver.audit_log->setStatus(ModSecurity::AuditLog::OnAuditLogStatus); } /* SecAuditLogFileMode */ | CONFIG_DIR_AUDIT_FLE_MOD { driver.audit_log->setFileMode(strtol($1.c_str(), NULL, 8)); } /* SecAuditLog2 */ | CONFIG_DIR_AUDIT_LOG2 { driver.audit_log->setFilePath2($1); } /* SecAuditLogParts */ | CONFIG_DIR_AUDIT_LOG_P { driver.audit_log->setParts($1); } /* SecAuditLog */ | CONFIG_DIR_AUDIT_LOG { driver.audit_log->setFilePath1($1); } /* SecAuditLogRelevantStatus */ | CONFIG_DIR_AUDIT_STS { std::string relevant_status($1); relevant_status.pop_back(); relevant_status.erase(0, 1); driver.audit_log->setRelevantStatus(relevant_status); } /* SecAuditLogType */ | CONFIG_DIR_AUDIT_TPE SPACE CONFIG_VALUE_SERIAL { driver.audit_log->setType(ModSecurity::AuditLog::SerialAuditLogType); } | CONFIG_DIR_AUDIT_TPE SPACE CONFIG_VALUE_PARALLEL { driver.audit_log->setType(ModSecurity::AuditLog::ParallelAuditLogType); } ; expression: audit_log | DIRECTIVE SPACE variables SPACE OPERATOR SPACE QUOTATION_MARK actions SPACE QUOTATION_MARK | DIRECTIVE SPACE variables SPACE OPERATOR SPACE QUOTATION_MARK actions QUOTATION_MARK { Operator *op = Operator::instantiate($5); const char *error = NULL; if (op->init(&error) == false) { driver.parserError << error; YYERROR; } Rule *rule = new Rule( /* op */ op, /* variables */ $3, /* actions */ $8 ); if (driver.addSecRule(rule) == false) { YYERROR; } } | DIRECTIVE SPACE variables SPACE FREE_TEXT SPACE QUOTATION_MARK actions SPACE QUOTATION_MARK | DIRECTIVE SPACE variables SPACE FREE_TEXT SPACE QUOTATION_MARK actions QUOTATION_MARK { Operator *op = Operator::instantiate("\"@rx " + $5 + "\""); const char *error = NULL; if (op->init(&error) == false) { driver.parserError << error; YYERROR; } Rule *rule = new Rule( /* op */ op, /* variables */ $3, /* actions */ $8 ); driver.addSecRule(rule); } | CONFIG_DIR_SEC_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK { Rule *rule = new Rule( /* op */ NULL, /* variables */ NULL, /* actions */ $4 ); driver.addSecAction(rule); } | CONFIG_DIR_SEC_ACTION SPACE actions { Rule *rule = new Rule( /* op */ NULL, /* variables */ NULL, /* actions */ $3 ); driver.addSecAction(rule); } | CONFIG_DIR_SEC_DEFAULT_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK { std::vector *actions = $4; std::vector checkedActions; int definedPhase = -1; int secRuleDefinedPhase = -1; for (Action *a : *actions) { Phase *phase = dynamic_cast(a); if (phase != NULL) { definedPhase = phase->phase; secRuleDefinedPhase = phase->m_secRulesPhase; } else if (a->action_kind == Action::RunTimeOnlyIfMatchKind || a->action_kind == Action::RunTimeBeforeMatchAttemptKind) { None *none = dynamic_cast(a); if (none != NULL) { driver.parserError << "The transformation none is not suitable to be part of the SecDefaultActions"; YYERROR; } checkedActions.push_back(a); } else { driver.parserError << "The action '" << a->action << "' is not suitable to be part of the SecDefaultActions"; YYERROR; } } if (definedPhase == -1) { definedPhase = ModSecurity::ModSecurity::Phases::RequestHeadersPhase; } if (!driver.defaultActions[definedPhase].empty()) { driver.parserError << "SecDefaultActions can only be placed once per phase and configuration context. Phase " << secRuleDefinedPhase << " was informed already."; YYERROR; } for (Action *a : checkedActions) { driver.defaultActions[definedPhase].push_back(a); } } | CONFIG_DIR_SEC_MARKER { driver.addSecMarker($1); } | CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_OFF { driver.secRuleEngine = ModSecurity::Rules::DisabledRuleEngine; } | CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_ON { driver.secRuleEngine = ModSecurity::Rules::EnabledRuleEngine; } | CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_DETC { driver.secRuleEngine = ModSecurity::Rules::DetectionOnlyRuleEngine; } | CONFIG_DIR_REQ_BODY SPACE CONFIG_VALUE_ON { driver.secRequestBodyAccess = true; } | CONFIG_DIR_REQ_BODY SPACE CONFIG_VALUE_OFF { driver.secRequestBodyAccess = false; } | CONFIG_DIR_RES_BODY SPACE CONFIG_VALUE_ON { driver.secResponseBodyAccess = true; } | CONFIG_DIR_RES_BODY SPACE CONFIG_VALUE_OFF { driver.secResponseBodyAccess = false; } | CONFIG_COMPONENT_SIG { driver.components.push_back($1); } /* Debug log: start */ | CONFIG_DIR_DEBUG_LVL { if (driver.m_debugLog != NULL) { driver.m_debugLog->setDebugLogLevel(atoi($1.c_str())); } else { driver.parserError << "Internal error, there is no DebugLog "; driver.parserError << "object associated with the driver class"; YYERROR; } } | CONFIG_DIR_DEBUG_LOG { if (driver.m_debugLog != NULL) { driver.m_debugLog->setDebugLogFile($1); } else { driver.parserError << "Internal error, there is no DebugLog "; driver.parserError << "object associated with the driver class"; YYERROR; } } /* Debug log: end */ | CONFIG_DIR_GEO_DB { GeoLookup::getInstance().setDataBase($1); } /* Body limits */ | CONFIG_DIR_REQ_BODY_LIMIT { driver.requestBodyLimit = atoi($1.c_str()); } | CONFIG_DIR_REQ_BODY_NO_FILES_LIMIT { driver.requestBodyNoFilesLimit = atoi($1.c_str()); } | CONFIG_DIR_REQ_BODY_IN_MEMORY_LIMIT { driver.requestBodyInMemoryLimit = atoi($1.c_str()); } | CONFIG_DIR_RES_BODY_LIMIT { driver.responseBodyLimit = atoi($1.c_str()); } | CONFIG_DIR_REQ_BODY_LIMIT_ACTION SPACE CONFIG_VALUE_PROCESS_PARTIAL { driver.requestBodyLimitAction = ModSecurity::Rules::BodyLimitAction::ProcessPartialBodyLimitAction; } | CONFIG_DIR_REQ_BODY_LIMIT_ACTION SPACE CONFIG_VALUE_REJECT { driver.requestBodyLimitAction = ModSecurity::Rules::BodyLimitAction::RejectBodyLimitAction; } | CONFIG_DIR_RES_BODY_LIMIT_ACTION SPACE CONFIG_VALUE_PROCESS_PARTIAL { driver.responseBodyLimitAction = ModSecurity::Rules::BodyLimitAction::ProcessPartialBodyLimitAction; } | CONFIG_DIR_RES_BODY_LIMIT_ACTION SPACE CONFIG_VALUE_REJECT { driver.responseBodyLimitAction = ModSecurity::Rules::BodyLimitAction::RejectBodyLimitAction; } | CONFIG_SEC_REMOTE_RULES_FAIL_ACTION SPACE CONFIG_VALUE_ABORT { driver.remoteRulesActionOnFailed = Rules::OnFailedRemoteRulesAction::AbortOnFailedRemoteRulesAction; } | CONFIG_SEC_REMOTE_RULES_FAIL_ACTION SPACE CONFIG_VALUE_WARN { driver.remoteRulesActionOnFailed = Rules::OnFailedRemoteRulesAction::WarnOnFailedRemoteRulesAction; } | CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION | CONFIG_DIR_PCRE_MATCH_LIMIT | CONGIG_DIR_RESPONSE_BODY_MP | CONGIG_DIR_SEC_TMP_DIR | CONGIG_DIR_SEC_DATA_DIR | CONGIG_DIR_SEC_ARG_SEP | CONGIG_DIR_SEC_COOKIE_FORMAT | CONGIG_DIR_SEC_STATUS_ENGINE | CONFIG_DIR_UNICODE_MAP_FILE | CONFIG_SEC_COLLECTION_TIMEOUT { } ; variables: variables PIPE var { std::vector *v = $1; v->push_back($3); $$ = $1; } | var { std::vector *variables = new std::vector; variables->push_back($1); $$ = variables; } ; var: VARIABLE { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new Variable(name)); } CHECK_VARIATION(!) { var = new Exclusion(new Variable(name)); } if (!var) { var = new Variable(name); } $$ = var; } | RUN_TIME_VAR_DUR { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new Duration(name)); } CHECK_VARIATION(!) { var = new Exclusion(new Duration(name)); } if (!var) { var = new Duration(name); } $$ = var; } | RUN_TIME_VAR_ENV { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new Env(name)); } CHECK_VARIATION(!) { var = new Exclusion(new Env(name)); } if (!var) { var = new Env(name); } $$ = var; } | RUN_TIME_VAR_BLD { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new ModsecBuild(name)); } CHECK_VARIATION(!) { var = new Exclusion(new ModsecBuild(name)); } if (!var) { var = new ModsecBuild(name); } $$ = var; } | RUN_TIME_VAR_HSV { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new HighestSeverity(name)); } CHECK_VARIATION(!) { var = new Exclusion(new HighestSeverity(name)); } if (!var) { var = new HighestSeverity(name); } $$ = var; } | RUN_TIME_VAR_TIME { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new Time(name)); } CHECK_VARIATION(!) { var = new Exclusion(new Time(name)); } if (!var) { var = new Time(name); } $$ = var; } | RUN_TIME_VAR_TIME_DAY { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeDay(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeDay(name)); } if (!var) { var = new TimeDay(name); } $$ = var; } | RUN_TIME_VAR_TIME_EPOCH { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeEpoch(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeEpoch(name)); } if (!var) { var = new TimeEpoch(name); } $$ = var; } | RUN_TIME_VAR_TIME_HOUR { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeHour(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeHour(name)); } if (!var) { var = new TimeHour(name); } $$ = var; } | RUN_TIME_VAR_TIME_MIN { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeMin(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeMin(name)); } if (!var) { var = new TimeMin(name); } $$ = var; } | RUN_TIME_VAR_TIME_MON { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeMon(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeMon(name)); } if (!var) { var = new TimeMon(name); } $$ = var; } | RUN_TIME_VAR_TIME_SEC { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeSec(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeSec(name)); } if (!var) { var = new TimeSec(name); } $$ = var; } | RUN_TIME_VAR_TIME_WDAY { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeWDay(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeWDay(name)); } if (!var) { var = new TimeWDay(name); } $$ = var; } | RUN_TIME_VAR_TIME_YEAR { std::string name($1); CHECK_VARIATION_DECL CHECK_VARIATION(&) { var = new Count(new TimeYear(name)); } CHECK_VARIATION(!) { var = new Exclusion(new TimeYear(name)); } if (!var) { var = new TimeYear(name); } $$ = var; } ; act: ACTION { std::string error; $$ = Action::instantiate($1); if ($$->init(&error) == false) { driver.parserError << error; YYERROR; } } | ACTION_INITCOL { $$ = Action::instantiate($1); } | TRANSFORMATION { $$ = Transformation::instantiate($1); } | ACTION_ACCURACY { $$ = Action::instantiate($1); } | ACTION_REDIRECT { $$ = new Redirect($1); } | ACTION_SEVERITY { $$ = new Severity($1); } | ACTION_EXPIREVAR { $$ = Action::instantiate($1); } | ACTION_SETVAR { std::string error; SetVar *setVar = new SetVar($1); if (setVar->init(&error) == false) { driver.parserError << error; YYERROR; } $$ = setVar; } | ACTION_SKIP_AFTER { $$ = new ModSecurity::actions::SkipAfter($1); } | ACTION_AUDIT_LOG { $$ = new ModSecurity::actions::AuditLog($1); } | LOG_DATA { $$ = new LogData($1); } | ACTION_MSG { $$ = new Msg($1); } | ACTION_TAG { $$ = new Tag($1); } | ACTION_REV { $$ = new Rev($1); } | ACTION_VER { $$ = Action::instantiate($1); } | ACTION_MATURITY { $$ = Action::instantiate($1); } | ACTION_CTL_BDY_XML { /* not ready yet. */ $$ = Action::instantiate($1); } | ACTION_CTL_BDY_JSON { /* not ready yet. */ $$ = Action::instantiate($1); } | ACTION_CTL_AUDIT_LOG_PARTS { $$ = new CtlAuditLogParts($1); } | ACTION_CTL_FORCE_REQ_BODY_VAR CONFIG_VALUE_ON { $$ = Action::instantiate($1); } | ACTION_CTL_FORCE_REQ_BODY_VAR CONFIG_VALUE_OFF { $$ = Action::instantiate($1); } | ACTION_CTL_RULE_ENGINE CONFIG_VALUE_ON { $$ = Action::instantiate($1); } | ACTION_CTL_RULE_ENGINE CONFIG_VALUE_OFF { $$ = Action::instantiate($1); } | ACTION_CTL_RULE_ENGINE CONFIG_VALUE_DETC { $$ = Action::instantiate($1); } | ACTION_CTL_AUDIT_ENGINE CONFIG_VALUE_ON { $$ = Action::instantiate($1); } | ACTION_CTL_AUDIT_ENGINE CONFIG_VALUE_OFF { $$ = Action::instantiate($1); } | ACTION_CTL_AUDIT_ENGINE CONFIG_VALUE_RELEVANT_ONLY { $$ = Action::instantiate($1); } ; actions: actions COMMA SPACE act { std::vector *a = $1; a->push_back($4); $$ = $1; } | actions COMMA act { std::vector *a = $1; a->push_back($3); $$ = $1; } | SPACE act { std::vector *a = new std::vector; a->push_back($2); $$ = a; } | act { std::vector *a = new std::vector; a->push_back($1); $$ = a; } ; %% void yy::seclang_parser::error (const location_type& l, const std::string& m) { driver.error (l, m); }