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