1 /*
2   Copyright 2021 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 /* This is a root node in the syntax tree */
26 
27 #include <mod_common.h>
28 #include <mod_custom.h>
29 
30 #include <mod_environ.h>
31 #include <mod_outputs.h>
32 #include <mod_access.h>
33 #include <mod_storage.h>
34 #include <mod_databases.h>
35 #include <mod_packages.h>
36 #include <mod_report.h>
37 #include <mod_files.h>
38 #include <mod_exec.h>
39 #include <mod_methods.h>
40 #include <mod_process.h>
41 #include <mod_services.h>
42 #include <mod_measurement.h>
43 #include <mod_knowledge.h>
44 #include <mod_users.h>
45 
46 #include <conversion.h>
47 #include <policy.h>
48 #include <syntax.h>
49 
50 #define CF_LOGRANGE    "stdout|udp_syslog|(\042?[a-zA-Z]:\\\\.*)|(/.*)"
51 #define CF_FACILITY "LOG_USER,LOG_DAEMON,LOG_LOCAL0,LOG_LOCAL1,LOG_LOCAL2,LOG_LOCAL3,LOG_LOCAL4,LOG_LOCAL5,LOG_LOCAL6,LOG_LOCAL7"
52 
53 static const char *const POLICY_ERROR_VARS_CONSTRAINT_DUPLICATE_TYPE =
54     "Variable contains existing data type contstraint %s, tried to "
55     "redefine with %s";
56 static const char *const POLICY_ERROR_VARS_PROMISER_NUMERICAL =
57     "Variable promises cannot have a purely numerical name (promiser)";
58 static const char *const POLICY_ERROR_VARS_PROMISER_INVALID =
59     "Variable promise is using an invalid name (promiser)";
60 static const char *const POLICY_ERROR_CLASSES_PROMISER_NUMERICAL =
61     "Classes promises cannot have a purely numerical name (promiser)";
62 
ActionCheck(const Body * body,Seq * errors)63 static bool ActionCheck(const Body *body, Seq *errors)
64 {
65     bool success = true;
66 
67     if (BodyHasConstraint(body, "log_kept")
68         || BodyHasConstraint(body, "log_repaired")
69         || BodyHasConstraint(body, "log_failed"))
70     {
71         if (!BodyHasConstraint(body, "log_string"))
72         {
73             SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_BODY, body, "An action body with log_kept, log_repaired or log_failed is required to have a log_string attribute"));
74             success = false;
75         }
76     }
77 
78     return success;
79 }
80 
81 static const ConstraintSyntax action_constraints[] =
82 {
83     CONSTRAINT_SYNTAX_GLOBAL,
84     ConstraintSyntaxNewOption("action_policy", "fix,warn,nop", "Whether to repair or report about non-kept promises", SYNTAX_STATUS_NORMAL),
85     ConstraintSyntaxNewInt("ifelapsed", CF_VALRANGE, "Number of minutes before next allowed assessment of promise. Default value: control body value", SYNTAX_STATUS_NORMAL),
86     ConstraintSyntaxNewInt("expireafter", CF_VALRANGE, "Number of minutes before a repair action is interrupted and retried. Default value: control body value", SYNTAX_STATUS_NORMAL),
87     ConstraintSyntaxNewString("log_string", "", "A message to be written to the log when a promise verification leads to a repair", SYNTAX_STATUS_NORMAL),
88     ConstraintSyntaxNewOption("log_level", "inform,verbose,error,log", "The reporting level sent to syslog", SYNTAX_STATUS_NORMAL),
89     ConstraintSyntaxNewString("log_kept", CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger", SYNTAX_STATUS_NORMAL),
90     ConstraintSyntaxNewOption("log_priority", "emergency,alert,critical,error,warning,notice,info,debug","The priority level of the log message, as interpreted by a syslog server", SYNTAX_STATUS_NORMAL),
91     ConstraintSyntaxNewString("log_repaired", CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger", SYNTAX_STATUS_NORMAL),
92     ConstraintSyntaxNewString("log_failed", CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger", SYNTAX_STATUS_NORMAL),
93     ConstraintSyntaxNewReal("value_kept", CF_REALRANGE, "A real number value attributed to keeping this promise", SYNTAX_STATUS_REMOVED),
94     ConstraintSyntaxNewReal("value_repaired", CF_REALRANGE, "A real number value attributed to reparing this promise", SYNTAX_STATUS_REMOVED),
95     ConstraintSyntaxNewReal("value_notkept", CF_REALRANGE, "A real number value (possibly negative) attributed to not keeping this promise", SYNTAX_STATUS_REMOVED),
96     ConstraintSyntaxNewBool("audit", "true/false switch for detailed audit records of this promise. Default value: false", SYNTAX_STATUS_NORMAL),
97     ConstraintSyntaxNewBool("background", "true/false switch for parallelizing the promise repair. Default value: false", SYNTAX_STATUS_NORMAL),
98     ConstraintSyntaxNewOption("report_level", "inform,verbose,error,log", "The reporting level for standard output for this promise. Default value: none", SYNTAX_STATUS_NORMAL),
99     ConstraintSyntaxNewString("measurement_class", "", "If set performance will be measured and recorded under this identifier", SYNTAX_STATUS_NORMAL),
100     ConstraintSyntaxNewNull()
101 };
102 
103 static const BodySyntax action_body = BodySyntaxNew("action", action_constraints, ActionCheck, SYNTAX_STATUS_NORMAL);
104 
105 static const ConstraintSyntax classes_constraints[] =
106 {
107     CONSTRAINT_SYNTAX_GLOBAL,
108     ConstraintSyntaxNewOption("scope", "namespace,bundle", "Scope of the contexts set by this body", SYNTAX_STATUS_NORMAL),
109     ConstraintSyntaxNewStringList("promise_repaired", CF_IDRANGE, "A list of classes to be defined globally", SYNTAX_STATUS_NORMAL),
110     ConstraintSyntaxNewStringList("repair_failed", CF_IDRANGE, "A list of classes to be defined globally", SYNTAX_STATUS_NORMAL),
111     ConstraintSyntaxNewStringList("repair_denied", CF_IDRANGE, "A list of classes to be defined globally", SYNTAX_STATUS_NORMAL),
112     ConstraintSyntaxNewStringList("repair_timeout", CF_IDRANGE, "A list of classes to be defined globally", SYNTAX_STATUS_NORMAL),
113     ConstraintSyntaxNewStringList("promise_kept", CF_IDRANGE, "A list of classes to be defined globally", SYNTAX_STATUS_NORMAL),
114     ConstraintSyntaxNewStringList("cancel_kept", CF_IDRANGE, "A list of classes to be cancelled if the promise is kept", SYNTAX_STATUS_NORMAL),
115     ConstraintSyntaxNewStringList("cancel_repaired", CF_IDRANGE, "A list of classes to be cancelled if the promise is repaired", SYNTAX_STATUS_NORMAL),
116     ConstraintSyntaxNewStringList("cancel_notkept", CF_IDRANGE, "A list of classes to be cancelled if the promise is not kept for any reason", SYNTAX_STATUS_NORMAL),
117     ConstraintSyntaxNewStringList("kept_returncodes", CF_INTLISTRANGE, "A list of return codes indicating a kept command-related promise", SYNTAX_STATUS_NORMAL),
118     ConstraintSyntaxNewStringList("repaired_returncodes", CF_INTLISTRANGE,"A list of return codes indicating a repaired command-related promise", SYNTAX_STATUS_NORMAL),
119     ConstraintSyntaxNewStringList("failed_returncodes", CF_INTLISTRANGE, "A list of return codes indicating a failed command-related promise", SYNTAX_STATUS_NORMAL),
120     ConstraintSyntaxNewInt("persist_time", CF_VALRANGE, "A number of minutes the specified classes should remain active", SYNTAX_STATUS_NORMAL),
121     ConstraintSyntaxNewOption("timer_policy", "absolute,reset", "Whether a persistent class restarts its counter when rediscovered. Default value: reset", SYNTAX_STATUS_NORMAL),
122     ConstraintSyntaxNewNull()
123 };
124 
125 static const BodySyntax classes_body = BodySyntaxNew("classes", classes_constraints, NULL, SYNTAX_STATUS_NORMAL);
126 
127 const ConstraintSyntax CF_VARBODY[] =
128 {
129     ConstraintSyntaxNewString("string", "", "A scalar string", SYNTAX_STATUS_NORMAL),
130     ConstraintSyntaxNewInt("int", CF_INTRANGE, "A scalar integer", SYNTAX_STATUS_NORMAL),
131     ConstraintSyntaxNewReal("real", CF_REALRANGE, "A scalar real number", SYNTAX_STATUS_NORMAL),
132     ConstraintSyntaxNewStringList("slist", "", "A list of scalar strings", SYNTAX_STATUS_NORMAL),
133     ConstraintSyntaxNewIntList("ilist", "A list of integers", SYNTAX_STATUS_NORMAL),
134     ConstraintSyntaxNewRealList("rlist", "A list of real numbers", SYNTAX_STATUS_NORMAL),
135     ConstraintSyntaxNewContainer("data", "A data container", SYNTAX_STATUS_NORMAL),
136     ConstraintSyntaxNewOption("policy", "free,overridable,constant,ifdefined", "The policy for (dis)allowing (re)definition of variables", SYNTAX_STATUS_NORMAL),
137     ConstraintSyntaxNewNull()
138 };
139 
CheckIdentifierNotPurelyNumerical(const char * identifier)140 static bool CheckIdentifierNotPurelyNumerical(const char *identifier)
141 {
142     if (*identifier == '\0')
143     {
144         return true;
145     }
146 
147     for (const char *check = identifier; *check != '\0' && check - identifier < CF_BUFSIZE; check++)
148     {
149         if (!isdigit(*check))
150         {
151             return true;
152         }
153     }
154 
155     return false;
156 }
157 
VarsParseTreeCheck(const Promise * pp,Seq * errors)158 static bool VarsParseTreeCheck(const Promise *pp, Seq *errors)
159 {
160     bool success = true;
161 
162     if (!CheckIdentifierNotPurelyNumerical(pp->promiser))
163     {
164         SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_PROMISE, pp,
165                                          POLICY_ERROR_VARS_PROMISER_NUMERICAL));
166         success = false;
167     }
168 
169     if (!CheckParseVariableName(pp->promiser))
170     {
171         SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_PROMISE, pp,
172                                          POLICY_ERROR_VARS_PROMISER_INVALID));
173         success = false;
174     }
175 
176     // ensure variables are declared with only one type.
177     {
178         char *data_type = NULL;
179 
180         for (size_t i = 0; i < SeqLength(pp->conlist); i++)
181         {
182             Constraint *cp = SeqAt(pp->conlist, i);
183 
184             if (DataTypeFromString(cp->lval) != CF_DATA_TYPE_NONE)
185             {
186                 if (data_type != NULL)
187                 {
188                     SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_CONSTRAINT, cp,
189                                                      POLICY_ERROR_VARS_CONSTRAINT_DUPLICATE_TYPE,
190                                                      data_type, cp->lval));
191                     success = false;
192                 }
193                 data_type = cp->lval;
194             }
195         }
196     }
197 
198     return success;
199 }
200 
201 const ConstraintSyntax CF_METABODY[] =
202 {
203     ConstraintSyntaxNewString("string", "", "A scalar string", SYNTAX_STATUS_NORMAL),
204     ConstraintSyntaxNewStringList("slist", "", "A list of scalar strings", SYNTAX_STATUS_NORMAL),
205     ConstraintSyntaxNewContainer("data", "A data container", SYNTAX_STATUS_NORMAL),
206     ConstraintSyntaxNewNull()
207 };
208 
209 const ConstraintSyntax CF_DEFAULTSBODY[] =
210 {
211     ConstraintSyntaxNewString("if_match_regex", "", "If this regular expression matches the current value of the variable, replace it with default", SYNTAX_STATUS_NORMAL),
212     ConstraintSyntaxNewString("string", "", "A scalar string", SYNTAX_STATUS_NORMAL),
213     ConstraintSyntaxNewStringList("slist", "", "A list of scalar strings", SYNTAX_STATUS_NORMAL),
214     ConstraintSyntaxNewNull()
215 };
216 
217 
218 const ConstraintSyntax CF_CLASSBODY[] =
219 {
220     ConstraintSyntaxNewOption("scope", "namespace,bundle", "Scope of the class set by this promise", SYNTAX_STATUS_NORMAL),
221     ConstraintSyntaxNewContextList("and", "Combine class sources with AND", SYNTAX_STATUS_NORMAL),
222     ConstraintSyntaxNewRealList("dist", "Generate a probabilistic class distribution (from strategies in cfengine 2)", SYNTAX_STATUS_NORMAL),
223     ConstraintSyntaxNewContext("expression", "Evaluate string expression of classes in normal form", SYNTAX_STATUS_NORMAL),
224     ConstraintSyntaxNewContextList("or", "Combine class sources with inclusive OR", SYNTAX_STATUS_NORMAL),
225     ConstraintSyntaxNewInt("persistence", CF_VALRANGE, "Make the class persistent (cached) to avoid reevaluation, time in minutes", SYNTAX_STATUS_NORMAL),
226     ConstraintSyntaxNewContext("not", "Evaluate the negation of string expression in normal form", SYNTAX_STATUS_NORMAL),
227     ConstraintSyntaxNewContextList("select_class", "Select one of the named list of classes to define based on host identity. Default value: random_selection", SYNTAX_STATUS_NORMAL),
228     ConstraintSyntaxNewContextList("xor", "Combine class sources with XOR", SYNTAX_STATUS_NORMAL),
229     ConstraintSyntaxNewNull()
230 };
231 
ClassesParseTreeCheck(const Promise * pp,Seq * errors)232 static bool ClassesParseTreeCheck(const Promise *pp, Seq *errors)
233 {
234     bool success = true;
235 
236     if (!CheckIdentifierNotPurelyNumerical(pp->promiser))
237     {
238         SeqAppend(errors, PolicyErrorNew(POLICY_ELEMENT_TYPE_PROMISE, pp,
239                                          POLICY_ERROR_CLASSES_PROMISER_NUMERICAL));
240         success = false;
241     }
242 
243     return success;
244 }
245 
246 const ConstraintSyntax CFG_CONTROLBODY[COMMON_CONTROL_MAX + 1] =
247 {
248     ConstraintSyntaxNewStringList("bundlesequence", ".*", "List of promise bundles to verify in order", SYNTAX_STATUS_NORMAL),
249     ConstraintSyntaxNewStringList("goal_patterns", "", "A list of regular expressions that match promisees/topics considered to be organizational goals", SYNTAX_STATUS_NORMAL),
250     ConstraintSyntaxNewBool("ignore_missing_bundles", "If any bundles in the bundlesequence do not exist, ignore and continue. Default value: false", SYNTAX_STATUS_NORMAL),
251     ConstraintSyntaxNewBool("ignore_missing_inputs", "If any input files do not exist, ignore and continue. Default value: false", SYNTAX_STATUS_NORMAL),
252     ConstraintSyntaxNewStringList("inputs", ".*", "List of additional filenames to parse for promises", SYNTAX_STATUS_NORMAL),
253     ConstraintSyntaxNewString("version", "", "Scalar version string for this configuration", SYNTAX_STATUS_NORMAL),
254     ConstraintSyntaxNewInt("lastseenexpireafter", CF_VALRANGE, "Number of minutes after which last-seen entries are purged. Default value: one week", SYNTAX_STATUS_NORMAL),
255     ConstraintSyntaxNewString("output_prefix", "", "The string prefix for standard output", SYNTAX_STATUS_NORMAL),
256     ConstraintSyntaxNewString("domain", ".*", "Specify the domain name for this host", SYNTAX_STATUS_NORMAL),
257     ConstraintSyntaxNewBool("require_comments", "Warn about promises that do not have comment documentation. Default value: false", SYNTAX_STATUS_NORMAL),
258     ConstraintSyntaxNewInt("host_licenses_paid", CF_VALRANGE, "This promise is deprecated since CFEngine version 3.1 and is ignored. Default value: 25", SYNTAX_STATUS_REMOVED),
259     ConstraintSyntaxNewContextList("site_classes", "A list of classes that will represent geographical site locations for hosts. These should be defined elsewhere in the configuration in a classes promise.", SYNTAX_STATUS_NORMAL),
260     ConstraintSyntaxNewString("syslog_host", CF_IPRANGE, "The name or address of a host to which syslog messages should be sent directly by UDP. Default value: localhost", SYNTAX_STATUS_NORMAL),
261     ConstraintSyntaxNewInt("syslog_port", CF_VALRANGE, "The port number of a UDP syslog service. Default value: 514", SYNTAX_STATUS_NORMAL),
262     ConstraintSyntaxNewString("system_log_level", "(critical|error|warning|notice|info)", "Minimum system log level of messages that should be logged to system log", SYNTAX_STATUS_NORMAL),
263     ConstraintSyntaxNewBool("fips_mode", "Activate full FIPS mode restrictions. Default value: false", SYNTAX_STATUS_NORMAL),
264     ConstraintSyntaxNewReal("bwlimit", CF_VALRANGE, "Limit outgoing protocol bandwidth in Bytes per second", SYNTAX_STATUS_NORMAL),
265     ConstraintSyntaxNewBool("cache_system_functions", "Cache the result of system functions. Default value: true", SYNTAX_STATUS_NORMAL),
266     ConstraintSyntaxNewOption("protocol_version", "0,undefined,1,classic,2,latest", "CFEngine protocol version to use when connecting to the server. Default: \"latest\"", SYNTAX_STATUS_NORMAL),
267     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),
268     ConstraintSyntaxNewString("tls_min_version", "", "Minimum acceptable TLS version for outgoing connections, defaults to OpenSSL's default", SYNTAX_STATUS_NORMAL),
269     ConstraintSyntaxNewStringList("package_inventory", ".*", "Name of the package manager used for software inventory management", SYNTAX_STATUS_NORMAL),
270     ConstraintSyntaxNewString("package_module", ".*", "Name of the default package manager", SYNTAX_STATUS_NORMAL),
271     ConstraintSyntaxNewNull()
272 };
273 
274 const ConstraintSyntax CFA_CONTROLBODY[] =
275 {
276     ConstraintSyntaxNewStringList("abortclasses", ".*", "A list of classes which if defined in an agent bundle lead to termination of cf-agent", SYNTAX_STATUS_NORMAL),
277     ConstraintSyntaxNewStringList("abortbundleclasses", ".*", "A list of classes which if defined lead to termination of current bundle", SYNTAX_STATUS_NORMAL),
278     ConstraintSyntaxNewStringList("addclasses", ".*", "A list of classes to be defined always in the current context", SYNTAX_STATUS_NORMAL),
279     ConstraintSyntaxNewStringList("agentaccess", ".*", "A list of user names allowed to execute cf-agent", SYNTAX_STATUS_NORMAL),
280     ConstraintSyntaxNewOption("agentfacility", CF_FACILITY, "The syslog facility for cf-agent. Default value: LOG_USER", SYNTAX_STATUS_NORMAL),
281     ConstraintSyntaxNewBool("allclassesreport", "Generate allclasses.txt report", SYNTAX_STATUS_NORMAL),
282     ConstraintSyntaxNewBool("alwaysvalidate", "true/false flag to determine whether configurations will always be checked before executing, or only after updates", SYNTAX_STATUS_NORMAL),
283     ConstraintSyntaxNewBool("auditing", "This option is deprecated, does nothing and is kept for backward compatibility. Default value: false", SYNTAX_STATUS_REMOVED),
284     ConstraintSyntaxNewString("binarypaddingchar", "", "Character used to pad unequal replacements in binary editing. Default value: space (ASC=32)", SYNTAX_STATUS_REMOVED),
285     ConstraintSyntaxNewString("bindtointerface", ".*", "Use this interface for outgoing connections", SYNTAX_STATUS_NORMAL),
286     ConstraintSyntaxNewBool("hashupdates", "true/false whether stored hashes are updated when change is detected in source. Default value: false", SYNTAX_STATUS_NORMAL),
287     ConstraintSyntaxNewString("childlibpath", ".*", "LD_LIBRARY_PATH for child processes", SYNTAX_STATUS_NORMAL),
288     ConstraintSyntaxNewInt("checksum_alert_time", "0,60", "The persistence time for the checksum_alert class. Default value: 10 mins", SYNTAX_STATUS_NORMAL),
289     ConstraintSyntaxNewOption("defaultcopytype", "mtime,atime,ctime,digest,hash,binary", "ctime or mtime differ", SYNTAX_STATUS_NORMAL),
290     ConstraintSyntaxNewBool("dryrun", "All talk and no action mode. Default value: false", SYNTAX_STATUS_NORMAL),
291     ConstraintSyntaxNewInt("editbinaryfilesize", CF_VALRANGE, "Integer limit on maximum binary file size to be edited. Default value: 100000", SYNTAX_STATUS_NORMAL),
292     ConstraintSyntaxNewInt("editfilesize", CF_VALRANGE, "Integer limit on maximum text file size to be edited. Default value: 100000", SYNTAX_STATUS_NORMAL),
293     ConstraintSyntaxNewStringList("environment", "[A-Za-z0-9_]+=.*", "List of environment variables to be inherited by children", SYNTAX_STATUS_NORMAL),
294     ConstraintSyntaxNewBool("exclamation", "true/false print exclamation marks during security warnings. Default value: true", SYNTAX_STATUS_REMOVED),
295     ConstraintSyntaxNewInt("expireafter", CF_VALRANGE, "Global default for time before on-going promise repairs are interrupted. Default value: 1 min", SYNTAX_STATUS_NORMAL),
296     ConstraintSyntaxNewStringList("files_single_copy", "", "List of filenames to be watched for multiple-source conflicts", SYNTAX_STATUS_NORMAL),
297     ConstraintSyntaxNewStringList("files_auto_define", "", "List of filenames to define classes if copied", SYNTAX_STATUS_NORMAL),
298     ConstraintSyntaxNewBool("hostnamekeys", "true/false label ppkeys by hostname not IP address. Default value: false", SYNTAX_STATUS_NORMAL),
299     ConstraintSyntaxNewInt("ifelapsed", CF_VALRANGE, "Global default for time that must elapse before promise will be rechecked. Default value: 1", SYNTAX_STATUS_NORMAL),
300     ConstraintSyntaxNewBool("inform", "true/false set inform level default. Default value: false", SYNTAX_STATUS_NORMAL),
301     ConstraintSyntaxNewBool("intermittency", "This option is deprecated, does nothing and is kept for backward compatibility. Default value: false", SYNTAX_STATUS_NORMAL),
302     ConstraintSyntaxNewInt("max_children", CF_VALRANGE, "Maximum number of background tasks that should be allowed concurrently. Default value: 1 concurrent agent promise", SYNTAX_STATUS_NORMAL),
303     ConstraintSyntaxNewInt("maxconnections", CF_VALRANGE, "Maximum number of outgoing connections to cf-serverd. Default value: 30 remote queries", SYNTAX_STATUS_NORMAL),
304     ConstraintSyntaxNewBool("mountfilesystems", "true/false mount any filesystems promised. Default value: false", SYNTAX_STATUS_NORMAL),
305     ConstraintSyntaxNewBool("nonalphanumfiles", "true/false warn about filenames with no alphanumeric content. Default value: false", SYNTAX_STATUS_NORMAL),
306     ConstraintSyntaxNewString("repchar", ".", "The character used to canonize pathnames in the file repository. Default value: _", SYNTAX_STATUS_NORMAL),
307     ConstraintSyntaxNewStringList("refresh_processes", CF_IDRANGE, "Reload the process table before verifying the bundles named in this list (lazy evaluation)", SYNTAX_STATUS_NORMAL),
308     ConstraintSyntaxNewString("default_repository", CF_ABSPATHRANGE, "Path to the default file repository. Default value: in situ", SYNTAX_STATUS_NORMAL),
309     ConstraintSyntaxNewBool("secureinput", "true/false check whether input files are writable by unauthorized users. Default value: false", SYNTAX_STATUS_NORMAL),
310     ConstraintSyntaxNewInt("sensiblecount", CF_VALRANGE, "Minimum number of files a mounted filesystem is expected to have. Default value: 2 files", SYNTAX_STATUS_NORMAL),
311     ConstraintSyntaxNewInt("sensiblesize", CF_VALRANGE, "Minimum number of bytes a mounted filesystem is expected to have. Default value: 1000 bytes", SYNTAX_STATUS_NORMAL),
312     ConstraintSyntaxNewBool("skipidentify", "Do not send IP/name during server connection because address resolution is broken. Default value: false", SYNTAX_STATUS_NORMAL),
313     ConstraintSyntaxNewStringList("suspiciousnames", "", "List of names to skip and warn about if found during any file search", SYNTAX_STATUS_NORMAL),
314     ConstraintSyntaxNewBool("syslog", "true/false switches on output to syslog at the inform level. Default value: false", SYNTAX_STATUS_REMOVED),
315     ConstraintSyntaxNewBool("track_value", "true/false switches on tracking of promise valuation. Default value: false", SYNTAX_STATUS_REMOVED),
316     ConstraintSyntaxNewStringList("timezone", "", "List of allowed timezones this machine must comply with", SYNTAX_STATUS_NORMAL),
317     ConstraintSyntaxNewInt("default_timeout", CF_VALRANGE, "Maximum time a network connection should attempt to connect. Default value: 10 seconds", SYNTAX_STATUS_NORMAL),
318     ConstraintSyntaxNewBool("verbose", "true/false switches on verbose standard output. Default value: false", SYNTAX_STATUS_NORMAL),
319     ConstraintSyntaxNewBool("report_class_log", "true/false enables logging classes at the end of agent execution. Default value: false", SYNTAX_STATUS_NORMAL),
320     ConstraintSyntaxNewBool("select_end_match_eof", "Set the default behavior of select_end_match_eof in edit_line promises. Default: false", SYNTAX_STATUS_NORMAL),
321     ConstraintSyntaxNewNull()
322 };
323 
324 const ConstraintSyntax CFS_CONTROLBODY[SERVER_CONTROL_MAX + 1] =
325 {
326     ConstraintSyntaxNewStringList("allowallconnects", "","List of IPs or hostnames that may have more than one connection to the server port", SYNTAX_STATUS_NORMAL),
327     ConstraintSyntaxNewStringList("allowconnects", "", "List of IPs or hostnames that may connect to the server port", SYNTAX_STATUS_NORMAL),
328     ConstraintSyntaxNewStringList("allowusers", "", "List of usernames who may execute requests from this server", SYNTAX_STATUS_NORMAL),
329     ConstraintSyntaxNewBool("auditing", "true/false activate auditing of server connections. Default value: false", SYNTAX_STATUS_NORMAL),
330     ConstraintSyntaxNewString("bindtointerface", "", "IP of the interface to which the server should bind on multi-homed hosts", SYNTAX_STATUS_NORMAL),
331     ConstraintSyntaxNewString("cfruncommand", CF_PATHRANGE, "Path to the cf-agent command or cf-execd wrapper for remote execution", SYNTAX_STATUS_NORMAL),
332     ConstraintSyntaxNewInt("call_collect_interval", CF_VALRANGE, "The interval in minutes in between collect calls to the policy hub offering a tunnel for report collection (Enterprise)", SYNTAX_STATUS_NORMAL),
333     ConstraintSyntaxNewInt("collect_window", CF_VALRANGE, "A time in seconds that a collect-call tunnel remains open to a hub to attempt a report transfer before it is closed (Enterprise)", SYNTAX_STATUS_NORMAL),
334     ConstraintSyntaxNewBool("denybadclocks", "true/false accept connections from hosts with clocks that are out of sync. Default value: true", SYNTAX_STATUS_NORMAL),
335     ConstraintSyntaxNewStringList("denyconnects", "", "List of IPs or hostnames that may NOT connect to the server port", SYNTAX_STATUS_NORMAL),
336     ConstraintSyntaxNewStringList("dynamicaddresses", "", "List of IPs or hostnames for which the IP/name binding is expected to change", SYNTAX_STATUS_NORMAL),
337     ConstraintSyntaxNewBool("hostnamekeys", "true/false store keys using hostname lookup instead of IP addresses. Default value: false", SYNTAX_STATUS_NORMAL),
338     ConstraintSyntaxNewInt("keycacheTTL", CF_VALRANGE, "Maximum number of hours to hold public keys in the cache. Default value: 24", SYNTAX_STATUS_REMOVED),
339     ConstraintSyntaxNewBool("logallconnections", "true/false causes the server to log all new connections to syslog. Default value: false", SYNTAX_STATUS_NORMAL),
340     ConstraintSyntaxNewBool("logencryptedtransfers", "true/false log all successful transfers required to be encrypted. Default value: false", SYNTAX_STATUS_NORMAL),
341     ConstraintSyntaxNewInt("maxconnections", CF_VALRANGE, "Maximum number of connections that will be accepted by cf-serverd. Default value: 30 remote queries", SYNTAX_STATUS_NORMAL),
342     ConstraintSyntaxNewInt("port", "1,65535", "Default port for cfengine server. Default value: 5308", SYNTAX_STATUS_NORMAL),
343     ConstraintSyntaxNewOption("serverfacility", CF_FACILITY, "Menu option for syslog facility level. Default value: LOG_USER", SYNTAX_STATUS_NORMAL),
344     ConstraintSyntaxNewStringList("skipverify", "", "This option is deprecated, does nothing and is kept for backward compatibility.", SYNTAX_STATUS_DEPRECATED),
345     ConstraintSyntaxNewStringList("trustkeysfrom", "", "List of IPs from whom we accept public keys on trust", SYNTAX_STATUS_NORMAL),
346     ConstraintSyntaxNewBool("listen", "true/false enable server daemon to listen on defined port. Default value: true", SYNTAX_STATUS_NORMAL),
347     ConstraintSyntaxNewString("allowciphers", "", "List of ciphers the server accepts. For Syntax help see man page for \"openssl ciphers\". Default is \"AES256-GCM-SHA384:AES256-SHA\"", SYNTAX_STATUS_NORMAL),
348     ConstraintSyntaxNewStringList("allowlegacyconnects", "", "List of IPs from whom we accept legacy protocol connections", SYNTAX_STATUS_NORMAL),
349     ConstraintSyntaxNewString("allowtlsversion", "", "Minimum TLS version allowed for incoming connections", SYNTAX_STATUS_NORMAL),
350     ConstraintSyntaxNewNull()
351 };
352 
353 const ConstraintSyntax CFM_CONTROLBODY[] =
354 {
355     ConstraintSyntaxNewReal("forgetrate", "0,1", "Decimal fraction [0,1] weighting of new values over old in 2d-average computation. Default value: 0.6", SYNTAX_STATUS_NORMAL),
356     ConstraintSyntaxNewOption("monitorfacility", CF_FACILITY, "Menu option for syslog facility. Default value: LOG_USER", SYNTAX_STATUS_NORMAL),
357     ConstraintSyntaxNewBool("histograms", "Ignored, kept for backward compatibility. Default value: true", SYNTAX_STATUS_NORMAL),
358     ConstraintSyntaxNewBool("tcpdump", "true/false use tcpdump if found. Default value: false", SYNTAX_STATUS_NORMAL),
359     ConstraintSyntaxNewString("tcpdumpcommand", CF_ABSPATHRANGE, "Path to the tcpdump command on this system", SYNTAX_STATUS_NORMAL),
360     ConstraintSyntaxNewNull()
361 };
362 
363 const ConstraintSyntax CFR_CONTROLBODY[] =
364 {
365     ConstraintSyntaxNewStringList("hosts", "", "List of host or IP addresses to attempt connection with", SYNTAX_STATUS_NORMAL),
366     ConstraintSyntaxNewInt("port", "1,65535", "Default port for cfengine server. Default value: 5308", SYNTAX_STATUS_NORMAL),
367     ConstraintSyntaxNewBool("force_ipv4", "true/false force use of ipv4 in connection. Default value: false", SYNTAX_STATUS_NORMAL),
368     ConstraintSyntaxNewBool("trustkey", "true/false automatically accept all keys on trust from servers. Default value: false", SYNTAX_STATUS_NORMAL),
369     ConstraintSyntaxNewBool("encrypt", "true/false encrypt connections with servers. Default value: false", SYNTAX_STATUS_NORMAL),
370     ConstraintSyntaxNewBool("background_children", "true/false parallelize connections to servers. Default value: false", SYNTAX_STATUS_NORMAL),
371     ConstraintSyntaxNewInt("max_children", CF_VALRANGE, "Maximum number of simultaneous connections to attempt. Default value: 50 runagents", SYNTAX_STATUS_NORMAL),
372     ConstraintSyntaxNewBool("output_to_file", "true/false whether to send collected output to file(s). Default value: false", SYNTAX_STATUS_NORMAL),
373     ConstraintSyntaxNewString("output_directory", CF_ABSPATHRANGE, "Directory where the output is stored", SYNTAX_STATUS_NORMAL),
374     ConstraintSyntaxNewInt("timeout", "1,9999", "Connection timeout, sec", SYNTAX_STATUS_NORMAL),
375     ConstraintSyntaxNewNull()
376 };
377 
378 const ConstraintSyntax CFEX_CONTROLBODY[] = /* enum cfexcontrol */
379 {
380     ConstraintSyntaxNewInt("splaytime", CF_VALRANGE, "Time in minutes to splay this host based on its name hash. Default value: 0", SYNTAX_STATUS_NORMAL),
381     ConstraintSyntaxNewString("mailfrom", ".*@.*", "Email-address cfengine mail appears to come from", SYNTAX_STATUS_NORMAL),
382     ConstraintSyntaxNewString("mailto", ".*@.*", "Email-address cfengine mail is sent to", SYNTAX_STATUS_NORMAL),
383     ConstraintSyntaxNewString("mailsubject", "", "Define a custom mailsubject for the email message", SYNTAX_STATUS_NORMAL),
384     ConstraintSyntaxNewString("smtpserver", ".*", "Name or IP of a willing smtp server for sending email", SYNTAX_STATUS_NORMAL),
385     ConstraintSyntaxNewInt("mailmaxlines", "0,1000", "Maximum number of lines of output to send by email. Default value: 30", SYNTAX_STATUS_NORMAL),
386     ConstraintSyntaxNewStringList("mailfilter_include", "", "Which lines from the cf-agent output will be included in emails (regular expression)", SYNTAX_STATUS_NORMAL),
387     ConstraintSyntaxNewStringList("mailfilter_exclude", "", "Which lines from the cf-agent output will be excluded in emails (regular expression)", SYNTAX_STATUS_NORMAL),
388     ConstraintSyntaxNewStringList("schedule", "", "The class schedule used by cf-execd for activating cf-agent", SYNTAX_STATUS_NORMAL),
389     ConstraintSyntaxNewOption("executorfacility", CF_FACILITY, "Menu option for syslog facility level. Default value: LOG_USER", SYNTAX_STATUS_NORMAL),
390     ConstraintSyntaxNewString("exec_command", CF_ABSPATHRANGE,"The full path and command to the executable run by default (overriding builtin)", SYNTAX_STATUS_NORMAL),
391     ConstraintSyntaxNewInt("agent_expireafter", "0,10080", "Maximum agent runtime (in minutes). Default value: 120", SYNTAX_STATUS_NORMAL),
392     ConstraintSyntaxNewStringList("runagent_socket_allow_users", "", "Users allowed to work with the runagent.socket to trigger agent runs", SYNTAX_STATUS_NORMAL),
393     ConstraintSyntaxNewNull()
394 };
395 
396 // Must be in sync with enum HubControl
397 const ConstraintSyntax CFH_CONTROLBODY[] =
398 {
399     ConstraintSyntaxNewString("export_zenoss", CF_PATHRANGE, "Generate report for Zenoss integration", SYNTAX_STATUS_REMOVED),
400     ConstraintSyntaxNewStringList("exclude_hosts", "", "A list of IP addresses of hosts to exclude from report collection", SYNTAX_STATUS_NORMAL),
401     ConstraintSyntaxNewStringList("hub_schedule", "", "The class schedule used by cf-hub for report collation", SYNTAX_STATUS_NORMAL),
402     ConstraintSyntaxNewInt("query_timeout", "0,300", "Timeout (s) for connecting to host when querying. Default value: 30 (s)", SYNTAX_STATUS_NORMAL),
403     ConstraintSyntaxNewInt("port", "1,65535", "Default port for contacting hub nodes. Default value: 5308", SYNTAX_STATUS_NORMAL),
404     ConstraintSyntaxNewInt("client_history_timeout", "1,65535", "Threshold in hours over which if client did not report, hub will start query for full state of the host and discard all accumulated report history on the client. Default value: 6 hours", SYNTAX_STATUS_NORMAL),
405     ConstraintSyntaxNewNull()
406 };
407 
408 const ConstraintSyntax file_control_constraints[] =  /* enum cfh_control */
409 {
410     ConstraintSyntaxNewString("namespace", "[a-zA-Z_][a-zA-Z0-9_]*", "Switch to a private namespace to protect current file from duplicate definitions", SYNTAX_STATUS_NORMAL),
411     ConstraintSyntaxNewStringList("inputs", ".*", "List of additional filenames to parse for promises", SYNTAX_STATUS_NORMAL),
412     ConstraintSyntaxNewNull()
413 };
414 
415 const ConstraintSyntax CFRE_CONTROLBODY[] = /* enum cfrecontrol */
416 {
417     ConstraintSyntaxNewString("aggregation_point", CF_ABSPATHRANGE, "The root directory of the data cache for CMDB aggregation", SYNTAX_STATUS_REMOVED),
418     ConstraintSyntaxNewOption("auto_scaling", CF_BOOL, "true/false whether to auto-scale graph output to optimize use of space. Default value: true", SYNTAX_STATUS_REMOVED),
419     ConstraintSyntaxNewString("build_directory", ".*", "The directory in which to generate output files", SYNTAX_STATUS_REMOVED),
420     ConstraintSyntaxNewStringList("csv2xml", "", "A list of csv formatted files in the build directory to convert to simple xml", SYNTAX_STATUS_REMOVED),
421     ConstraintSyntaxNewOption("error_bars", CF_BOOL, "true/false whether to generate error bars on graph output", SYNTAX_STATUS_REMOVED),
422     ConstraintSyntaxNewString("html_banner", "", "HTML code for a banner to be added to rendered in html after the header", SYNTAX_STATUS_REMOVED),
423     ConstraintSyntaxNewOption("html_embed", CF_BOOL, "If true, no header and footer tags will be added to html output", SYNTAX_STATUS_REMOVED),
424     ConstraintSyntaxNewString("html_footer", "", "HTML code for a page footer to be added to rendered in html before the end body tag", SYNTAX_STATUS_REMOVED),
425     ConstraintSyntaxNewString("query_engine", "", "Name of a dynamic web-page used to accept and drive queries in a browser", SYNTAX_STATUS_REMOVED),
426     ConstraintSyntaxNewOptionList("reports", "all,audit,performance,all_locks,active_locks,hashes,classes,last_seen,monitor_now,monitor_history,monitor_summary,compliance,setuid,file_changes,installed_software,software_patches,value,variables", "A list of reports that may be generated", SYNTAX_STATUS_REMOVED),
427     ConstraintSyntaxNewOption("report_output", "csv,html,text,xml", "Menu option for generated output format. Applies only to text reports, graph data remain in xydy format.", SYNTAX_STATUS_REMOVED),
428     ConstraintSyntaxNewString("style_sheet", "", "Name of a style-sheet to be used in rendering html output (added to headers)", SYNTAX_STATUS_REMOVED),
429     ConstraintSyntaxNewString("time_stamps", CF_BOOL, "true/false whether to generate timestamps in the output directory name", SYNTAX_STATUS_REMOVED),
430     ConstraintSyntaxNewNull()
431 };
432 
433 
434 const ConstraintSyntax CFK_CONTROLBODY[] =
435 {
436     ConstraintSyntaxNewString("build_directory", ".*", "The directory in which to generate output files", SYNTAX_STATUS_REMOVED),
437     ConstraintSyntaxNewString("document_root", ".*", "The directory in which the web root resides", SYNTAX_STATUS_REMOVED),
438     ConstraintSyntaxNewOption("generate_manual", CF_BOOL, "true/false generate texinfo manual page skeleton for this version", SYNTAX_STATUS_REMOVED),
439     ConstraintSyntaxNewString("graph_directory", CF_ABSPATHRANGE, "Path to directory where rendered .png files will be created", SYNTAX_STATUS_REMOVED),
440     ConstraintSyntaxNewOption("graph_output", CF_BOOL, "true/false generate png visualization of topic map if possible (requires lib)", SYNTAX_STATUS_REMOVED),
441     ConstraintSyntaxNewString("html_banner", "", "HTML code for a banner to be added to rendered in html after the header", SYNTAX_STATUS_REMOVED),
442     ConstraintSyntaxNewString("html_footer", "", "HTML code for a page footer to be added to rendered in html before the end body tag", SYNTAX_STATUS_REMOVED),
443     ConstraintSyntaxNewString("id_prefix", ".*", "The LTM identifier prefix used to label topic maps (used for disambiguation in merging)", SYNTAX_STATUS_REMOVED),
444     ConstraintSyntaxNewString("manual_source_directory", CF_ABSPATHRANGE, "Path to directory where raw text about manual topics is found (defaults to build_directory)", SYNTAX_STATUS_REMOVED),
445     ConstraintSyntaxNewString("query_engine", "", "Name of a dynamic web-page used to accept and drive queries in a browser", SYNTAX_STATUS_REMOVED),
446     ConstraintSyntaxNewOption("query_output", "html,text", "Menu option for generated output format", SYNTAX_STATUS_REMOVED),
447     ConstraintSyntaxNewOption("sql_type", "mysql,postgres", "Menu option for supported database type", SYNTAX_STATUS_REMOVED),
448     ConstraintSyntaxNewString("sql_database", "", "Name of database used for the topic map", SYNTAX_STATUS_REMOVED),
449     ConstraintSyntaxNewString("sql_owner", "", "User id of sql database user", SYNTAX_STATUS_REMOVED),
450     ConstraintSyntaxNewString("sql_passwd", "", "Embedded password for accessing sql database", SYNTAX_STATUS_REMOVED),
451     ConstraintSyntaxNewString("sql_server", "", "Name or IP of database server (or localhost)", SYNTAX_STATUS_REMOVED),
452     ConstraintSyntaxNewString("sql_connection_db", "", "The name of an existing database to connect to in order to create/manage other databases", SYNTAX_STATUS_REMOVED),
453     ConstraintSyntaxNewString("style_sheet", "", "Name of a style-sheet to be used in rendering html output (added to headers)", SYNTAX_STATUS_REMOVED),
454     ConstraintSyntaxNewOption("view_projections", CF_BOOL, "Perform view-projection analytics in graph generation", SYNTAX_STATUS_REMOVED),
455     ConstraintSyntaxNewNull()
456 };
457 
458 
459 /* This list is for checking free standing body lval => rval bindings */
460 
461 const BodySyntax CONTROL_BODIES[] =
462 {
463     BodySyntaxNew(CF_COMMONC, CFG_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
464     BodySyntaxNew(CF_AGENTC, CFA_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
465     BodySyntaxNew(CF_SERVERC, CFS_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
466     BodySyntaxNew(CF_MONITORC, CFM_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
467     BodySyntaxNew(CF_RUNC, CFR_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
468     BodySyntaxNew(CF_EXECC, CFEX_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
469     BodySyntaxNew(CF_HUBC, CFH_CONTROLBODY, NULL, SYNTAX_STATUS_NORMAL),
470     BodySyntaxNew("file", file_control_constraints, NULL, SYNTAX_STATUS_NORMAL),
471 
472     BodySyntaxNew("reporter", CFRE_CONTROLBODY, NULL, SYNTAX_STATUS_REMOVED),
473     BodySyntaxNew("knowledge", CFK_CONTROLBODY, NULL, SYNTAX_STATUS_REMOVED),
474 
475     //  get others from modules e.g. "agent","files",CF_FILES_BODIES,
476 
477     BodySyntaxNewNull()
478 };
479 
480 /*********************************************************/
481 /*                                                       */
482 /* Constraint values/types                               */
483 /*                                                       */
484 /*********************************************************/
485 
486  /* This is where we place lval => rval bindings that
487     apply to more than one promise_type, e.g. generic
488     processing behavioural details */
489 
490 const ConstraintSyntax CF_COMMON_BODIES[] =
491 {
492     ConstraintSyntaxNewBody("action", &action_body, "Output behaviour", SYNTAX_STATUS_NORMAL),
493     ConstraintSyntaxNewBody("classes", &classes_body, "Signalling behaviour", SYNTAX_STATUS_NORMAL),
494     ConstraintSyntaxNewString("comment", "", "A comment about this promise's real intention that follows through the program", SYNTAX_STATUS_NORMAL),
495     ConstraintSyntaxNewStringList("depends_on", "","A list of promise handles that this promise builds on or depends on somehow (for knowledge management)", SYNTAX_STATUS_NORMAL),
496     ConstraintSyntaxNewString("handle", "", "A unique id-tag string for referring to this as a promisee elsewhere", SYNTAX_STATUS_NORMAL),
497     ConstraintSyntaxNewString("ifvarclass", "", "Extended classes ANDed with context (alias for 'if')", SYNTAX_STATUS_NORMAL),
498     ConstraintSyntaxNewString("if", "", "Extended classes ANDed with context", SYNTAX_STATUS_NORMAL),
499     ConstraintSyntaxNewString("unless", "", "Negated 'if'", SYNTAX_STATUS_NORMAL),
500     ConstraintSyntaxNewStringList("meta", "", "User-data associated with policy, e.g. key=value strings", SYNTAX_STATUS_NORMAL),
501     ConstraintSyntaxNewString("with", "", "A string that will replace every instance of $(with)", SYNTAX_STATUS_NORMAL),
502     ConstraintSyntaxNewNull()
503 };
504 
505  /* This is where we place promise promise_types that apply
506     to more than one type of bundle, e.g. agent,server.. */
507 
508 const PromiseTypeSyntax CF_COMMON_PROMISE_TYPES[] =
509 {
510 
511     PromiseTypeSyntaxNew("*", "classes", CF_CLASSBODY, &ClassesParseTreeCheck, SYNTAX_STATUS_NORMAL),
512     PromiseTypeSyntaxNew("*", "defaults", CF_DEFAULTSBODY, NULL, SYNTAX_STATUS_NORMAL),
513     PromiseTypeSyntaxNew("*", "meta", CF_METABODY, NULL, SYNTAX_STATUS_NORMAL),
514     PromiseTypeSyntaxNew("*", "reports", CF_REPORT_BODIES, NULL, SYNTAX_STATUS_NORMAL),
515     PromiseTypeSyntaxNew("*", "vars", CF_VARBODY, &VarsParseTreeCheck, SYNTAX_STATUS_NORMAL),
516     PromiseTypeSyntaxNew("*", "*", CF_COMMON_BODIES, NULL, SYNTAX_STATUS_NORMAL),
517     PromiseTypeSyntaxNewNull()
518 };
519 
520 /*********************************************************/
521 /* THIS IS WHERE TO ATTACH SYNTAX MODULES                */
522 /*********************************************************/
523 
524 /* Read in all parsable Bundle definitions */
525 /* REMEMBER TO REGISTER THESE IN cf3.extern.h */
526 
527 const PromiseTypeSyntax *const CF_ALL_PROMISE_TYPES[] =
528 {
529     CF_COMMON_PROMISE_TYPES,         /* Add modules after this, mod_report.c is here */
530     CF_EXEC_PROMISE_TYPES,           /* mod_exec.c */
531     CF_DATABASES_PROMISE_TYPES,      /* mod_databases.c */
532     CF_ENVIRONMENT_PROMISE_TYPES,    /* mod_environ.c */
533     CF_FILES_PROMISE_TYPES,          /* mod_files.c */
534     CF_METHOD_PROMISE_TYPES,         /* mod_methods.c */
535     CF_OUTPUTS_PROMISE_TYPES,        /* mod_outputs.c */
536     CF_PACKAGES_PROMISE_TYPES,       /* mod_packages.c */
537     CF_PROCESS_PROMISE_TYPES,        /* mod_process.c */
538     CF_SERVICES_PROMISE_TYPES,       /* mod_services.c */
539     CF_STORAGE_PROMISE_TYPES,        /* mod_storage.c */
540     CF_REMACCESS_PROMISE_TYPES,      /* mod_access.c */
541     CF_MEASUREMENT_PROMISE_TYPES,    /* mod_measurement.c */
542     CF_KNOWLEDGE_PROMISE_TYPES,      /* mod_knowledge.c */
543     CF_USERS_PROMISE_TYPES,          /* mod_users.c */
544 };
545 
546 const int CF3_MODULES = (sizeof(CF_ALL_PROMISE_TYPES) / sizeof(CF_ALL_PROMISE_TYPES[0]));
547 
548 
CommonControlFromString(const char * lval)549 CommonControl CommonControlFromString(const char *lval)
550 {
551     int i = 0;
552     for (const ConstraintSyntax *s = CFG_CONTROLBODY; s->lval; s++, i++)
553     {
554         if (strcmp(lval, s->lval) == 0)
555         {
556             return (CommonControl)i;
557         }
558     }
559 
560     return COMMON_CONTROL_MAX;
561 }
562