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