diff --git a/cf-agent/cf-agent.c b/cf-agent/cf-agent.c index a015224bffb..8b951192358 100644 --- a/cf-agent/cf-agent.c +++ b/cf-agent/cf-agent.c @@ -943,6 +943,8 @@ static void KeepPromises(EvalContext *ctx, const Policy *policy, GenericAgentCon static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config) { + assert(config != NULL); + Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_AGENT); if (constraints) { @@ -1302,6 +1304,24 @@ static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericA continue; } + if (StringEqual(cp->lval, CFA_CONTROLBODY[AGENT_CONTROL_REPORT_METATAGS_INCLUDE].lval)) + { + assert(value_type == CF_DATA_TYPE_STRING_LIST); + RlistDestroy(config->agent_specific.agent.report_metatags_include); + config->agent_specific.agent.report_metatags_include = RlistCopy(value); + Log(LOG_LEVEL_VERBOSE, "Setting report_metatags_include"); + continue; + } + + if (StringEqual(cp->lval, CFA_CONTROLBODY[AGENT_CONTROL_REPORT_METATAGS_EXCLUDE].lval)) + { + assert(value_type == CF_DATA_TYPE_STRING_LIST); + RlistDestroy(config->agent_specific.agent.report_metatags_exclude); + config->agent_specific.agent.report_metatags_exclude = RlistCopy(value); + Log(LOG_LEVEL_VERBOSE, "Setting report_metatags_exclude"); + continue; + } + if (StringEqual(cp->lval, CFA_CONTROLBODY[AGENT_CONTROL_EVALUATION_ORDER].lval)) { assert(value_type == CF_DATA_TYPE_STRING); diff --git a/cf-net/cf-net.c b/cf-net/cf-net.c index aaf8c7f4d23..10badcc1754 100644 --- a/cf-net/cf-net.c +++ b/cf-net/cf-net.c @@ -133,7 +133,7 @@ static const char *const HINTS[] = "Enable basic information output", "Minimum TLS version to use", "TLS ciphers to use (comma-separated list)", - "Specify CFEngine protocol to use. Possible values: 'classic', 'tls', 'cookie', 'filestream', 'leech2', 'latest' (default)", + "Specify CFEngine protocol to use. Possible values: 'classic', 'tls', 'cookie', 'filestream', 'leech2', 'transfusion', 'latest' (default)", "Print rsync performance statistics to stderr", NULL }; diff --git a/libcfnet/protocol_version.c b/libcfnet/protocol_version.c index 56049c582c4..034f01be582 100644 --- a/libcfnet/protocol_version.c +++ b/libcfnet/protocol_version.c @@ -41,6 +41,10 @@ ProtocolVersion ParseProtocolVersionPolicy(const char *const s) { return CF_PROTOCOL_LEECH2; } + else if (StringEqual(s, "6") || StringEqual(s, "transfusion")) + { + return CF_PROTOCOL_TRANSFUSION; + } else if (StringEqual(s, "latest")) { return CF_PROTOCOL_LATEST; diff --git a/libcfnet/protocol_version.h b/libcfnet/protocol_version.h index 14d90303056..9ca344e019f 100644 --- a/libcfnet/protocol_version.h +++ b/libcfnet/protocol_version.h @@ -41,10 +41,11 @@ typedef enum CF_PROTOCOL_COOKIE = 3, CF_PROTOCOL_FILESTREAM = 4, CF_PROTOCOL_LEECH2 = 5, + CF_PROTOCOL_TRANSFUSION = 6, } ProtocolVersion; /* We use CF_PROTOCOL_LATEST as the default for new connections. */ -#define CF_PROTOCOL_LATEST CF_PROTOCOL_LEECH2 +#define CF_PROTOCOL_LATEST CF_PROTOCOL_TRANSFUSION static inline const char *ProtocolVersionString(const ProtocolVersion p) { @@ -60,6 +61,8 @@ static inline const char *ProtocolVersionString(const ProtocolVersion p) return "filestream"; case CF_PROTOCOL_LEECH2: return "leech2"; + case CF_PROTOCOL_TRANSFUSION: + return "transfusion"; default: return "undefined"; } @@ -100,6 +103,11 @@ static inline bool ProtocolSupportsLeech2(const ProtocolVersion p) return (p >= CF_PROTOCOL_LEECH2); } +static inline bool ProtocolSupportsTransfusion(const ProtocolVersion p) +{ + return (p >= CF_PROTOCOL_TRANSFUSION); +} + static inline bool ProtocolTerminateCSV(const ProtocolVersion p) { return (p < CF_PROTOCOL_COOKIE); diff --git a/libpromises/cf3.defs.h b/libpromises/cf3.defs.h index b9e79365f61..d9c38ed5c62 100644 --- a/libpromises/cf3.defs.h +++ b/libpromises/cf3.defs.h @@ -498,6 +498,8 @@ typedef enum AGENT_CONTROL_COPYFROM_RESTRICT_KEYS, AGENT_CONTROL_EVALUATION_ORDER, AGENT_CONTROL_DEFAULT_DIRECTORY_CREATE_MODE, + AGENT_CONTROL_REPORT_METATAGS_INCLUDE, + AGENT_CONTROL_REPORT_METATAGS_EXCLUDE, AGENT_CONTROL_NONE } AgentControl; diff --git a/libpromises/generic_agent.c b/libpromises/generic_agent.c index 6cc9f6897c0..4e84a27e06c 100644 --- a/libpromises/generic_agent.c +++ b/libpromises/generic_agent.c @@ -2620,6 +2620,10 @@ GenericAgentConfig *GenericAgentConfigNewDefault(AgentType agent_type, bool tty_ /* Log classes */ config->agent_specific.agent.report_class_log = false; + /* Report class metatags filter (NULL means no filter) */ + config->agent_specific.agent.report_metatags_include = NULL; + config->agent_specific.agent.report_metatags_exclude = NULL; + config->agent_specific.common.no_augments = false; config->agent_specific.common.no_host_specific = false; @@ -2664,6 +2668,8 @@ void GenericAgentConfigDestroy(GenericAgentConfig *config) free(config->agent_specific.agent.bootstrap_host); free(config->agent_specific.agent.bootstrap_ip); free(config->agent_specific.agent.bootstrap_port); + RlistDestroy(config->agent_specific.agent.report_metatags_include); + RlistDestroy(config->agent_specific.agent.report_metatags_exclude); free(config); } } diff --git a/libpromises/generic_agent.h b/libpromises/generic_agent.h index 58f792ab763..a81489530e4 100644 --- a/libpromises/generic_agent.h +++ b/libpromises/generic_agent.h @@ -97,6 +97,8 @@ typedef struct // BODY AGENT CONTROL bool report_class_log; + Rlist *report_metatags_include; + Rlist *report_metatags_exclude; } agent; struct { diff --git a/libpromises/mod_common.c b/libpromises/mod_common.c index b3ce69ae73a..137c464e67d 100644 --- a/libpromises/mod_common.c +++ b/libpromises/mod_common.c @@ -266,7 +266,7 @@ const ConstraintSyntax CFG_CONTROLBODY[COMMON_CONTROL_MAX + 1] = ConstraintSyntaxNewBool("fips_mode", "Activate full FIPS mode restrictions. Default value: false", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewReal("bwlimit", CF_VALRANGE, "Limit outgoing protocol bandwidth in Bytes per second", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewBool("cache_system_functions", "Cache the result of system functions. Default value: true", SYNTAX_STATUS_NORMAL), - ConstraintSyntaxNewOption("protocol_version", "1,classic,2,tls,3,cookie,4,filestream,5,leech2,latest", "CFEngine protocol version to use when connecting to the server. Default: \"latest\"", SYNTAX_STATUS_NORMAL), + ConstraintSyntaxNewOption("protocol_version", "1,classic,2,tls,3,cookie,4,filestream,5,leech2,6,transfusion,latest", "CFEngine protocol version to use when connecting to the server. Default: \"latest\"", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewString("tls_ciphers", "", "List of acceptable ciphers in outgoing TLS connections, defaults to OpenSSL's default. For syntax help see man page for \"openssl ciphers\"", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewString("tls_min_version", "", "Minimum acceptable TLS version for outgoing connections, defaults to OpenSSL's default", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewStringList("package_inventory", ".*", "Name of the package manager used for software inventory management", SYNTAX_STATUS_NORMAL), @@ -325,6 +325,8 @@ const ConstraintSyntax CFA_CONTROLBODY[] = ConstraintSyntaxNewStringList("copyfrom_restrict_keys", ".*", "A list of key hashes to restrict copy_from to", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewString("evaluation_order", "(classic|top_down)", "Order of evaluation of promises of agent", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewString("default_directory_create_mode", ".*", "Default directory create mode (defaults to 0700 if not specified)", SYNTAX_STATUS_NORMAL), + ConstraintSyntaxNewStringList("report_metatags_include", CF_ANYSTRING, "List of regex filters for metatags of classes to be included into reports", SYNTAX_STATUS_NORMAL), + ConstraintSyntaxNewStringList("report_metatags_exclude", CF_ANYSTRING, "List of regex filters for metatags of classes to be excluded from reports", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewNull() }; diff --git a/libpromises/mod_files.c b/libpromises/mod_files.c index fc93b4b155d..8ea14d6bfb1 100644 --- a/libpromises/mod_files.c +++ b/libpromises/mod_files.c @@ -336,7 +336,7 @@ static const ConstraintSyntax copy_from_constraints[] = ConstraintSyntaxNewBool("trustkey", "true/false trust public keys from remote server if previously unknown. Default value: false", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewBool("type_check", "true/false compare file types before copying and require match", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewBool("verify", "true/false verify transferred file by hashing after copy (resource penalty). Default value: false", SYNTAX_STATUS_NORMAL), - ConstraintSyntaxNewOption("protocol_version", "1,classic,2,tls,3,cookie,4,filestream,5,leech2,latest", "CFEngine protocol version to use when connecting to the server. Default: undefined", SYNTAX_STATUS_NORMAL), + ConstraintSyntaxNewOption("protocol_version", "1,classic,2,tls,3,cookie,4,filestream,5,leech2,6,transfusion,latest", "CFEngine protocol version to use when connecting to the server. Default: undefined", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewBool("missing_ok", "true/false Do not treat missing file as an error. Default value: false", SYNTAX_STATUS_NORMAL), ConstraintSyntaxNewNull() }; diff --git a/libpromises/rlist.c b/libpromises/rlist.c index 3b997cfa1cc..ee1ad7b8395 100644 --- a/libpromises/rlist.c +++ b/libpromises/rlist.c @@ -37,6 +37,8 @@ #include #include #include /* IsCf3VarString */ +#include +#include static Rlist *RlistPrependRval(Rlist **start, Rval rval); @@ -1776,3 +1778,15 @@ Rlist *RlistFromContainer(const JsonElement *container) return list; } + +Seq *RlistToStringSeq(const Rlist *list) +{ + Seq *seq = SeqNew(RlistLen(list), free); + + for (const Rlist *rp = list; rp != NULL; rp = rp->next) + { + SeqAppend(seq, xstrdup(RlistScalarValue(rp))); + } + + return seq; +} diff --git a/libpromises/rlist.h b/libpromises/rlist.h index 37d39d88c9c..65b1e299cf3 100644 --- a/libpromises/rlist.h +++ b/libpromises/rlist.h @@ -29,6 +29,7 @@ #include #include #include +#include /* NOTE: an empty Rlist is simply NULL. */ struct Rlist_ @@ -107,6 +108,13 @@ Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_ent Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int max); Rlist *RlistFromContainer(const JsonElement *container); +/** + * @brief Copy the scalar strings of a list into a sequence + * @param list List of scalar strings (NULL is the empty list) + * @return Sequence of copied strings. Destroy with SeqDestroy(). + */ +Seq *RlistToStringSeq(const Rlist *list); + void RlistWrite(Writer *writer, const Rlist *list); Rlist *RlistLast(Rlist *start); void RlistFilter(Rlist **list, bool (*KeepPredicate)(void *item, void *predicate_data), void *predicate_user_data, void (*DestroyItem)(void *item));