1 /*
2   Copyright 2020 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 #include <attributes.h>
26 
27 #include <promises.h>
28 #include <policy.h>
29 #include <conversion.h>
30 #include <logging.h>
31 #include <chflags.h>
32 #include <audit.h>
33 #include <protocol.h> // ParseProtocolVersionPolicy()
34 
35 #define CF_DEFINECLASSES "classes"
36 #define CF_TRANSACTION   "action"
37 
38 static FilePerms GetPermissionConstraints(const EvalContext *ctx, const Promise *pp);
39 
ClearFilesAttributes(Attributes * whom)40 void ClearFilesAttributes(Attributes *whom)
41 {
42     UidListDestroy(whom->perms.owners);
43     GidListDestroy(whom->perms.groups);
44 }
45 
GetFilesAttributes(const EvalContext * ctx,const Promise * pp)46 Attributes GetFilesAttributes(const EvalContext *ctx, const Promise *pp)
47 {
48     Attributes attr = ZeroAttributes;
49 
50 // default for file copy
51 
52     attr.havedepthsearch = PromiseGetConstraintAsBoolean(ctx, "depth_search", pp);
53     attr.haveselect = PromiseGetConstraintAsBoolean(ctx, "file_select", pp);
54     attr.haverename = PromiseGetConstraintAsBoolean(ctx, "rename", pp);
55     attr.havedelete = PromiseGetConstraintAsBoolean(ctx, "delete", pp);
56     attr.content = PromiseGetConstraintAsRval(pp, "content", RVAL_TYPE_SCALAR);
57     attr.haveperms = PromiseGetConstraintAsBoolean(ctx, "perms", pp);
58     attr.havechange = PromiseGetConstraintAsBoolean(ctx, "changes", pp);
59     attr.havecopy = PromiseGetConstraintAsBoolean(ctx, "copy_from", pp);
60     attr.havelink = PromiseGetConstraintAsBoolean(ctx, "link_from", pp);
61 
62     attr.edit_template = PromiseGetConstraintAsRval(pp, "edit_template", RVAL_TYPE_SCALAR);
63     attr.edit_template_string = PromiseGetConstraintAsRval(pp, "edit_template_string", RVAL_TYPE_SCALAR);
64     attr.template_method = PromiseGetConstraintAsRval(pp, "template_method", RVAL_TYPE_SCALAR);
65     attr.template_data = PromiseGetConstraintAsRval(pp, "template_data", RVAL_TYPE_CONTAINER);
66 
67     if (!attr.template_method )
68     {
69         attr.template_method = "cfengine";
70     }
71 
72     attr.haveeditline = PromiseBundleOrBodyConstraintExists(ctx, "edit_line", pp);
73     attr.haveeditxml = PromiseBundleOrBodyConstraintExists(ctx, "edit_xml", pp);
74     attr.haveedit = (attr.haveeditline) || (attr.haveeditxml) || (attr.edit_template) || (attr.edit_template_string);
75 
76 /* Files, specialist */
77 
78     attr.repository = PromiseGetConstraintAsRval(pp, "repository", RVAL_TYPE_SCALAR);
79     attr.create = PromiseGetConstraintAsBoolean(ctx, "create", pp);
80     attr.touch = PromiseGetConstraintAsBoolean(ctx, "touch", pp);
81     attr.transformer = PromiseGetConstraintAsRval(pp, "transformer", RVAL_TYPE_SCALAR);
82     attr.move_obstructions = PromiseGetConstraintAsBoolean(ctx, "move_obstructions", pp);
83     attr.pathtype = PromiseGetConstraintAsRval(pp, "pathtype", RVAL_TYPE_SCALAR);
84     attr.file_type = PromiseGetConstraintAsRval(pp, "file_type", RVAL_TYPE_SCALAR);
85 
86     attr.acl = GetAclConstraints(ctx, pp);
87     attr.perms = GetPermissionConstraints(ctx, pp);
88     attr.select = GetSelectConstraints(ctx, pp);
89     attr.delete = GetDeleteConstraints(ctx, pp);
90     attr.rename = GetRenameConstraints(ctx, pp);
91     attr.change = GetChangeMgtConstraints(ctx, pp);
92     attr.copy = GetCopyConstraints(ctx, pp);
93     attr.link = GetLinkConstraints(ctx, pp);
94     attr.edits = GetEditDefaults(ctx, pp);
95 
96     if (attr.edit_template || attr.edit_template_string)
97     {
98         attr.edits.empty_before_use = true;
99         attr.edits.inherit = true;
100     }
101 
102 /* Files, multiple use */
103 
104     attr.recursion = GetRecursionConstraints(ctx, pp);
105 
106 /* Common ("included") */
107 
108     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
109     attr.transaction = GetTransactionConstraints(ctx, pp);
110     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
111     attr.classes = GetClassDefinitionConstraints(ctx, pp);
112 
113     return attr;
114 }
115 
116 /*******************************************************************/
117 
GetReportsAttributes(const EvalContext * ctx,const Promise * pp)118 Attributes GetReportsAttributes(const EvalContext *ctx, const Promise *pp)
119 {
120     Attributes attr = ZeroAttributes;
121 
122     attr.transaction = GetTransactionConstraints(ctx, pp);
123     attr.classes = GetClassDefinitionConstraints(ctx, pp);
124 
125     attr.report = GetReportConstraints(ctx, pp);
126     return attr;
127 }
128 
129 /*******************************************************************/
130 
GetEnvironmentsAttributes(const EvalContext * ctx,const Promise * pp)131 Attributes GetEnvironmentsAttributes(const EvalContext *ctx, const Promise *pp)
132 {
133     Attributes attr = ZeroAttributes;
134 
135     attr.transaction = GetTransactionConstraints(ctx, pp);
136     attr.classes = GetClassDefinitionConstraints(ctx, pp);
137     attr.env = GetEnvironmentsConstraints(ctx, pp);
138 
139     return attr;
140 }
141 
142 /*******************************************************************/
143 
GetServicesAttributes(const EvalContext * ctx,const Promise * pp)144 Attributes GetServicesAttributes(const EvalContext *ctx, const Promise *pp)
145 {
146     Attributes attr = ZeroAttributes;
147 
148     attr.transaction = GetTransactionConstraints(ctx, pp);
149     attr.classes = GetClassDefinitionConstraints(ctx, pp);
150     attr.service = GetServicesConstraints(ctx, pp);
151     attr.havebundle = PromiseBundleOrBodyConstraintExists(ctx, "service_bundle", pp);
152 
153     return attr;
154 }
155 
156 /*******************************************************************/
157 
GetPackageAttributes(const EvalContext * ctx,const Promise * pp)158 Attributes GetPackageAttributes(const EvalContext *ctx, const Promise *pp)
159 {
160     Attributes attr = ZeroAttributes;
161 
162     attr.transaction = GetTransactionConstraints(ctx, pp);
163     attr.classes = GetClassDefinitionConstraints(ctx, pp);
164     attr.packages = GetPackageConstraints(ctx, pp);
165     attr.new_packages = GetNewPackageConstraints(ctx, pp);
166     return attr;
167 }
168 
169 /*******************************************************************/
170 
GetUserConstraints(const EvalContext * ctx,const Promise * pp)171 static User GetUserConstraints(const EvalContext *ctx, const Promise *pp)
172 {
173     User u;
174     char *value;
175 
176     value = PromiseGetConstraintAsRval(pp, "policy", RVAL_TYPE_SCALAR);
177     u.policy = UserStateFromString(value);
178 
179     u.uid = PromiseGetConstraintAsRval(pp, "uid", RVAL_TYPE_SCALAR);
180 
181     value = PromiseGetConstraintAsRval(pp, "format", RVAL_TYPE_SCALAR);
182     u.password_format = PasswordFormatFromString(value);
183     u.password = PromiseGetConstraintAsRval(pp, "data", RVAL_TYPE_SCALAR);
184     u.description = PromiseGetConstraintAsRval(pp, "description", RVAL_TYPE_SCALAR);
185 
186     u.group_primary = PromiseGetConstraintAsRval(pp, "group_primary", RVAL_TYPE_SCALAR);
187     u.home_dir = PromiseGetConstraintAsRval(pp, "home_dir", RVAL_TYPE_SCALAR);
188     u.shell = PromiseGetConstraintAsRval(pp, "shell", RVAL_TYPE_SCALAR);
189 
190     u.groups_secondary = PromiseGetConstraintAsList(ctx, "groups_secondary", pp);
191 
192     const Constraint *cp = PromiseGetImmediateConstraint(pp, "groups_secondary");
193     u.groups_secondary_given = (cp != NULL);
194 
195     if (value && ((u.policy) == USER_STATE_NONE))
196     {
197         Log(LOG_LEVEL_ERR, "Unsupported user policy '%s' in users promise", value);
198         PromiseRef(LOG_LEVEL_ERR, pp);
199     }
200 
201     return u;
202 }
203 
GetUserAttributes(const EvalContext * ctx,const Promise * pp)204 Attributes GetUserAttributes(const EvalContext *ctx, const Promise *pp)
205 {
206     Attributes attr = ZeroAttributes;
207 
208     attr.havebundle = PromiseBundleOrBodyConstraintExists(ctx, "home_bundle", pp);
209 
210     attr.inherit = PromiseGetConstraintAsBoolean(ctx, "home_bundle_inherit", pp);
211 
212     attr.transaction = GetTransactionConstraints(ctx, pp);
213     attr.classes = GetClassDefinitionConstraints(ctx, pp);
214     attr.users = GetUserConstraints(ctx, pp);
215     return attr;
216 }
217 
218 /*******************************************************************/
219 
GetDatabaseAttributes(const EvalContext * ctx,const Promise * pp)220 Attributes GetDatabaseAttributes(const EvalContext *ctx, const Promise *pp)
221 {
222     Attributes attr = ZeroAttributes;
223 
224     attr.transaction = GetTransactionConstraints(ctx, pp);
225     attr.classes = GetClassDefinitionConstraints(ctx, pp);
226     attr.database = GetDatabaseConstraints(ctx, pp);
227     return attr;
228 }
229 
230 /*******************************************************************/
231 
GetClassContextAttributes(const EvalContext * ctx,const Promise * pp)232 Attributes GetClassContextAttributes(const EvalContext *ctx, const Promise *pp)
233 {
234     Attributes a = ZeroAttributes;
235 
236     a.transaction = GetTransactionConstraints(ctx, pp);
237     a.classes = GetClassDefinitionConstraints(ctx, pp);
238     a.context = GetContextConstraints(ctx, pp);
239 
240     return a;
241 }
242 
243 /*******************************************************************/
244 
GetExecAttributes(const EvalContext * ctx,const Promise * pp)245 Attributes GetExecAttributes(const EvalContext *ctx, const Promise *pp)
246 {
247     Attributes attr = ZeroAttributes;
248 
249     attr.contain = GetExecContainConstraints(ctx, pp);
250     attr.havecontain = PromiseGetConstraintAsBoolean(ctx, "contain", pp);
251 
252     attr.args = PromiseGetConstraintAsRval(pp, "args", RVAL_TYPE_SCALAR);
253     attr.arglist = PromiseGetConstraintAsList(ctx, "arglist", pp);
254     attr.module = PromiseGetConstraintAsBoolean(ctx, "module", pp);
255 
256     // Possible to suppress info level messages per commands promise:
257     if (PromiseBundleOrBodyConstraintExists(ctx, "inform", pp))
258     {
259         attr.inform = PromiseGetConstraintAsBoolean(ctx, "inform", pp);
260     }
261     else
262     {
263         attr.inform = true; // Default to printing the inform messages
264     }
265 
266 /* Common ("included") */
267 
268     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
269     attr.transaction = GetTransactionConstraints(ctx, pp);
270 
271     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
272     attr.classes = GetClassDefinitionConstraints(ctx, pp);
273 
274     return attr;
275 }
276 
277 /*******************************************************************/
278 
GetProcessAttributes(const EvalContext * ctx,const Promise * pp)279 Attributes GetProcessAttributes(const EvalContext *ctx, const Promise *pp)
280 {
281     Attributes attr = ZeroAttributes;
282 
283     attr.signals = PromiseGetConstraintAsList(ctx, "signals", pp);
284     attr.process_stop = PromiseGetConstraintAsRval(pp, "process_stop", RVAL_TYPE_SCALAR);
285     attr.haveprocess_count = PromiseGetConstraintAsBoolean(ctx, "process_count", pp);
286     attr.haveselect = PromiseGetConstraintAsBoolean(ctx, "process_select", pp);
287     attr.restart_class = PromiseGetConstraintAsRval(pp, "restart_class", RVAL_TYPE_SCALAR);
288 
289     attr.process_count = GetMatchesConstraints(ctx, pp);
290     attr.process_select = GetProcessFilterConstraints(ctx, pp);
291 
292 /* Common ("included") */
293 
294     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
295     attr.transaction = GetTransactionConstraints(ctx, pp);
296 
297     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
298     attr.classes = GetClassDefinitionConstraints(ctx, pp);
299 
300     return attr;
301 }
302 
303 /*******************************************************************/
304 
GetStorageAttributes(const EvalContext * ctx,const Promise * pp)305 Attributes GetStorageAttributes(const EvalContext *ctx, const Promise *pp)
306 {
307     Attributes attr = ZeroAttributes;
308 
309     attr.mount = GetMountConstraints(ctx, pp);
310     attr.volume = GetVolumeConstraints(ctx, pp);
311     attr.havevolume = PromiseGetConstraintAsBoolean(ctx, "volume", pp);
312     attr.havemount = PromiseGetConstraintAsBoolean(ctx, "mount", pp);
313 
314 /* Common ("included") */
315 
316     if (attr.edits.maxfilesize <= 0)
317     {
318         attr.edits.maxfilesize = EDITFILESIZE;
319     }
320 
321     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
322     attr.transaction = GetTransactionConstraints(ctx, pp);
323 
324     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
325     attr.classes = GetClassDefinitionConstraints(ctx, pp);
326 
327     return attr;
328 }
329 
330 /*******************************************************************/
331 
GetMethodAttributes(const EvalContext * ctx,const Promise * pp)332 Attributes GetMethodAttributes(const EvalContext *ctx, const Promise *pp)
333 {
334     Attributes attr = ZeroAttributes;
335 
336     attr.havebundle = PromiseBundleOrBodyConstraintExists(ctx, "usebundle", pp);
337 
338     attr.inherit = PromiseGetConstraintAsBoolean(ctx, "inherit", pp);
339 
340 /* Common ("included") */
341 
342     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
343     attr.transaction = GetTransactionConstraints(ctx, pp);
344 
345     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
346     attr.classes = GetClassDefinitionConstraints(ctx, pp);
347 
348     return attr;
349 }
350 
GetMeasurementAttributes(const EvalContext * ctx,const Promise * pp)351 Attributes GetMeasurementAttributes(const EvalContext *ctx, const Promise *pp)
352 {
353     Attributes attr = ZeroAttributes;
354 
355     attr.measure = GetMeasurementConstraint(ctx, pp);
356 
357 /* Common ("included") */
358 
359     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
360     attr.transaction = GetTransactionConstraints(ctx, pp);
361 
362     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
363     attr.classes = GetClassDefinitionConstraints(ctx, pp);
364 
365     return attr;
366 }
367 
368 /*******************************************************************/
369 /* Level                                                           */
370 /*******************************************************************/
371 
GetServicesConstraints(const EvalContext * ctx,const Promise * pp)372 Services GetServicesConstraints(const EvalContext *ctx, const Promise *pp)
373 {
374     Services s;
375 
376     s.service_type = PromiseGetConstraintAsRval(pp, "service_type", RVAL_TYPE_SCALAR);
377     s.service_policy = PromiseGetConstraintAsRval(pp, "service_policy", RVAL_TYPE_SCALAR);
378     s.service_autostart_policy = PromiseGetConstraintAsRval(pp, "service_autostart_policy", RVAL_TYPE_SCALAR);
379     s.service_args = PromiseGetConstraintAsRval(pp, "service_args", RVAL_TYPE_SCALAR);
380     s.service_depend = PromiseGetConstraintAsList(ctx, "service_dependencies", pp);
381     s.service_depend_chain = PromiseGetConstraintAsRval(pp, "service_dependence_chain", RVAL_TYPE_SCALAR);
382 
383     return s;
384 }
385 
386 /*******************************************************************/
387 
GetEnvironmentsConstraints(const EvalContext * ctx,const Promise * pp)388 Environments GetEnvironmentsConstraints(const EvalContext *ctx, const Promise *pp)
389 {
390     Environments e;
391 
392     e.cpus = PromiseGetConstraintAsInt(ctx, "env_cpus", pp);
393     e.memory = PromiseGetConstraintAsInt(ctx, "env_memory", pp);
394     e.disk = PromiseGetConstraintAsInt(ctx, "env_disk", pp);
395     e.baseline = PromiseGetConstraintAsRval(pp, "env_baseline", RVAL_TYPE_SCALAR);
396     e.spec = PromiseGetConstraintAsRval(pp, "env_spec", RVAL_TYPE_SCALAR);
397     e.host = PromiseGetConstraintAsRval(pp, "environment_host", RVAL_TYPE_SCALAR);
398 
399     e.addresses = PromiseGetConstraintAsList(ctx, "env_addresses", pp);
400     e.name = PromiseGetConstraintAsRval(pp, "env_name", RVAL_TYPE_SCALAR);
401     e.type = PromiseGetConstraintAsRval(pp, "environment_type", RVAL_TYPE_SCALAR);
402     e.state = EnvironmentStateFromString(PromiseGetConstraintAsRval(pp, "environment_state", RVAL_TYPE_SCALAR));
403 
404     return e;
405 }
406 
407 /*******************************************************************/
408 
GetExecContainConstraints(const EvalContext * ctx,const Promise * pp)409 ExecContain GetExecContainConstraints(const EvalContext *ctx, const Promise *pp)
410 {
411     ExecContain e;
412 
413     e.shelltype = ShellTypeFromString(PromiseGetConstraintAsRval(pp, "useshell", RVAL_TYPE_SCALAR));
414     e.umask = PromiseGetConstraintAsOctal(ctx, "umask", pp);
415     e.owner = PromiseGetConstraintAsUid(ctx, "exec_owner", pp);
416     e.group = PromiseGetConstraintAsGid(ctx, "exec_group", pp);
417     e.preview = PromiseGetConstraintAsBoolean(ctx, "preview", pp);
418     if (PromiseBundleOrBodyConstraintExists(ctx, "no_output", pp))
419     {
420         e.nooutput = PromiseGetConstraintAsBoolean(ctx, "no_output", pp);
421     }
422     else
423     {
424         e.nooutput = PromiseGetConstraintAsBoolean(ctx, "module", pp);
425     }
426     e.timeout = PromiseGetConstraintAsInt(ctx, "exec_timeout", pp);
427     e.chroot = PromiseGetConstraintAsRval(pp, "chroot", RVAL_TYPE_SCALAR);
428     e.chdir = PromiseGetConstraintAsRval(pp, "chdir", RVAL_TYPE_SCALAR);
429 
430     return e;
431 }
432 
433 /*******************************************************************/
434 
GetRecursionConstraints(const EvalContext * ctx,const Promise * pp)435 DirectoryRecursion GetRecursionConstraints(const EvalContext *ctx, const Promise *pp)
436 {
437     DirectoryRecursion r;
438 
439     r.travlinks = PromiseGetConstraintAsBoolean(ctx, "traverse_links", pp);
440     r.rmdeadlinks = PromiseGetConstraintAsBoolean(ctx, "rmdeadlinks", pp);
441     r.depth = PromiseGetConstraintAsInt(ctx, "depth", pp);
442 
443     if (r.depth == CF_NOINT)
444     {
445         r.depth = 0;
446     }
447 
448     r.xdev = PromiseGetConstraintAsBoolean(ctx, "xdev", pp);
449     r.include_dirs = PromiseGetConstraintAsList(ctx, "include_dirs", pp);
450     r.exclude_dirs = PromiseGetConstraintAsList(ctx, "exclude_dirs", pp);
451     r.include_basedir = PromiseGetConstraintAsBoolean(ctx, "include_basedir", pp);
452     return r;
453 }
454 
455 /*******************************************************************/
456 
GetAclConstraints(const EvalContext * ctx,const Promise * pp)457 Acl GetAclConstraints(const EvalContext *ctx, const Promise *pp)
458 {
459     Acl ac;
460 
461     ac.acl_method = AclMethodFromString(PromiseGetConstraintAsRval(pp, "acl_method", RVAL_TYPE_SCALAR));
462     ac.acl_type = AclTypeFromString(PromiseGetConstraintAsRval(pp, "acl_type", RVAL_TYPE_SCALAR));
463     ac.acl_default = AclDefaultFromString(PromiseGetConstraintAsRval(pp, "acl_default", RVAL_TYPE_SCALAR));
464     if (ac.acl_default == ACL_DEFAULT_NONE)
465     {
466         /* Deprecated attribute. */
467         ac.acl_default = AclDefaultFromString(PromiseGetConstraintAsRval(pp, "acl_directory_inherit", RVAL_TYPE_SCALAR));
468     }
469     ac.acl_entries = PromiseGetConstraintAsList(ctx, "aces", pp);
470     ac.acl_default_entries = PromiseGetConstraintAsList(ctx, "specify_default_aces", pp);
471     if (ac.acl_default_entries == NULL)
472     {
473         /* Deprecated attribute. */
474         ac.acl_default_entries = PromiseGetConstraintAsList(ctx, "specify_inherit_aces", pp);
475     }
476     ac.acl_inherit = AclInheritFromString(PromiseGetConstraintAsRval(pp, "acl_inherit", RVAL_TYPE_SCALAR));
477     return ac;
478 }
479 
480 /*******************************************************************/
481 
GetPermissionConstraints(const EvalContext * ctx,const Promise * pp)482 static FilePerms GetPermissionConstraints(const EvalContext *ctx, const Promise *pp)
483 {
484     FilePerms p;
485     char *value;
486     Rlist *list;
487 
488     value = PromiseGetConstraintAsRval(pp, "mode", RVAL_TYPE_SCALAR);
489 
490     p.plus = CF_SAMEMODE;
491     p.minus = CF_SAMEMODE;
492 
493     if (!ParseModeString(value, &p.plus, &p.minus))
494     {
495         Log(LOG_LEVEL_ERR, "Problem validating a mode string");
496         PromiseRef(LOG_LEVEL_ERR, pp);
497     }
498 
499     list = PromiseGetConstraintAsList(ctx, "bsdflags", pp);
500 
501     p.plus_flags = 0;
502     p.minus_flags = 0;
503 
504     if (list && (!ParseFlagString(list, &p.plus_flags, &p.minus_flags)))
505     {
506         Log(LOG_LEVEL_ERR, "Problem validating a BSD flag string");
507         PromiseRef(LOG_LEVEL_ERR, pp);
508     }
509 
510     p.owners = Rlist2UidList((Rlist *) PromiseGetConstraintAsRval(pp, "owners", RVAL_TYPE_LIST), pp);
511     p.groups = Rlist2GidList((Rlist *) PromiseGetConstraintAsRval(pp, "groups", RVAL_TYPE_LIST), pp);
512 
513     p.findertype = PromiseGetConstraintAsRval(pp, "findertype", RVAL_TYPE_SCALAR);
514     p.rxdirs = PromiseGetConstraintAsBoolean(ctx, "rxdirs", pp);
515 
516 // The default should be true
517 
518     if (!PromiseGetConstraintAsRval(pp, "rxdirs", RVAL_TYPE_SCALAR))
519     {
520         p.rxdirs = true;
521     }
522 
523     return p;
524 }
525 
526 /*******************************************************************/
527 
GetSelectConstraints(const EvalContext * ctx,const Promise * pp)528 FileSelect GetSelectConstraints(const EvalContext *ctx, const Promise *pp)
529 {
530     FileSelect s;
531     char *value;
532     Rlist *rp;
533     mode_t plus, minus;
534     u_long fplus, fminus;
535     int entries = false;
536 
537     s.name = (Rlist *) PromiseGetConstraintAsRval(pp, "leaf_name", RVAL_TYPE_LIST);
538     s.path = (Rlist *) PromiseGetConstraintAsRval(pp, "path_name", RVAL_TYPE_LIST);
539     s.filetypes = (Rlist *) PromiseGetConstraintAsRval(pp, "file_types", RVAL_TYPE_LIST);
540     s.issymlinkto = (Rlist *) PromiseGetConstraintAsRval(pp, "issymlinkto", RVAL_TYPE_LIST);
541 
542     s.perms = PromiseGetConstraintAsList(ctx, "search_mode", pp);
543 
544     for (rp = s.perms; rp != NULL; rp = rp->next)
545     {
546         plus = 0;
547         minus = 0;
548         value = RlistScalarValue(rp);
549 
550         if (!ParseModeString(value, &plus, &minus))
551         {
552             Log(LOG_LEVEL_ERR, "Problem validating a mode string");
553             PromiseRef(LOG_LEVEL_ERR, pp);
554         }
555     }
556 
557     s.bsdflags = PromiseGetConstraintAsList(ctx, "search_bsdflags", pp);
558 
559     fplus = 0;
560     fminus = 0;
561 
562     if (!ParseFlagString(s.bsdflags, &fplus, &fminus))
563     {
564         Log(LOG_LEVEL_ERR, "Problem validating a BSD flag string");
565         PromiseRef(LOG_LEVEL_ERR, pp);
566     }
567 
568     if ((s.name) || (s.path) || (s.filetypes) || (s.issymlinkto) || (s.perms) || (s.bsdflags))
569     {
570         entries = true;
571     }
572 
573     s.owners = (Rlist *) PromiseGetConstraintAsRval(pp, "search_owners", RVAL_TYPE_LIST);
574     s.groups = (Rlist *) PromiseGetConstraintAsRval(pp, "search_groups", RVAL_TYPE_LIST);
575 
576     value = PromiseGetConstraintAsRval(pp, "search_size", RVAL_TYPE_SCALAR);
577     if (value)
578     {
579         entries++;
580     }
581 
582     if (!IntegerRangeFromString(value, (long *) &s.min_size, (long *) &s.max_size))
583     {
584         PromiseRef(LOG_LEVEL_ERR, pp);
585         FatalError(ctx, "Could not make sense of integer range [%s]", value);
586     }
587 
588     value = PromiseGetConstraintAsRval(pp, "ctime", RVAL_TYPE_SCALAR);
589     if (value)
590     {
591         entries++;
592     }
593 
594     if (!IntegerRangeFromString(value, (long *) &s.min_ctime, (long *) &s.max_ctime))
595     {
596         PromiseRef(LOG_LEVEL_ERR, pp);
597         FatalError(ctx, "Could not make sense of integer range [%s]", value);
598     }
599 
600     value = PromiseGetConstraintAsRval(pp, "atime", RVAL_TYPE_SCALAR);
601     if (value)
602     {
603         entries++;
604     }
605 
606     if (!IntegerRangeFromString(value, (long *) &s.min_atime, (long *) &s.max_atime))
607     {
608         PromiseRef(LOG_LEVEL_ERR, pp);
609         FatalError(ctx, "Could not make sense of integer range [%s]", value);
610     }
611     value = PromiseGetConstraintAsRval(pp, "mtime", RVAL_TYPE_SCALAR);
612     if (value)
613     {
614         entries++;
615     }
616 
617     if (!IntegerRangeFromString(value, (long *) &s.min_mtime, (long *) &s.max_mtime))
618     {
619         PromiseRef(LOG_LEVEL_ERR, pp);
620         FatalError(ctx, "Could not make sense of integer range [%s]", value);
621     }
622 
623     s.exec_regex = PromiseGetConstraintAsRval(pp, "exec_regex", RVAL_TYPE_SCALAR);
624     s.exec_program = PromiseGetConstraintAsRval(pp, "exec_program", RVAL_TYPE_SCALAR);
625 
626     if ((s.owners) || (s.min_size) || (s.exec_regex) || (s.exec_program))
627     {
628         entries = true;
629     }
630 
631     if ((s.result = PromiseGetConstraintAsRval(pp, "file_result", RVAL_TYPE_SCALAR)) == NULL)
632     {
633         if (!entries)
634         {
635             Log(LOG_LEVEL_ERR, "file_select body missing its a file_result return value");
636         }
637     }
638 
639     return s;
640 }
641 
642 /*******************************************************************/
643 
ActionAttributeLogLevelFromString(const char * log_level)644 LogLevel ActionAttributeLogLevelFromString(const char *log_level)
645 {
646     if (!log_level)
647     {
648         return LOG_LEVEL_ERR;
649     }
650 
651     if (strcmp("inform", log_level) == 0)
652     {
653         return LOG_LEVEL_INFO;
654     }
655     else if (strcmp("verbose", log_level) == 0)
656     {
657         return LOG_LEVEL_VERBOSE;
658     }
659     else
660     {
661         return LOG_LEVEL_ERR;
662     }
663 }
664 
GetTransactionConstraints(const EvalContext * ctx,const Promise * pp)665 TransactionContext GetTransactionConstraints(const EvalContext *ctx, const Promise *pp)
666 {
667     TransactionContext t;
668     char *value;
669 
670     value = PromiseGetConstraintAsRval(pp, "action_policy", RVAL_TYPE_SCALAR);
671 
672     if (value && ((strcmp(value, "warn") == 0) || (strcmp(value, "nop") == 0)))
673     {
674         t.action = cfa_warn;
675     }
676     else
677     {
678         t.action = cfa_fix;     // default
679     }
680 
681     t.background = PromiseGetConstraintAsBoolean(ctx, "background", pp);
682     t.ifelapsed = PromiseGetConstraintAsInt(ctx, "ifelapsed", pp);
683     t.expireafter = PromiseGetConstraintAsInt(ctx, "expireafter", pp);
684 
685     /* Warn if promise locking was used with a promise that doesn't support it.
686      * XXX: EvalContextGetPass() takes 'EvalContext *' instead of 'const EvalContext *'*/
687     if ((strcmp("access", pp->parent_section->promise_type) == 0 ||
688          strcmp("classes", pp->parent_section->promise_type) == 0 ||
689          strcmp("defaults", pp->parent_section->promise_type) == 0 ||
690          strcmp("meta", pp->parent_section->promise_type) == 0 ||
691          strcmp("roles", pp->parent_section->promise_type) == 0 ||
692          strcmp("vars", pp->parent_section->promise_type) == 0))
693     {
694         if (t.ifelapsed != CF_NOINT)
695         {
696             Log(LOG_LEVEL_WARNING,
697                 "ifelapsed attribute specified in action body for %s promise '%s',"
698                 " but %s promises do not support promise locking",
699                 pp->parent_section->promise_type, pp->promiser,
700                 pp->parent_section->promise_type);
701         }
702         if (t.expireafter != CF_NOINT)
703         {
704             Log(LOG_LEVEL_WARNING,
705                 "expireafter attribute specified in action body for %s promise '%s',"
706                 " but %s promises do not support promise locking",
707                 pp->parent_section->promise_type, pp->promiser,
708                 pp->parent_section->promise_type);
709         }
710     }
711 
712     if (t.ifelapsed == CF_NOINT)
713     {
714         t.ifelapsed = VIFELAPSED;
715     }
716 
717     if (t.expireafter == CF_NOINT)
718     {
719         t.expireafter = VEXPIREAFTER;
720     }
721 
722     t.audit = PromiseGetConstraintAsBoolean(ctx, "audit", pp);
723     t.log_string = PromiseGetConstraintAsRval(pp, "log_string", RVAL_TYPE_SCALAR);
724     t.log_priority = SyslogPriorityFromString(PromiseGetConstraintAsRval(pp, "log_priority", RVAL_TYPE_SCALAR));
725 
726     t.log_kept = PromiseGetConstraintAsRval(pp, "log_kept", RVAL_TYPE_SCALAR);
727     t.log_repaired = PromiseGetConstraintAsRval(pp, "log_repaired", RVAL_TYPE_SCALAR);
728     t.log_failed = PromiseGetConstraintAsRval(pp, "log_failed", RVAL_TYPE_SCALAR);
729 
730     value = PromiseGetConstraintAsRval(pp, "log_level", RVAL_TYPE_SCALAR);
731     t.log_level = ActionAttributeLogLevelFromString(value);
732 
733     value = PromiseGetConstraintAsRval(pp, "report_level", RVAL_TYPE_SCALAR);
734     t.report_level = ActionAttributeLogLevelFromString(value);
735 
736     t.measure_id = PromiseGetConstraintAsRval(pp, "measurement_class", RVAL_TYPE_SCALAR);
737 
738     return t;
739 }
740 
741 /*******************************************************************/
742 
GetClassDefinitionConstraints(const EvalContext * ctx,const Promise * pp)743 DefineClasses GetClassDefinitionConstraints(const EvalContext *ctx, const Promise *pp)
744 {
745     DefineClasses c;
746     char *pt = NULL;
747 
748     {
749         const char *context_scope = PromiseGetConstraintAsRval(pp, "scope", RVAL_TYPE_SCALAR);
750         c.scope = ContextScopeFromString(context_scope);
751     }
752     c.change = (Rlist *) PromiseGetConstraintAsList(ctx, "promise_repaired", pp);
753     c.failure = (Rlist *) PromiseGetConstraintAsList(ctx, "repair_failed", pp);
754     c.denied = (Rlist *) PromiseGetConstraintAsList(ctx, "repair_denied", pp);
755     c.timeout = (Rlist *) PromiseGetConstraintAsList(ctx, "repair_timeout", pp);
756     c.kept = (Rlist *) PromiseGetConstraintAsList(ctx, "promise_kept", pp);
757 
758     c.del_change = (Rlist *) PromiseGetConstraintAsList(ctx, "cancel_repaired", pp);
759     c.del_kept = (Rlist *) PromiseGetConstraintAsList(ctx, "cancel_kept", pp);
760     c.del_notkept = (Rlist *) PromiseGetConstraintAsList(ctx, "cancel_notkept", pp);
761 
762     c.retcode_kept = (Rlist *) PromiseGetConstraintAsList(ctx, "kept_returncodes", pp);
763     c.retcode_repaired = (Rlist *) PromiseGetConstraintAsList(ctx, "repaired_returncodes", pp);
764     c.retcode_failed = (Rlist *) PromiseGetConstraintAsList(ctx, "failed_returncodes", pp);
765 
766     c.persist = PromiseGetConstraintAsInt(ctx, "persist_time", pp);
767 
768     if (c.persist == CF_NOINT)
769     {
770         c.persist = 0;
771     }
772 
773     pt = PromiseGetConstraintAsRval(pp, "timer_policy", RVAL_TYPE_SCALAR);
774 
775     if (pt && (strncmp(pt, "abs", 3) == 0))
776     {
777         c.timer = CONTEXT_STATE_POLICY_PRESERVE;
778     }
779     else
780     {
781         c.timer = CONTEXT_STATE_POLICY_RESET;
782     }
783 
784     return c;
785 }
786 
787 /*******************************************************************/
788 
GetDeleteConstraints(const EvalContext * ctx,const Promise * pp)789 FileDelete GetDeleteConstraints(const EvalContext *ctx, const Promise *pp)
790 {
791     FileDelete f;
792     char *value;
793 
794     value = PromiseGetConstraintAsRval(pp, "dirlinks", RVAL_TYPE_SCALAR);
795 
796     if (value && (strcmp(value, "keep") == 0))
797     {
798         f.dirlinks = TIDY_LINK_KEEP;
799     }
800     else
801     {
802         f.dirlinks = TIDY_LINK_DELETE;
803     }
804 
805     f.rmdirs = PromiseGetConstraintAsBoolean(ctx, "rmdirs", pp);
806     return f;
807 }
808 
809 /*******************************************************************/
810 
GetRenameConstraints(const EvalContext * ctx,const Promise * pp)811 FileRename GetRenameConstraints(const EvalContext *ctx, const Promise *pp)
812 {
813     FileRename r;
814     char *value;
815 
816     value = PromiseGetConstraintAsRval(pp, "disable_mode", RVAL_TYPE_SCALAR);
817 
818     if (!ParseModeString(value, &r.plus, &r.minus))
819     {
820         Log(LOG_LEVEL_ERR, "Problem validating a mode string");
821         PromiseRef(LOG_LEVEL_ERR, pp);
822     }
823 
824     r.disable = PromiseGetConstraintAsBoolean(ctx, "disable", pp);
825     r.disable_suffix = PromiseGetConstraintAsRval(pp, "disable_suffix", RVAL_TYPE_SCALAR);
826     r.newname = PromiseGetConstraintAsRval(pp, "newname", RVAL_TYPE_SCALAR);
827     r.rotate = PromiseGetConstraintAsInt(ctx, "rotate", pp);
828 
829     return r;
830 }
831 
832 /*******************************************************************/
833 
ENTERPRISE_FUNC_0ARG_DEFINE_STUB(HashMethod,GetBestFileChangeHashMethod)834 ENTERPRISE_FUNC_0ARG_DEFINE_STUB(HashMethod, GetBestFileChangeHashMethod)
835 {
836     return HASH_METHOD_BEST;
837 }
838 
GetChangeMgtConstraints(const EvalContext * ctx,const Promise * pp)839 FileChange GetChangeMgtConstraints(const EvalContext *ctx, const Promise *pp)
840 {
841     FileChange c;
842     char *value;
843 
844     value = PromiseGetConstraintAsRval(pp, "hash", RVAL_TYPE_SCALAR);
845 
846     if (value && (strcmp(value, "best") == 0))
847     {
848         c.hash = GetBestFileChangeHashMethod();
849     }
850     else if (value && (strcmp(value, "md5") == 0))
851     {
852         c.hash = HASH_METHOD_MD5;
853     }
854     else if (value && (strcmp(value, "sha1") == 0))
855     {
856         c.hash = HASH_METHOD_SHA1;
857     }
858     else if (value && (strcmp(value, "sha256") == 0))
859     {
860         c.hash = HASH_METHOD_SHA256;
861     }
862     else if (value && (strcmp(value, "sha384") == 0))
863     {
864         c.hash = HASH_METHOD_SHA384;
865     }
866     else if (value && (strcmp(value, "sha512") == 0))
867     {
868         c.hash = HASH_METHOD_SHA512;
869     }
870     else
871     {
872         c.hash = CF_DEFAULT_DIGEST;
873     }
874 
875     if (FIPS_MODE && (c.hash == HASH_METHOD_MD5))
876     {
877         Log(LOG_LEVEL_ERR, "FIPS mode is enabled, and md5 is not an approved algorithm");
878         PromiseRef(LOG_LEVEL_ERR, pp);
879     }
880 
881     value = PromiseGetConstraintAsRval(pp, "report_changes", RVAL_TYPE_SCALAR);
882 
883     if (value && (strcmp(value, "content") == 0))
884     {
885         c.report_changes = FILE_CHANGE_REPORT_CONTENT_CHANGE;
886     }
887     else if (value && (strcmp(value, "stats") == 0))
888     {
889         c.report_changes = FILE_CHANGE_REPORT_STATS_CHANGE;
890     }
891     else if (value && (strcmp(value, "all") == 0))
892     {
893         c.report_changes = FILE_CHANGE_REPORT_ALL;
894     }
895     else
896     {
897         c.report_changes = FILE_CHANGE_REPORT_NONE;
898     }
899 
900     if (PromiseGetConstraintAsRval(pp, "update_hashes", RVAL_TYPE_SCALAR))
901     {
902         c.update = PromiseGetConstraintAsBoolean(ctx, "update_hashes", pp);
903     }
904     else
905     {
906         c.update = GetChecksumUpdatesDefault(ctx);
907     }
908 
909     c.report_diffs = PromiseGetConstraintAsBoolean(ctx, "report_diffs", pp);
910     return c;
911 }
912 
913 /*******************************************************************/
914 
GetCopyConstraints(const EvalContext * ctx,const Promise * pp)915 FileCopy GetCopyConstraints(const EvalContext *ctx, const Promise *pp)
916 {
917     FileCopy f;
918     long min, max;
919     const char *value;
920 
921     f.source = PromiseGetConstraintAsRval(pp, "source", RVAL_TYPE_SCALAR);
922     f.servers = PromiseGetConstraintAsList(ctx, "servers", pp);
923 
924     value = PromiseGetConstraintAsRval(pp, "compare", RVAL_TYPE_SCALAR);
925     if (value == NULL)
926     {
927         value = DEFAULT_COPYTYPE;
928     }
929     f.compare = FileComparatorFromString(value);
930 
931     value = PromiseGetConstraintAsRval(pp, "link_type", RVAL_TYPE_SCALAR);
932     f.link_type = FileLinkTypeFromString(value);
933 
934     char *protocol_version = PromiseGetConstraintAsRval(pp, "protocol_version",
935                                                         RVAL_TYPE_SCALAR);
936 
937     /* Default is undefined, which leaves the choice to body common. */
938     f.protocol_version = CF_PROTOCOL_UNDEFINED;
939     if (protocol_version != NULL)
940     {
941         ProtocolVersion parsed = ParseProtocolVersionPolicy(protocol_version);
942         if (ProtocolIsKnown(parsed))
943         {
944             f.protocol_version = parsed;
945         }
946     }
947 
948     f.port = PromiseGetConstraintAsRval(pp, "portnumber", RVAL_TYPE_SCALAR);
949     f.timeout = (short) PromiseGetConstraintAsInt(ctx, "timeout", pp);
950     f.link_instead = PromiseGetConstraintAsList(ctx, "linkcopy_patterns", pp);
951     f.copy_links = PromiseGetConstraintAsList(ctx, "copylink_patterns", pp);
952 
953     value = PromiseGetConstraintAsRval(pp, "copy_backup", RVAL_TYPE_SCALAR);
954 
955     if (value && (strcmp(value, "false") == 0))
956     {
957         f.backup = BACKUP_OPTION_NO_BACKUP;
958     }
959     else if (value && (strcmp(value, "timestamp") == 0))
960     {
961         f.backup = BACKUP_OPTION_TIMESTAMP;
962     }
963     else
964     {
965         f.backup = BACKUP_OPTION_BACKUP;
966     }
967 
968     f.stealth = PromiseGetConstraintAsBoolean(ctx, "stealth", pp);
969     f.collapse = PromiseGetConstraintAsBoolean(ctx, "collapse_destination_dir", pp);
970     f.preserve = PromiseGetConstraintAsBoolean(ctx, "preserve", pp);
971     f.type_check = PromiseGetConstraintAsBoolean(ctx, "type_check", pp);
972     f.force_update = PromiseGetConstraintAsBoolean(ctx, "force_update", pp);
973     f.force_ipv4 = PromiseGetConstraintAsBoolean(ctx, "force_ipv4", pp);
974     f.check_root = PromiseGetConstraintAsBoolean(ctx, "check_root", pp);
975 
976     value = PromiseGetConstraintAsRval(pp, "copy_size", RVAL_TYPE_SCALAR);
977     if (!IntegerRangeFromString(value, &min, &max))
978     {
979         PromiseRef(LOG_LEVEL_ERR, pp);
980         FatalError(ctx, "Could not make sense of integer range [%s]", value);
981     }
982 
983     f.min_size = (size_t) min;
984     f.max_size = (size_t) max;
985 
986     f.trustkey = PromiseGetConstraintAsBoolean(ctx, "trustkey", pp);
987     f.encrypt = PromiseGetConstraintAsBoolean(ctx, "encrypt", pp);
988     f.verify = PromiseGetConstraintAsBoolean(ctx, "verify", pp);
989     f.purge = PromiseGetConstraintAsBoolean(ctx, "purge", pp);
990     f.missing_ok = PromiseGetConstraintAsBoolean(ctx, "missing_ok", pp);
991     f.destination = NULL;
992 
993     return f;
994 }
995 
996 /*******************************************************************/
997 
GetLinkConstraints(const EvalContext * ctx,const Promise * pp)998 FileLink GetLinkConstraints(const EvalContext *ctx, const Promise *pp)
999 {
1000     FileLink f;
1001     char *value;
1002 
1003     f.source = PromiseGetConstraintAsRval(pp, "source", RVAL_TYPE_SCALAR);
1004     value = PromiseGetConstraintAsRval(pp, "link_type", RVAL_TYPE_SCALAR);
1005     f.link_type = FileLinkTypeFromString(value);
1006     f.copy_patterns = PromiseGetConstraintAsList(ctx, "copy_patterns", pp);
1007 
1008     value = PromiseGetConstraintAsRval(pp, "when_no_source", RVAL_TYPE_SCALAR);
1009 
1010     if (value && (strcmp(value, "force") == 0))
1011     {
1012         f.when_no_file = cfa_force;
1013     }
1014     else if (value && (strcmp(value, "delete") == 0))
1015     {
1016         f.when_no_file = cfa_delete;
1017     }
1018     else
1019     {
1020         f.when_no_file = cfa_skip;
1021     }
1022 
1023     value = PromiseGetConstraintAsRval(pp, "when_linking_children", RVAL_TYPE_SCALAR);
1024 
1025     if (value && (strcmp(value, "override_file") == 0))
1026     {
1027         f.when_linking_children = cfa_override;
1028     }
1029     else
1030     {
1031         f.when_linking_children = cfa_onlynonexisting;
1032     }
1033 
1034     f.link_children = PromiseGetConstraintAsBoolean(ctx, "link_children", pp);
1035 
1036     return f;
1037 }
1038 
1039 /*******************************************************************/
1040 
GetEditDefaults(const EvalContext * ctx,const Promise * pp)1041 EditDefaults GetEditDefaults(const EvalContext *ctx, const Promise *pp)
1042 {
1043     EditDefaults e = { 0 };
1044     char *value;
1045 
1046     e.maxfilesize = PromiseGetConstraintAsInt(ctx, "max_file_size", pp);
1047 
1048     if (e.maxfilesize == CF_NOINT)
1049     {
1050         e.maxfilesize = EDITFILESIZE;
1051     }
1052 
1053     value = PromiseGetConstraintAsRval(pp, "edit_backup", RVAL_TYPE_SCALAR);
1054 
1055     if (value && (strcmp(value, "false") == 0))
1056     {
1057         e.backup = BACKUP_OPTION_NO_BACKUP;
1058     }
1059     else if (value && (strcmp(value, "timestamp") == 0))
1060     {
1061         e.backup = BACKUP_OPTION_TIMESTAMP;
1062     }
1063     else if (value && (strcmp(value, "rotate") == 0))
1064     {
1065         e.backup = BACKUP_OPTION_ROTATE;
1066         e.rotate = PromiseGetConstraintAsInt(ctx, "rotate", pp);
1067     }
1068     else
1069     {
1070         e.backup = BACKUP_OPTION_BACKUP;
1071     }
1072 
1073     e.empty_before_use = PromiseGetConstraintAsBoolean(ctx, "empty_file_before_editing", pp);
1074 
1075     e.joinlines = PromiseGetConstraintAsBoolean(ctx, "recognize_join", pp);
1076 
1077     e.inherit = PromiseGetConstraintAsBoolean(ctx, "inherit", pp);
1078 
1079     return e;
1080 }
1081 
1082 /*******************************************************************/
1083 
GetContextConstraints(const EvalContext * ctx,const Promise * pp)1084 ContextConstraint GetContextConstraints(const EvalContext *ctx, const Promise *pp)
1085 {
1086     ContextConstraint a;
1087 
1088     a.nconstraints = 0;
1089     a.expression = NULL;
1090     a.persistent = PromiseGetConstraintAsInt(ctx, "persistence", pp);
1091 
1092     {
1093         const char *context_scope = PromiseGetConstraintAsRval(pp, "scope", RVAL_TYPE_SCALAR);
1094         a.scope = ContextScopeFromString(context_scope);
1095     }
1096 
1097     for (size_t i = 0; i < SeqLength(pp->conlist); i++)
1098     {
1099         Constraint *cp = SeqAt(pp->conlist, i);
1100 
1101         for (int k = 0; CF_CLASSBODY[k].lval != NULL; k++)
1102         {
1103             if (strcmp(cp->lval, "persistence") == 0 || strcmp(cp->lval, "scope") == 0)
1104             {
1105                 continue;
1106             }
1107 
1108             if (strcmp(cp->lval, CF_CLASSBODY[k].lval) == 0)
1109             {
1110                 a.expression = cp;
1111                 a.nconstraints++;
1112             }
1113         }
1114     }
1115 
1116     return a;
1117 }
1118 
1119 /*******************************************************************/
1120 
GetPackageConstraints(const EvalContext * ctx,const Promise * pp)1121 Packages GetPackageConstraints(const EvalContext *ctx, const Promise *pp)
1122 {
1123     Packages p = {0};
1124 
1125     bool has_package_method =
1126             PromiseBundleOrBodyConstraintExists(ctx, "package_method", pp);
1127     bool has_generic_package_method = false;
1128 
1129     if (!has_package_method)
1130     {
1131         /* Check if we have generic package_method. */
1132         const Policy *policy = PolicyFromPromise(pp);
1133         Seq *bodies_and_args = EvalContextResolveBodyExpression(ctx, policy, "generic", "package_method");; // at position 0 we'll have the body, then its rval, then the same for each of its inherit_from parents
1134         if (bodies_and_args != NULL &&
1135             SeqLength(bodies_and_args) > 0)
1136         {
1137             const Body *bp = SeqAt(bodies_and_args, 0); // guaranteed to be non-NULL
1138             CopyBodyConstraintsToPromise((EvalContext*)ctx, (Promise*)pp, bp);
1139             has_generic_package_method = true;
1140         }
1141         SeqDestroy(bodies_and_args);
1142     }
1143 
1144 
1145     p.package_version = PromiseGetConstraintAsRval(pp, "package_version", RVAL_TYPE_SCALAR);
1146     p.package_architectures = PromiseGetConstraintAsList(ctx, "package_architectures", pp);
1147     p.package_select = PackageVersionComparatorFromString(PromiseGetConstraintAsRval(pp, "package_select", RVAL_TYPE_SCALAR));
1148     p.package_policy = PackageActionFromString(PromiseGetConstraintAsRval(pp, "package_policy", RVAL_TYPE_SCALAR));
1149 
1150     if (p.package_version == NULL && p.package_architectures == NULL &&
1151         p.package_select == PACKAGE_VERSION_COMPARATOR_NONE &&
1152         p.package_policy == PACKAGE_ACTION_NONE)
1153     {
1154         p.is_empty = true;
1155     }
1156     else
1157     {
1158         p.is_empty = false;
1159     }
1160 
1161     if (p.package_policy == PACKAGE_ACTION_NONE)        // Default action => package add
1162     {
1163         p.package_policy = PACKAGE_ACTION_ADD;
1164     }
1165 
1166     p.has_package_method = has_package_method | has_generic_package_method;
1167 
1168     /* body package_method constraints */
1169     p.package_add_command = PromiseGetConstraintAsRval(pp, "package_add_command", RVAL_TYPE_SCALAR);
1170     p.package_arch_regex = PromiseGetConstraintAsRval(pp, "package_arch_regex", RVAL_TYPE_SCALAR);
1171     p.package_changes = PackageActionPolicyFromString(PromiseGetConstraintAsRval(pp, "package_changes", RVAL_TYPE_SCALAR));
1172     p.package_delete_command = PromiseGetConstraintAsRval(pp, "package_delete_command", RVAL_TYPE_SCALAR);
1173     p.package_delete_convention = PromiseGetConstraintAsRval(pp, "package_delete_convention", RVAL_TYPE_SCALAR);
1174     p.package_file_repositories = PromiseGetConstraintAsList(ctx, "package_file_repositories", pp);
1175     p.package_installed_regex = PromiseGetConstraintAsRval(pp, "package_installed_regex", RVAL_TYPE_SCALAR);
1176     p.package_default_arch_command = PromiseGetConstraintAsRval(pp, "package_default_arch_command", RVAL_TYPE_SCALAR);
1177     p.package_list_arch_regex = PromiseGetConstraintAsRval(pp, "package_list_arch_regex", RVAL_TYPE_SCALAR);
1178     p.package_list_command = PromiseGetConstraintAsRval(pp, "package_list_command", RVAL_TYPE_SCALAR);
1179     p.package_name_regex = PromiseGetConstraintAsRval(pp, "package_name_regex", RVAL_TYPE_SCALAR);
1180     p.package_list_update_command = PromiseGetConstraintAsRval(pp, "package_list_update_command", RVAL_TYPE_SCALAR);
1181     p.package_list_update_ifelapsed = PromiseGetConstraintAsInt(ctx, "package_list_update_ifelapsed", pp);
1182     p.package_list_version_regex = PromiseGetConstraintAsRval(pp, "package_list_version_regex", RVAL_TYPE_SCALAR);
1183     p.package_name_convention = PromiseGetConstraintAsRval(pp, "package_name_convention", RVAL_TYPE_SCALAR);
1184     p.package_patch_name_regex = PromiseGetConstraintAsRval(pp, "package_patch_name_regex", RVAL_TYPE_SCALAR);
1185     p.package_noverify_regex = PromiseGetConstraintAsRval(pp, "package_noverify_regex", RVAL_TYPE_SCALAR);
1186     p.package_noverify_returncode = PromiseGetConstraintAsInt(ctx, "package_noverify_returncode", pp);
1187     p.package_patch_arch_regex = PromiseGetConstraintAsRval(pp, "package_patch_arch_regex", RVAL_TYPE_SCALAR);
1188     p.package_patch_command = PromiseGetConstraintAsRval(pp, "package_patch_command", RVAL_TYPE_SCALAR);
1189     p.package_patch_installed_regex = PromiseGetConstraintAsRval(pp, "package_patch_installed_regex", RVAL_TYPE_SCALAR);
1190     p.package_patch_list_command = PromiseGetConstraintAsRval(pp, "package_patch_list_command", RVAL_TYPE_SCALAR);
1191     p.package_list_name_regex = PromiseGetConstraintAsRval(pp, "package_list_name_regex", RVAL_TYPE_SCALAR);
1192     p.package_patch_version_regex = PromiseGetConstraintAsRval(pp, "package_patch_version_regex", RVAL_TYPE_SCALAR);
1193     p.package_update_command = PromiseGetConstraintAsRval(pp, "package_update_command", RVAL_TYPE_SCALAR);
1194     p.package_verify_command = PromiseGetConstraintAsRval(pp, "package_verify_command", RVAL_TYPE_SCALAR);
1195     p.package_version_regex = PromiseGetConstraintAsRval(pp, "package_version_regex", RVAL_TYPE_SCALAR);
1196     p.package_multiline_start = PromiseGetConstraintAsRval(pp, "package_multiline_start", RVAL_TYPE_SCALAR);
1197     if (PromiseGetConstraint(pp, "package_commands_useshell") == NULL)
1198     {
1199         p.package_commands_useshell = true;
1200     }
1201     else
1202     {
1203         p.package_commands_useshell = PromiseGetConstraintAsBoolean(ctx, "package_commands_useshell", pp);
1204     }
1205     p.package_version_less_command = PromiseGetConstraintAsRval(pp, "package_version_less_command", RVAL_TYPE_SCALAR);
1206     p.package_version_equal_command = PromiseGetConstraintAsRval(pp, "package_version_equal_command", RVAL_TYPE_SCALAR);
1207 
1208     return p;
1209 }
1210 
1211 /*******************************************************************/
1212 
1213 static const char *new_packages_actions[] =
1214 {
1215     "absent",
1216     "present",
1217     NULL
1218 };
1219 
GetNewPackageConstraints(const EvalContext * ctx,const Promise * pp)1220 NewPackages GetNewPackageConstraints(const EvalContext *ctx, const Promise *pp)
1221 {
1222     NewPackages p = {0};
1223     NewPackages empty = {0};
1224 
1225     p.package_version = PromiseGetConstraintAsRval(pp, "version", RVAL_TYPE_SCALAR);
1226     p.package_architecture = PromiseGetConstraintAsRval(pp, "architecture", RVAL_TYPE_SCALAR);
1227     p.package_options = PromiseGetConstraintAsList(ctx, "options", pp);
1228 
1229     p.is_empty = (memcmp(&p, &empty, sizeof(NewPackages)) == 0);
1230     p.package_policy = GetNewPackagePolicy(PromiseGetConstraintAsRval(pp, "policy", RVAL_TYPE_SCALAR),
1231                                            new_packages_actions);
1232 
1233     /* We can have only policy specified in new package promise definition. */
1234     if (p.package_policy != NEW_PACKAGE_ACTION_NONE)
1235     {
1236         p.is_empty = false;
1237     }
1238 
1239     /* If we have promise package manager specified.
1240      * IMPORTANT: this must be done after is_empty flag is set as we can have
1241      * some default options for new package promise specified and still use
1242      * old promise inside policy. */
1243     char *local_promise_manager =
1244             PromiseGetConstraintAsRval(pp, "package_module_name", RVAL_TYPE_SCALAR);
1245     if (local_promise_manager)
1246     {
1247         p.module_body = GetPackageModuleFromContext(ctx, local_promise_manager);
1248     }
1249     else
1250     {
1251         p.module_body = GetDefaultPackageModuleFromContext(ctx);
1252     }
1253     p.package_inventory = GetDefaultInventoryFromContext(ctx);
1254 
1255     /* If global options are not override by promise specific ones. */
1256     if (!p.package_options && p.module_body)
1257     {
1258         p.package_options = p.module_body->options;
1259     }
1260 
1261     return p;
1262 }
1263 
1264 /*******************************************************************/
1265 
GetProcessFilterConstraints(const EvalContext * ctx,const Promise * pp)1266 ProcessSelect GetProcessFilterConstraints(const EvalContext *ctx, const Promise *pp)
1267 {
1268     ProcessSelect p;
1269     char *value;
1270     int entries = 0;
1271 
1272     p.owner = PromiseGetConstraintAsList(ctx, "process_owner", pp);
1273 
1274     value = PromiseGetConstraintAsRval(pp, "pid", RVAL_TYPE_SCALAR);
1275 
1276     if (value)
1277     {
1278         entries++;
1279     }
1280 
1281     if (!IntegerRangeFromString(value, &p.min_pid, &p.max_pid))
1282     {
1283         PromiseRef(LOG_LEVEL_ERR, pp);
1284         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1285     }
1286     value = PromiseGetConstraintAsRval(pp, "ppid", RVAL_TYPE_SCALAR);
1287 
1288     if (value)
1289     {
1290         entries++;
1291     }
1292 
1293     if (!IntegerRangeFromString(value, &p.min_ppid, &p.max_ppid))
1294     {
1295         PromiseRef(LOG_LEVEL_ERR, pp);
1296         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1297     }
1298     value = PromiseGetConstraintAsRval(pp, "pgid", RVAL_TYPE_SCALAR);
1299 
1300     if (value)
1301     {
1302         entries++;
1303     }
1304 
1305     if (!IntegerRangeFromString(value, &p.min_pgid, &p.max_pgid))
1306     {
1307         PromiseRef(LOG_LEVEL_ERR, pp);
1308         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1309     }
1310     value = PromiseGetConstraintAsRval(pp, "rsize", RVAL_TYPE_SCALAR);
1311 
1312     if (value)
1313     {
1314         entries++;
1315     }
1316 
1317     if (!IntegerRangeFromString(value, &p.min_rsize, &p.max_rsize))
1318     {
1319         PromiseRef(LOG_LEVEL_ERR, pp);
1320         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1321     }
1322     value = PromiseGetConstraintAsRval(pp, "vsize", RVAL_TYPE_SCALAR);
1323     if (value)
1324     {
1325         entries++;
1326     }
1327 
1328     if (!IntegerRangeFromString(value, &p.min_vsize, &p.max_vsize))
1329     {
1330         PromiseRef(LOG_LEVEL_ERR, pp);
1331         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1332     }
1333     value = PromiseGetConstraintAsRval(pp, "ttime_range", RVAL_TYPE_SCALAR);
1334     if (value)
1335     {
1336         entries++;
1337     }
1338 
1339     if (!IntegerRangeFromString(value, (long *) &p.min_ttime, (long *) &p.max_ttime))
1340     {
1341         PromiseRef(LOG_LEVEL_ERR, pp);
1342         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1343     }
1344     value = PromiseGetConstraintAsRval(pp, "stime_range", RVAL_TYPE_SCALAR);
1345     if (value)
1346     {
1347         entries++;
1348     }
1349 
1350     if (!IntegerRangeFromString(value, (long *) &p.min_stime, (long *) &p.max_stime))
1351     {
1352         PromiseRef(LOG_LEVEL_ERR, pp);
1353         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1354     }
1355 
1356     p.status = PromiseGetConstraintAsRval(pp, "status", RVAL_TYPE_SCALAR);
1357     p.command = PromiseGetConstraintAsRval(pp, "command", RVAL_TYPE_SCALAR);
1358     p.tty = PromiseGetConstraintAsRval(pp, "tty", RVAL_TYPE_SCALAR);
1359 
1360     value = PromiseGetConstraintAsRval(pp, "priority", RVAL_TYPE_SCALAR);
1361     if (value)
1362     {
1363         entries++;
1364     }
1365 
1366     if (!IntegerRangeFromString(value, &p.min_pri, &p.max_pri))
1367     {
1368         PromiseRef(LOG_LEVEL_ERR, pp);
1369         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1370     }
1371     value = PromiseGetConstraintAsRval(pp, "threads", RVAL_TYPE_SCALAR);
1372     if (value)
1373     {
1374         entries++;
1375     }
1376 
1377     if (!IntegerRangeFromString(value, &p.min_thread, &p.max_thread))
1378     {
1379         PromiseRef(LOG_LEVEL_ERR, pp);
1380         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1381     }
1382 
1383     if ((p.owner) || (p.status) || (p.command) || (p.tty))
1384     {
1385         entries = true;
1386     }
1387 
1388     if ((p.process_result = PromiseGetConstraintAsRval(pp, "process_result", RVAL_TYPE_SCALAR)) == NULL)
1389     {
1390         if (entries)
1391         {
1392             Log(LOG_LEVEL_ERR, "process_select body missing its a process_result return value");
1393         }
1394     }
1395 
1396     return p;
1397 }
1398 
1399 /*******************************************************************/
1400 
GetMatchesConstraints(const EvalContext * ctx,const Promise * pp)1401 ProcessCount GetMatchesConstraints(const EvalContext *ctx, const Promise *pp)
1402 {
1403     ProcessCount p;
1404     char *value;
1405 
1406     value = PromiseGetConstraintAsRval(pp, "match_range", RVAL_TYPE_SCALAR);
1407     if (!IntegerRangeFromString(value, &p.min_range, &p.max_range))
1408     {
1409         PromiseRef(LOG_LEVEL_ERR, pp);
1410         FatalError(ctx, "Could not make sense of integer range [%s]", value);
1411     }
1412     p.in_range_define = PromiseGetConstraintAsList(ctx, "in_range_define", pp);
1413     p.out_of_range_define = PromiseGetConstraintAsList(ctx, "out_of_range_define", pp);
1414 
1415     return p;
1416 }
1417 
GetInsertionAttributes(const EvalContext * ctx,const Promise * pp)1418 Attributes GetInsertionAttributes(const EvalContext *ctx, const Promise *pp)
1419 {
1420     Attributes attr = ZeroAttributes;
1421 
1422     attr.havelocation = PromiseGetConstraintAsBoolean(ctx, "location", pp);
1423     attr.location = GetLocationAttributes(pp);
1424 
1425     attr.sourcetype = PromiseGetConstraintAsRval(pp, "insert_type", RVAL_TYPE_SCALAR);
1426     attr.expandvars = PromiseGetConstraintAsBoolean(ctx, "expand_scalars", pp);
1427 
1428     attr.haveinsertselect = PromiseGetConstraintAsBoolean(ctx, "insert_select", pp);
1429     attr.line_select = GetInsertSelectConstraints(ctx, pp);
1430 
1431     attr.insert_match = PromiseGetConstraintAsList(ctx, "whitespace_policy", pp);
1432 
1433 /* Common ("included") */
1434 
1435     attr.haveregion = PromiseGetConstraintAsBoolean(ctx, "select_region", pp);
1436     attr.region = GetRegionConstraints(ctx, pp);
1437 
1438     attr.xml = GetXmlConstraints(pp);
1439 
1440     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
1441     attr.transaction = GetTransactionConstraints(ctx, pp);
1442 
1443     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
1444     attr.classes = GetClassDefinitionConstraints(ctx, pp);
1445 
1446     return attr;
1447 }
1448 
1449 /*******************************************************************/
1450 
GetLocationAttributes(const Promise * pp)1451 EditLocation GetLocationAttributes(const Promise *pp)
1452 {
1453     EditLocation e;
1454     char *value;
1455 
1456     e.line_matching = PromiseGetConstraintAsRval(pp, "select_line_matching", RVAL_TYPE_SCALAR);
1457 
1458     value = PromiseGetConstraintAsRval(pp, "before_after", RVAL_TYPE_SCALAR);
1459 
1460     if (value && (strcmp(value, "before") == 0))
1461     {
1462         e.before_after = EDIT_ORDER_BEFORE;
1463     }
1464     else
1465     {
1466         e.before_after = EDIT_ORDER_AFTER;
1467     }
1468 
1469     e.first_last = PromiseGetConstraintAsRval(pp, "first_last", RVAL_TYPE_SCALAR);
1470     return e;
1471 }
1472 
1473 /*******************************************************************/
1474 
GetDeletionAttributes(const EvalContext * ctx,const Promise * pp)1475 Attributes GetDeletionAttributes(const EvalContext *ctx, const Promise *pp)
1476 {
1477     Attributes attr = ZeroAttributes;
1478 
1479     attr.not_matching = PromiseGetConstraintAsBoolean(ctx, "not_matching", pp);
1480 
1481     attr.havedeleteselect = PromiseGetConstraintAsBoolean(ctx, "delete_select", pp);
1482     attr.line_select = GetDeleteSelectConstraints(ctx, pp);
1483 
1484     /* common */
1485 
1486     attr.haveregion = PromiseGetConstraintAsBoolean(ctx, "select_region", pp);
1487     attr.region = GetRegionConstraints(ctx, pp);
1488 
1489     attr.xml = GetXmlConstraints(pp);
1490 
1491     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
1492     attr.transaction = GetTransactionConstraints(ctx, pp);
1493 
1494     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
1495     attr.classes = GetClassDefinitionConstraints(ctx, pp);
1496 
1497     return attr;
1498 }
1499 
1500 /*******************************************************************/
1501 
GetColumnAttributes(const EvalContext * ctx,const Promise * pp)1502 Attributes GetColumnAttributes(const EvalContext *ctx, const Promise *pp)
1503 {
1504     Attributes attr = ZeroAttributes;
1505 
1506     attr.havecolumn = PromiseGetConstraintAsBoolean(ctx, "edit_field", pp);
1507     attr.column = GetColumnConstraints(ctx, pp);
1508 
1509     /* common */
1510 
1511     attr.haveregion = PromiseGetConstraintAsBoolean(ctx, "select_region", pp);
1512     attr.region = GetRegionConstraints(ctx, pp);
1513 
1514     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
1515     attr.transaction = GetTransactionConstraints(ctx, pp);
1516 
1517     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
1518     attr.classes = GetClassDefinitionConstraints(ctx, pp);
1519 
1520     return attr;
1521 }
1522 
1523 /*******************************************************************/
1524 
GetReplaceAttributes(const EvalContext * ctx,const Promise * pp)1525 Attributes GetReplaceAttributes(const EvalContext *ctx, const Promise *pp)
1526 {
1527     Attributes attr = ZeroAttributes;
1528 
1529     attr.havereplace = PromiseGetConstraintAsBoolean(ctx, "replace_patterns", pp);
1530     attr.replace = GetReplaceConstraints(pp);
1531 
1532     attr.havecolumn = PromiseGetConstraintAsBoolean(ctx, "replace_with", pp);
1533 
1534     /* common */
1535 
1536     attr.haveregion = PromiseGetConstraintAsBoolean(ctx, "select_region", pp);
1537     attr.region = GetRegionConstraints(ctx, pp);
1538 
1539     attr.xml = GetXmlConstraints(pp);
1540 
1541     attr.havetrans = PromiseGetConstraintAsBoolean(ctx, CF_TRANSACTION, pp);
1542     attr.transaction = GetTransactionConstraints(ctx, pp);
1543 
1544     attr.haveclasses = PromiseGetConstraintAsBoolean(ctx, CF_DEFINECLASSES, pp);
1545     attr.classes = GetClassDefinitionConstraints(ctx, pp);
1546 
1547     return attr;
1548 }
1549 
1550 /*******************************************************************/
1551 
GetXmlConstraints(const Promise * pp)1552 EditXml GetXmlConstraints(const Promise *pp)
1553 {
1554     EditXml x;
1555 
1556     x.havebuildxpath = ((x.build_xpath = PromiseGetConstraintAsRval(pp, "build_xpath", RVAL_TYPE_SCALAR)) != NULL);
1557     x.haveselectxpath = ((x.select_xpath = PromiseGetConstraintAsRval(pp, "select_xpath", RVAL_TYPE_SCALAR)) != NULL);
1558     x.haveattributevalue = ((x.attribute_value = PromiseGetConstraintAsRval(pp, "attribute_value", RVAL_TYPE_SCALAR)) != NULL);
1559 
1560     return x;
1561 }
1562 
1563 /*******************************************************************/
1564 
GetRegionConstraints(const EvalContext * ctx,const Promise * pp)1565 EditRegion GetRegionConstraints(const EvalContext *ctx, const Promise *pp)
1566 {
1567     EditRegion e;
1568 
1569     e.select_start = PromiseGetConstraintAsRval(pp, "select_start", RVAL_TYPE_SCALAR);
1570     e.select_end = PromiseGetConstraintAsRval(pp, "select_end", RVAL_TYPE_SCALAR);
1571     e.include_start = PromiseGetConstraintAsBoolean(ctx, "include_start_delimiter", pp);
1572     e.include_end = PromiseGetConstraintAsBoolean(ctx, "include_end_delimiter", pp);
1573 
1574     // set the value based on body agent control
1575     char *local_select_end = PromiseGetConstraintAsRval(pp,  "select_end_match_eof", RVAL_TYPE_SCALAR);
1576     if (local_select_end != NULL)
1577     {
1578         if (strcmp(local_select_end, "true") == 0)
1579         {
1580             e.select_end_match_eof = true;
1581         }
1582         else
1583         {
1584             e.select_end_match_eof = false;
1585         }
1586     }
1587     else
1588     {
1589         e.select_end_match_eof = EvalContextGetSelectEndMatchEof(ctx);
1590     }
1591     return e;
1592 }
1593 
1594 /*******************************************************************/
1595 
GetReplaceConstraints(const Promise * pp)1596 EditReplace GetReplaceConstraints(const Promise *pp)
1597 {
1598     EditReplace r;
1599 
1600     r.replace_value = PromiseGetConstraintAsRval(pp, "replace_value", RVAL_TYPE_SCALAR);
1601     r.occurrences = PromiseGetConstraintAsRval(pp, "occurrences", RVAL_TYPE_SCALAR);
1602 
1603     return r;
1604 }
1605 
1606 /*******************************************************************/
1607 
GetColumnConstraints(const EvalContext * ctx,const Promise * pp)1608 EditColumn GetColumnConstraints(const EvalContext *ctx, const Promise *pp)
1609 {
1610     EditColumn c;
1611     char *value;
1612 
1613     c.column_separator = PromiseGetConstraintAsRval(pp, "field_separator", RVAL_TYPE_SCALAR);
1614     c.select_column = PromiseGetConstraintAsInt(ctx, "select_field", pp);
1615 
1616     if (((c.select_column) != CF_NOINT) && (PromiseGetConstraintAsBoolean(ctx, "start_fields_from_zero", pp)))
1617     {
1618         c.select_column++;
1619     }
1620 
1621     value = PromiseGetConstraintAsRval(pp, "value_separator", RVAL_TYPE_SCALAR);
1622 
1623     if (value)
1624     {
1625         c.value_separator = *value;
1626     }
1627     else
1628     {
1629         c.value_separator = '\0';
1630     }
1631 
1632     c.column_value = PromiseGetConstraintAsRval(pp, "field_value", RVAL_TYPE_SCALAR);
1633     c.column_operation = PromiseGetConstraintAsRval(pp, "field_operation", RVAL_TYPE_SCALAR);
1634     c.extend_columns = PromiseGetConstraintAsBoolean(ctx, "extend_fields", pp);
1635     c.blanks_ok = PromiseGetConstraintAsBoolean(ctx, "allow_blank_fields", pp);
1636     return c;
1637 }
1638 
1639 /*******************************************************************/
1640 /* Storage                                                         */
1641 /*******************************************************************/
1642 
GetMountConstraints(const EvalContext * ctx,const Promise * pp)1643 StorageMount GetMountConstraints(const EvalContext *ctx, const Promise *pp)
1644 {
1645     StorageMount m;
1646 
1647     m.mount_type = PromiseGetConstraintAsRval(pp, "mount_type", RVAL_TYPE_SCALAR);
1648     m.mount_source = PromiseGetConstraintAsRval(pp, "mount_source", RVAL_TYPE_SCALAR);
1649     m.mount_server = PromiseGetConstraintAsRval(pp, "mount_server", RVAL_TYPE_SCALAR);
1650     m.mount_options = PromiseGetConstraintAsList(ctx, "mount_options", pp);
1651     m.editfstab = PromiseGetConstraintAsBoolean(ctx, "edit_fstab", pp);
1652     m.unmount = PromiseGetConstraintAsBoolean(ctx, "unmount", pp);
1653 
1654     return m;
1655 }
1656 
1657 /*******************************************************************/
1658 
GetVolumeConstraints(const EvalContext * ctx,const Promise * pp)1659 StorageVolume GetVolumeConstraints(const EvalContext *ctx, const Promise *pp)
1660 {
1661     StorageVolume v;
1662     char *value;
1663 
1664     v.check_foreign = PromiseGetConstraintAsBoolean(ctx, "check_foreign", pp);
1665     value = PromiseGetConstraintAsRval(pp, "freespace", RVAL_TYPE_SCALAR);
1666 
1667     v.freespace = (long) IntFromString(value);
1668     value = PromiseGetConstraintAsRval(pp, "sensible_size", RVAL_TYPE_SCALAR);
1669     v.sensible_size = (int) IntFromString(value);
1670     value = PromiseGetConstraintAsRval(pp, "sensible_count", RVAL_TYPE_SCALAR);
1671     v.sensible_count = (int) IntFromString(value);
1672     v.scan_arrivals = PromiseGetConstraintAsBoolean(ctx, "scan_arrivals", pp);
1673 
1674 // defaults
1675     if (v.sensible_size == CF_NOINT)
1676     {
1677         v.sensible_size = 1000;
1678     }
1679 
1680     if (v.sensible_count == CF_NOINT)
1681     {
1682         v.sensible_count = 2;
1683     }
1684 
1685     return v;
1686 }
1687 
GetReportConstraints(const EvalContext * ctx,const Promise * pp)1688 Report GetReportConstraints(const EvalContext *ctx, const Promise *pp)
1689 {
1690  Report r = {0};
1691 
1692  r.result = PromiseGetConstraintAsRval(pp, "bundle_return_value_index", RVAL_TYPE_SCALAR);
1693 
1694     if (PromiseGetConstraintAsRval(pp, "lastseen", RVAL_TYPE_SCALAR))
1695     {
1696         r.havelastseen = true;
1697         r.lastseen = PromiseGetConstraintAsInt(ctx, "lastseen", pp);
1698 
1699         if (r.lastseen == CF_NOINT)
1700         {
1701             r.lastseen = 0;
1702         }
1703     }
1704     else
1705     {
1706         r.havelastseen = false;
1707         r.lastseen = 0;
1708     }
1709 
1710     if (!PromiseGetConstraintAsReal(ctx, "intermittency", pp, &r.intermittency))
1711     {
1712         r.intermittency = 0;
1713     }
1714 
1715     r.haveprintfile = PromiseGetConstraintAsBoolean(ctx, "printfile", pp);
1716     r.filename = PromiseGetConstraintAsRval(pp, "file_to_print", RVAL_TYPE_SCALAR);
1717     r.numlines = PromiseGetConstraintAsInt(ctx, "number_of_lines", pp);
1718 
1719     if (r.numlines == CF_NOINT)
1720     {
1721         r.numlines = 5;
1722     }
1723 
1724     r.showstate = PromiseGetConstraintAsList(ctx, "showstate", pp);
1725 
1726     r.friend_pattern = PromiseGetConstraintAsRval(pp, "friend_pattern", RVAL_TYPE_SCALAR);
1727 
1728     r.to_file = PromiseGetConstraintAsRval(pp, "report_to_file", RVAL_TYPE_SCALAR);
1729 
1730     if ((r.result) && ((r.haveprintfile) || (r.filename) || (r.showstate) || (r.to_file) || (r.lastseen)))
1731     {
1732         Log(LOG_LEVEL_ERR, "bundle_return_value promise for '%s' in bundle '%s' with too many constraints (ignored)", pp->promiser, PromiseGetBundle(pp)->name);
1733     }
1734 
1735     return r;
1736 }
1737 
1738 /*******************************************************************/
1739 
GetInsertSelectConstraints(const EvalContext * ctx,const Promise * pp)1740 LineSelect GetInsertSelectConstraints(const EvalContext *ctx, const Promise *pp)
1741 {
1742     LineSelect s;
1743 
1744     s.startwith_from_list = PromiseGetConstraintAsList(ctx, "insert_if_startwith_from_list", pp);
1745     s.not_startwith_from_list = PromiseGetConstraintAsList(ctx, "insert_if_not_startwith_from_list", pp);
1746     s.match_from_list = PromiseGetConstraintAsList(ctx, "insert_if_match_from_list", pp);
1747     s.not_match_from_list = PromiseGetConstraintAsList(ctx, "insert_if_not_match_from_list", pp);
1748     s.contains_from_list = PromiseGetConstraintAsList(ctx, "insert_if_contains_from_list", pp);
1749     s.not_contains_from_list = PromiseGetConstraintAsList(ctx, "insert_if_not_contains_from_list", pp);
1750 
1751     return s;
1752 }
1753 
1754 /*******************************************************************/
1755 
GetDeleteSelectConstraints(const EvalContext * ctx,const Promise * pp)1756 LineSelect GetDeleteSelectConstraints(const EvalContext *ctx, const Promise *pp)
1757 {
1758     LineSelect s;
1759 
1760     s.startwith_from_list = PromiseGetConstraintAsList(ctx, "delete_if_startwith_from_list", pp);
1761     s.not_startwith_from_list = PromiseGetConstraintAsList(ctx, "delete_if_not_startwith_from_list", pp);
1762     s.match_from_list = PromiseGetConstraintAsList(ctx, "delete_if_match_from_list", pp);
1763     s.not_match_from_list = PromiseGetConstraintAsList(ctx, "delete_if_not_match_from_list", pp);
1764     s.contains_from_list = PromiseGetConstraintAsList(ctx, "delete_if_contains_from_list", pp);
1765     s.not_contains_from_list = PromiseGetConstraintAsList(ctx, "delete_if_not_contains_from_list", pp);
1766 
1767     return s;
1768 }
1769 
1770 /*******************************************************************/
1771 
GetMeasurementConstraint(const EvalContext * ctx,const Promise * pp)1772 Measurement GetMeasurementConstraint(const EvalContext *ctx, const Promise *pp)
1773 {
1774     Measurement m;
1775     char *value;
1776 
1777     m.stream_type = PromiseGetConstraintAsRval(pp, "stream_type", RVAL_TYPE_SCALAR);
1778 
1779     value = PromiseGetConstraintAsRval(pp, "data_type", RVAL_TYPE_SCALAR);
1780     m.data_type = DataTypeFromString(value);
1781 
1782     if (m.data_type == CF_DATA_TYPE_NONE)
1783     {
1784         m.data_type = CF_DATA_TYPE_STRING;
1785     }
1786 
1787     m.history_type = PromiseGetConstraintAsRval(pp, "history_type", RVAL_TYPE_SCALAR);
1788     m.select_line_matching = PromiseGetConstraintAsRval(pp, "select_line_matching", RVAL_TYPE_SCALAR);
1789     m.select_line_number = PromiseGetConstraintAsInt(ctx, "select_line_number", pp);
1790     m.policy = MeasurePolicyFromString(PromiseGetConstraintAsRval(pp, "select_multiline_policy", RVAL_TYPE_SCALAR));
1791 
1792     m.extraction_regex = PromiseGetConstraintAsRval(pp, "extraction_regex", RVAL_TYPE_SCALAR);
1793     m.units = PromiseGetConstraintAsRval(pp, "units", RVAL_TYPE_SCALAR);
1794     m.growing = PromiseGetConstraintAsBoolean(ctx, "track_growing_file", pp);
1795     return m;
1796 }
1797 
1798 /*******************************************************************/
1799 
GetDatabaseConstraints(const EvalContext * ctx,const Promise * pp)1800 Database GetDatabaseConstraints(const EvalContext *ctx, const Promise *pp)
1801 {
1802     Database d;
1803     char *value;
1804 
1805     d.db_server_owner = PromiseGetConstraintAsRval(pp, "db_server_owner", RVAL_TYPE_SCALAR);
1806     d.db_server_password = PromiseGetConstraintAsRval(pp, "db_server_password", RVAL_TYPE_SCALAR);
1807     d.db_server_host = PromiseGetConstraintAsRval(pp, "db_server_host", RVAL_TYPE_SCALAR);
1808     d.db_connect_db = PromiseGetConstraintAsRval(pp, "db_server_connection_db", RVAL_TYPE_SCALAR);
1809     d.type = PromiseGetConstraintAsRval(pp, "database_type", RVAL_TYPE_SCALAR);
1810     d.server = PromiseGetConstraintAsRval(pp, "database_server", RVAL_TYPE_SCALAR);
1811     d.columns = PromiseGetConstraintAsList(ctx, "database_columns", pp);
1812     d.rows = PromiseGetConstraintAsList(ctx, "database_rows", pp);
1813     d.operation = PromiseGetConstraintAsRval(pp, "database_operation", RVAL_TYPE_SCALAR);
1814     d.exclude = PromiseGetConstraintAsList(ctx, "registry_exclude", pp);
1815 
1816     value = PromiseGetConstraintAsRval(pp, "db_server_type", RVAL_TYPE_SCALAR);
1817     d.db_server_type = DatabaseTypeFromString(value);
1818 
1819     if (value && ((d.db_server_type) == DATABASE_TYPE_NONE))
1820     {
1821         Log(LOG_LEVEL_ERR, "Unsupported database type '%s' in databases promise", value);
1822         PromiseRef(LOG_LEVEL_ERR, pp);
1823     }
1824 
1825     return d;
1826 }
1827