cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

verify_vars.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 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 <verify_vars.h>
26 
27 #include <actuator.h>
28 #include <attributes.h>
29 #include <regex.h> /* CompileRegex,StringMatchFullWithPrecompiledRegex */
30 #include <buffer.h>
31 #include <misc_lib.h>
32 #include <fncall.h>
33 #include <rlist.h>
34 #include <conversion.h>
35 #include <expand.h>
36 #include <scope.h>
37 #include <promises.h>
38 #include <vars.h>
39 #include <matching.h>
40 #include <syntax.h>
41 #include <audit.h>
42 #include <string_lib.h>
43 #include <cleanup.h>
44 
45 typedef struct
46 {
50  Constraint *cp_save; // e.g. string => "foo"
52 
53 
55 static bool Epimenides(EvalContext *ctx, const char *ns, const char *scope, const char *var, Rval rval, int level);
56 static bool CompareRval(const void *rval1_item, RvalType rval1_type, const void *rval2_item, RvalType rval2_type);
57 
58 static bool IsLegalVariableName(EvalContext *ctx, const Promise *pp)
59 {
60  const char *var_name = pp->promiser;
61 
62  /* TODO: remove at some point (global, leaked), but for now
63  * this offers an attractive speedup. */
64  static pcre *rx = NULL;
65  if (!rx)
66  {
67  /* \200-\377 is there for multibyte unicode characters */
68  rx = CompileRegex("[a-zA-Z0-9_\200-\377.]+(\\[.+\\])*"); /* Known leak, see TODO. */
69  }
70 
71  if (!StringMatchFullWithPrecompiledRegex(rx, var_name))
72  {
73  return false;
74  }
75 
76  char *bracket = strchr(var_name, '[');
77  char *dot = strchr(var_name, '.');
78  /* we only care about variable name prefix, not dots inside array keys */
79  if ((dot != NULL) && ((bracket == NULL) || (dot < bracket)))
80  {
81  /* detect and prevent remote bundle variable injection (CFE-1915) */
82  char *prefix = xstrndup(var_name, dot - var_name);
83  const Bundle *cur_bundle = PromiseGetBundle(pp);
84 
85  if (!StringEqual(prefix, cur_bundle->name))
86  {
88  "Variable '%s' may be attempted to be injected into a remote bundle",
89  var_name);
91  {
92  Log(LOG_LEVEL_ERR, "Remote bundle variable injection detected!");
93  free(prefix);
94  return false;
95  }
96  /* the conflicting bundle may be defined later, we need to remember
97  * this promise as potentially dangerous */
98  EvalContextPushRemoteVarPromise(ctx, prefix, pp->org_pp);
99  }
100  free(prefix);
101  }
102 
103  return true;
104 }
105 
106 // TODO why not printing that new definition is skipped?
107 // TODO what with ifdefined?
108 
110  ARG_UNUSED void *param)
111 {
113 
114  Log(LOG_LEVEL_DEBUG, "Evaluating vars promise: %s", pp->promiser);
116  "ok_redefine=%d, drop_undefined=%d, should_converge=%d",
117  opts.ok_redefine, opts.drop_undefined, opts.should_converge);
118 
119  if (!opts.should_converge)
120  {
122  "Skipping vars promise because should_converge=false");
123  return PROMISE_RESULT_NOOP;
124  }
125 
126 // opts.drop_undefined = true; /* always remove @{unresolved_list} */
127 
129  // More consideration needs to be given to using these
130  //a.transaction = GetTransactionConstraints(pp);
131 
132  /* Warn if promise locking was used with a promise that doesn't support it
133  * (which applies to all of 'vars', 'meta' and 'defaults' promises handled
134  * by this code).
135  * (Only do this in the first pass in cf-promises, we don't have to repeat
136  * the warning over and over.) */
138  {
139  int ifelapsed = PromiseGetConstraintAsInt(ctx, "ifelapsed", pp);
140  if (ifelapsed != CF_NOINT)
141  {
143  "ifelapsed attribute specified in action body for %s promise '%s',"
144  " but %s promises do not support promise locking",
147  }
148  int expireafter = PromiseGetConstraintAsInt(ctx, "expireafter", pp);
149  if (expireafter != CF_NOINT)
150  {
152  "expireafter attribute specified in action body for %s promise '%s',"
153  " but %s promises do not support promise locking",
156  }
157  }
158 
160 
162  if (strcmp("meta", pp->parent_promise_type->name) == 0)
163  {
164  VarRefSetMeta(ref, true);
165  }
166 
167  DataType existing_value_type = CF_DATA_TYPE_NONE;
168  const void *existing_value;
169  if (IsExpandable(pp->promiser))
170  {
171  existing_value = NULL;
172  }
173  else
174  {
175  existing_value = EvalContextVariableGet(ctx, ref, &existing_value_type);
176  }
177 
178  Rval rval = opts.cp_save->rval;
179  PromiseResult result;
180 
181  if (rval.item != NULL || rval.type == RVAL_TYPE_LIST)
182  {
183  DataType data_type = DataTypeFromString(opts.cp_save->lval);
184 
185  if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL)
186  {
187  FnCall *fp = RvalFnCallValue(rval);
188  const FnCallType *fn = FnCallTypeGet(fp->name);
189  if (!fn)
190  {
191  assert(false && "Canary: should have been caught before this point");
192  FatalError(ctx, "While setting variable '%s' in bundle '%s', unknown function '%s'",
193  pp->promiser, PromiseGetBundle(pp)->name, fp->name);
194  }
195 
196  if (fn->dtype != DataTypeFromString(opts.cp_save->lval))
197  {
198  FatalError(ctx, "While setting variable '%s' in bundle '%s', variable declared type '%s' but function '%s' returns type '%s'",
199  pp->promiser, PromiseGetBundle(pp)->name, opts.cp_save->lval,
200  fp->name, DataTypeToString(fn->dtype));
201  }
202 
203  if (existing_value_type != CF_DATA_TYPE_NONE)
204  {
205  // Already did this
206  VarRefDestroy(ref);
207  return PROMISE_RESULT_NOOP;
208  }
209 
210  FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp);
211 
212  if (res.status == FNCALL_FAILURE)
213  {
214  /* We do not assign variables to failed fn calls */
215  if (EvalContextGetPass(ctx) == CF_DONEPASSES-1) {
216  // If we still fail at last pass, make a log
217  Log(LOG_LEVEL_VERBOSE, "While setting variable '%s' in bundle '%s', function '%s' failed - skipping",
218  pp->promiser, PromiseGetBundle(pp)->name, fp->name);
219  }
220  RvalDestroy(res.rval);
221  VarRefDestroy(ref);
222  return PROMISE_RESULT_NOOP;
223  }
224  else
225  {
226  rval = res.rval;
227  }
228  }
229  else
230  {
231  Buffer *conv = BufferNew();
232  bool malformed = false, misprint = false;
233 
234  if (strcmp(opts.cp_save->lval, "int") == 0)
235  {
236  long int asint = IntFromString(opts.cp_save->rval.item);
237  if (asint == CF_NOINT)
238  {
239  malformed = true;
240  }
241  else if (0 > BufferPrintf(conv, "%ld", asint))
242  {
243  misprint = true;
244  }
245  else
246  {
247  rval = RvalNew(BufferData(conv), opts.cp_save->rval.type);
248  }
249  }
250  else if (strcmp(opts.cp_save->lval, "real") == 0)
251  {
252  double real_value;
253  if (!DoubleFromString(opts.cp_save->rval.item, &real_value))
254  {
255  malformed = true;
256  }
257  else if (0 > BufferPrintf(conv, "%lf", real_value))
258  {
259  misprint = true;
260  }
261  else
262  {
263  rval = RvalNew(BufferData(conv), opts.cp_save->rval.type);
264  }
265  }
266  else
267  {
268  rval = RvalCopy(opts.cp_save->rval);
269  }
270  BufferDestroy(conv);
271 
272  if (malformed)
273  {
274  /* Arises when opts->cp_save->rval.item isn't yet expanded. */
275  /* Has already been logged by *FromString */
276  VarRefDestroy(ref);
277  return PROMISE_RESULT_FAIL;
278  }
279  else if (misprint)
280  {
281  /* Even though no problems with memory allocation can
282  * get here, there might be other problems. */
283  UnexpectedError("Problems writing to buffer");
284  VarRefDestroy(ref);
285  return PROMISE_RESULT_FAIL;
286  }
287  else if (rval.type == RVAL_TYPE_LIST)
288  {
289  Rlist *rval_list = RvalRlistValue(rval);
290  RlistFlatten(ctx, &rval_list);
291  rval.item = rval_list;
292  }
293  }
294 
295  if (Epimenides(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, pp->promiser, rval, 0))
296  {
297  Log(LOG_LEVEL_ERR, "Variable '%s' contains itself indirectly - an unkeepable promise", pp->promiser);
298  DoCleanupAndExit(EXIT_FAILURE);
299  }
300  else
301  {
302  /* See if the variable needs recursively expanding again */
303 
304  Rval returnval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ref->ns, ref->scope, rval, true, pp);
305 
306  RvalDestroy(rval);
307 
308  // freed before function exit
309  rval = returnval;
310  }
311 
312  /* If variable did resolve but we're not allowed to modify it. */
313  /* ok_redefine: only on second iteration, else we ignore broken promises. TODO wat? */
314  if (existing_value_type != CF_DATA_TYPE_NONE &&
315  !opts.ok_redefine)
316  {
317  if (!CompareRval(existing_value, DataTypeToRvalType(existing_value_type),
318  rval.item, rval.type))
319  {
320  switch (rval.type)
321  {
322  /* TODO redefinition shouldn't be mentioned. Maybe handle like normal variable definition/ */
323  case RVAL_TYPE_SCALAR:
324  Log(LOG_LEVEL_VERBOSE, "V: Skipping redefinition of constant scalar '%s': from '%s' to '%s'",
325  pp->promiser, (const char *)existing_value, RvalScalarValue(rval));
327  break;
328 
329  case RVAL_TYPE_LIST:
330  {
331  Log(LOG_LEVEL_VERBOSE, "V: Skipping redefinition of constant list '%s'", pp->promiser);
332  Writer *w = StringWriter();
333  RlistWrite(w, existing_value);
334  char *oldstr = StringWriterClose(w);
335  Log(LOG_LEVEL_DEBUG, "Old value: %s", oldstr);
336  free(oldstr);
337 
338  w = StringWriter();
339  RlistWrite(w, rval.item);
340  char *newstr = StringWriterClose(w);
341  Log(LOG_LEVEL_DEBUG, "Skipped new value: %s", newstr);
342  free(newstr);
343 
345  }
346  break;
347 
348  case RVAL_TYPE_CONTAINER:
349  case RVAL_TYPE_FNCALL:
351  break;
352  }
353  }
354 
355  RvalDestroy(rval);
356  VarRefDestroy(ref);
357  return PROMISE_RESULT_NOOP;
358  }
359 
360  if (IsCf3VarString(pp->promiser))
361  {
362  // Unexpanded variables, we don't do anything with
363  RvalDestroy(rval);
364  VarRefDestroy(ref);
365  return PROMISE_RESULT_NOOP;
366  }
367 
368  if (!IsLegalVariableName(ctx, pp))
369  {
370  Log(LOG_LEVEL_ERR, "Variable identifier '%s' is not legal", pp->promiser);
372  RvalDestroy(rval);
373  VarRefDestroy(ref);
374  return PROMISE_RESULT_NOOP;
375  }
376 
377  if (rval.type == RVAL_TYPE_LIST)
378  {
379  if (opts.drop_undefined)
380  {
381  Rlist *stripped = RvalRlistValue(rval);
382  Rlist *entry = stripped;
383  while (entry)
384  {
385  Rlist *delete_me = NULL;
386  if (IsNakedVar(RlistScalarValue(entry), '@'))
387  {
388  delete_me = entry;
389  }
390  entry = entry->next;
391  RlistDestroyEntry(&stripped, delete_me);
392  }
393  rval.item = stripped;
394  }
395 
396  for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next)
397  {
398  switch (rp->val.type)
399  {
400  case RVAL_TYPE_SCALAR:
401  break;
402 
403  default:
404  // Cannot assign variable because value is a list containing a non-scalar item
405  VarRefDestroy(ref);
406  RvalDestroy(rval);
407  return PROMISE_RESULT_NOOP;
408  }
409  }
410  }
411 
412  if (ref->num_indices > 0)
413  {
414  if (data_type == CF_DATA_TYPE_CONTAINER)
415  {
416  char *lval_str = VarRefToString(ref, true);
417  Log(LOG_LEVEL_ERR, "Cannot assign a container to an indexed variable name '%s'. Should be assigned to '%s' instead",
418  lval_str, ref->lval);
419  free(lval_str);
420  VarRefDestroy(ref);
421  RvalDestroy(rval);
422  return PROMISE_RESULT_NOOP;
423  }
424  else
425  {
426  DataType existing_type;
427  VarRef *base_ref = VarRefCopyIndexless(ref);
428  if (EvalContextVariableGet(ctx, ref, &existing_type) && existing_type == CF_DATA_TYPE_CONTAINER)
429  {
430  char *lval_str = VarRefToString(ref, true);
431  char *base_ref_str = VarRefToString(base_ref, true);
432  Log(LOG_LEVEL_ERR, "Cannot assign value to indexed variable name '%s', because a container is already assigned to the base name '%s'",
433  lval_str, base_ref_str);
434  free(lval_str);
435  free(base_ref_str);
436  VarRefDestroy(base_ref);
437  VarRefDestroy(ref);
438  RvalDestroy(rval);
439  return PROMISE_RESULT_NOOP;
440  }
441  VarRefDestroy(base_ref);
442  }
443  }
444 
445 
446  DataType required_datatype = DataTypeFromString(opts.cp_save->lval);
447  if (rval.type != DataTypeToRvalType(required_datatype))
448  {
449  char *ref_str = VarRefToString(ref, true);
450  char *value_str = RvalToString(rval);
451  Log(LOG_LEVEL_ERR, "Variable '%s' expected a variable of type '%s', but was given incompatible value '%s'",
452  ref_str, DataTypeToString(required_datatype), value_str);
454 
455  free(ref_str);
456  free(value_str);
457  VarRefDestroy(ref);
458  RvalDestroy(rval);
459  return PROMISE_RESULT_FAIL;
460  }
461 
462  /* WRITE THE VARIABLE AT LAST. */
463  bool success = EvalContextVariablePut(ctx, ref, rval.item, required_datatype, "source=promise");
464 
465  if (!success)
466  {
468  "Unable to converge %s.%s value (possibly empty or infinite regression)",
469  ref->scope, pp->promiser);
471 
472  VarRefDestroy(ref);
473  RvalDestroy(rval);
474  return PROMISE_RESULT_FAIL;
475  }
476 
477  Rlist *promise_meta = PromiseGetConstraintAsList(ctx, "meta", pp);
478  if (promise_meta)
479  {
480  StringSet *class_meta = EvalContextVariableTags(ctx, ref);
481  Buffer *print;
482  for (const Rlist *rp = promise_meta; rp; rp = rp->next)
483  {
484  StringSetAdd(class_meta, xstrdup(RlistScalarValue(rp)));
485  print = StringSetToBuffer(class_meta, ',');
487  "Added tag %s to class %s, tags now [%s]",
488  RlistScalarValue(rp), pp->promiser, BufferData(print));
489  BufferDestroy(print);
490  }
491  }
492 
493  result = PROMISE_RESULT_NOOP;
494  }
495  else
496  {
497  Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser);
498  Log(LOG_LEVEL_ERR, "Rule from %s at/before line %zu", PromiseGetBundle(pp)->source_path, opts.cp_save->offset.line);
499  result = PROMISE_RESULT_FAIL;
500  }
501 
502  /*
503  * FIXME: Variable promise are exempt from normal evaluation logic still, so
504  * they are not pushed to evaluation stack before being evaluated. Due to
505  * this reason, we cannot call cfPS here to set classes, as it will error
506  * out with ProgrammingError.
507  *
508  * In order to support 'classes' body for variables as well, we call
509  * ClassAuditLog explicitly.
510  */
511  ClassAuditLog(ctx, pp, &a, result);
512 
513  VarRefDestroy(ref);
514  RvalDestroy(rval);
515 
516  return result;
517 }
518 
519 static bool CompareRval(const void *rval1_item, RvalType rval1_type,
520  const void *rval2_item, RvalType rval2_type)
521 {
522  if (rval1_type != rval2_type)
523  {
524  return -1;
525  }
526 
527  switch (rval1_type)
528  {
529  case RVAL_TYPE_SCALAR:
530 
531  if (IsCf3VarString(rval1_item) || IsCf3VarString(rval2_item))
532  {
533  return -1; // inconclusive
534  }
535 
536  if (strcmp(rval1_item, rval2_item) != 0)
537  {
538  return false;
539  }
540 
541  break;
542 
543  case RVAL_TYPE_LIST:
544  return RlistEqual(rval1_item, rval2_item);
545 
546  case RVAL_TYPE_FNCALL:
547  return -1;
548 
549  default:
550  return -1;
551  }
552 
553  return true;
554 }
555 
556 static bool Epimenides(EvalContext *ctx, const char *ns, const char *scope, const char *var, Rval rval, int level)
557 {
558  switch (rval.type)
559  {
560  case RVAL_TYPE_SCALAR:
561 
562  if (StringContainsVar(RvalScalarValue(rval), var))
563  {
564  Log(LOG_LEVEL_ERR, "Scalar variable '%s' contains itself (non-convergent) '%s'", var, RvalScalarValue(rval));
565  return true;
566  }
567 
568  if (IsCf3VarString(RvalScalarValue(rval)))
569  {
570  Buffer *exp = BufferNew();
571  ExpandScalar(ctx, ns, scope, RvalScalarValue(rval), exp);
572 
573  if (strcmp(BufferData(exp), RvalScalarValue(rval)) == 0)
574  {
575  BufferDestroy(exp);
576  return false;
577  }
578 
579  if (level > 3)
580  {
581  BufferDestroy(exp);
582  return false;
583  }
584 
585  if (Epimenides(ctx, ns, scope, var, (Rval) { BufferGet(exp), RVAL_TYPE_SCALAR}, level + 1))
586  {
587  BufferDestroy(exp);
588  return true;
589  }
590 
591  BufferDestroy(exp);
592  }
593 
594  break;
595 
596  case RVAL_TYPE_LIST:
597  for (const Rlist *rp = RvalRlistValue(rval); rp != NULL; rp = rp->next)
598  {
599  if (Epimenides(ctx, ns, scope, var, rp->val, level))
600  {
601  return true;
602  }
603  }
604  break;
605 
606  case RVAL_TYPE_CONTAINER:
607  case RVAL_TYPE_FNCALL:
609  return false;
610  }
611 
612  return false;
613 }
614 
615 /**
616  * @brief Collects variable constraints controlling how the promise should be converged
617  */
619 {
621  opts.drop_undefined = false;
622  opts.cp_save = NULL; /* main variable value */
623  /* By default allow variable redefinition, use "policy" constraint
624  * to override. */
625  opts.ok_redefine = true;
626  /* Main return value: becomes true at the end of the function. */
627  opts.should_converge = false;
628 
629  if (!IsDefinedClass(ctx, pp->classes))
630  {
631  return opts;
632  }
633 
634  int num_values = 0;
635  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
636  {
637  Constraint *cp = SeqAt(pp->conlist, i);
638 
639  if (strcmp(cp->lval, "comment") == 0)
640  {
641  // Comments don't affect convergence
642  // Unclear why this is in the constraint list in the first place?
643  continue;
644  }
645  else if (cp->rval.item == NULL && cp->rval.type != RVAL_TYPE_LIST)
646  {
647  // No right value, considered empty
648  continue;
649  }
650  else if (strcmp(cp->lval, "ifvarclass") == 0 ||
651  strcmp(cp->lval, "if") == 0)
652  {
653  switch (cp->rval.type)
654  {
655  case RVAL_TYPE_SCALAR:
656  if (!IsDefinedClass(ctx, cp->rval.item))
657  {
658  return opts;
659  }
660 
661  break;
662 
663  case RVAL_TYPE_FNCALL:
664  {
665  bool excluded = false;
666 
667  /* eval it: e.g. ifvarclass => not("a_class") */
668 
669  Rval res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), cp->rval.item, pp).rval;
670 
671  /* Don't continue unless function was evaluated properly */
672  if (res.type != RVAL_TYPE_SCALAR)
673  {
674  RvalDestroy(res);
675  return opts;
676  }
677 
678  excluded = !IsDefinedClass(ctx, res.item);
679 
680  RvalDestroy(res);
681 
682  if (excluded)
683  {
684  return opts;
685  }
686  }
687  break;
688 
689  default:
690  Log(LOG_LEVEL_ERR, "Invalid if/ifvarclass type '%c': should be string or function", cp->rval.type);
691  }
692  }
693  else if (strcmp(cp->lval, "policy") == 0)
694  {
695  if (strcmp(cp->rval.item, "ifdefined") == 0)
696  {
697  opts.drop_undefined = true;
698  }
699  else if (strcmp(cp->rval.item, "constant") == 0)
700  {
701  opts.ok_redefine = false;
702  }
703  }
704  else if (DataTypeFromString(cp->lval) != CF_DATA_TYPE_NONE)
705  {
706  num_values++;
707  opts.cp_save = cp;
708  }
709  }
710 
711  if (opts.cp_save == NULL)
712  {
713  Log(LOG_LEVEL_WARNING, "Incomplete vars promise: %s",
714  pp->promiser);
716  return opts;
717  }
718 
719  if (num_values > 2)
720  {
722  "Variable '%s' breaks its own promise with multiple (%d) values",
723  pp->promiser, num_values);
725  return opts;
726  }
727 
728  /* All constraints look OK, and classes are defined. Move forward with
729  * this promise. */
730  opts.should_converge = true;
731 
732  return opts;
733 }
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
char * xstrndup(const char *str, size_t n)
Definition: alloc.c:61
DefineClasses GetClassDefinitionConstraints(const EvalContext *ctx, const Promise *pp)
Definition: attributes.c:742
void FatalError(const EvalContext *ctx, char *s,...)
Definition: audit.c:94
void BufferDestroy(Buffer *buffer)
Destroys a buffer and frees the memory associated with it.
Definition: buffer.c:72
Buffer * BufferNew(void)
Buffer initialization routine.
Definition: buffer.c:48
char * BufferGet(Buffer *buffer)
This functions allows direct access to the storage inside Buffer.
Definition: buffer.c:239
const char * BufferData(const Buffer *buffer)
Provides a pointer to the internal data.
Definition: buffer.c:470
int BufferPrintf(Buffer *buffer, const char *format,...)
Stores complex data on the buffer.
Definition: buffer.c:348
#define ARG_UNUSED
Definition: cf-net.c:47
RvalType
Definition: cf3.defs.h:605
@ RVAL_TYPE_CONTAINER
Definition: cf3.defs.h:609
@ RVAL_TYPE_LIST
Definition: cf3.defs.h:607
@ RVAL_TYPE_SCALAR
Definition: cf3.defs.h:606
@ RVAL_TYPE_FNCALL
Definition: cf3.defs.h:608
@ RVAL_TYPE_NOPROMISEE
Definition: cf3.defs.h:610
PromiseResult
Definition: cf3.defs.h:122
@ PROMISE_RESULT_NOOP
Definition: cf3.defs.h:124
@ PROMISE_RESULT_FAIL
Definition: cf3.defs.h:127
@ AGENT_TYPE_COMMON
Definition: cf3.defs.h:401
DataType
Definition: cf3.defs.h:368
@ CF_DATA_TYPE_NONE
Definition: cf3.defs.h:385
@ CF_DATA_TYPE_CONTAINER
Definition: cf3.defs.h:384
#define CF_NOINT
Definition: cf3.defs.h:339
#define ZeroAttributes
Definition: cf3.defs.h:1626
#define CF_DONEPASSES
Definition: cf3.defs.h:344
AgentType THIS_AGENT_TYPE
Definition: cf3globals.c:43
void free(void *)
void DoCleanupAndExit(int ret)
Definition: cleanup.c:57
DataType DataTypeFromString(const char *name)
Definition: conversion.c:318
bool DoubleFromString(const char *s, double *value_out)
Definition: conversion.c:521
long IntFromString(const char *s)
Definition: conversion.c:390
const char * DataTypeToString(DataType type)
Definition: conversion.c:331
void ClassAuditLog(EvalContext *ctx, const Promise *pp, const Attributes *attr, PromiseResult status)
const StringSet * EvalContextGetBundleNames(const EvalContext *ctx)
StringSet * EvalContextVariableTags(const EvalContext *ctx, const VarRef *ref)
const void * EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, DataType *type_out)
void EvalContextPushRemoteVarPromise(EvalContext *ctx, const char *bundle_name, const Promise *pp)
int EvalContextGetPass(EvalContext *ctx)
bool EvalContextVariablePut(EvalContext *ctx, const VarRef *ref, const void *value, DataType type, const char *tags)
static bool IsDefinedClass(const EvalContext *ctx, const char *context)
Definition: eval_context.h:213
char * ExpandScalar(const EvalContext *ctx, const char *ns, const char *scope, const char *string, Buffer *out)
Definition: expand.c:516
Rval EvaluateFinalRval(EvalContext *ctx, const Policy *policy, const char *ns, const char *scope, Rval rval, bool forcelist, const Promise *pp)
Definition: expand.c:610
bool IsNakedVar(const char *str, char vtype)
Definition: expand.c:1198
bool IsExpandable(const char *str)
Definition: expand.c:1117
const FnCallType * FnCallTypeGet(const char *name)
Definition: fncall.c:430
FnCallResult FnCallEvaluate(EvalContext *ctx, const Policy *policy, FnCall *fp, const Promise *caller)
Definition: fncall.c:309
@ FNCALL_FAILURE
Definition: fncall.h:41
#define NULL
Definition: getopt1.c:56
@ LogDebug
Definition: log.h:34
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_MOD_VARS
Definition: logging.h:63
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_WARNING
Definition: logging.h:43
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
#define UnexpectedError(...)
Definition: misc_lib.h:38
Rlist * PromiseGetConstraintAsList(const EvalContext *ctx, const char *lval, const Promise *pp)
Get the Rlist value of the first effective constraint found matching, from a promise.
Definition: policy.c:2920
int PromiseGetConstraintAsInt(const EvalContext *ctx, const char *lval, const Promise *pp)
Get the int value of the first effective constraint found matching, from a promise.
Definition: policy.c:2724
const Policy * PromiseGetPolicy(const Promise *pp)
Definition: policy.c:2676
const Bundle * PromiseGetBundle(const Promise *pp)
Definition: policy.c:2671
void PromiseRef(LogLevel level, const Promise *pp)
Definition: promises.c:769
pcre * CompileRegex(const char *regex)
Definition: regex.c:37
bool StringMatchFullWithPrecompiledRegex(pcre *pattern, const char *str)
Definition: regex.c:121
bool RlistEqual(const Rlist *list1, const Rlist *list2)
Definition: rlist.c:1599
char * RlistScalarValue(const Rlist *rlist)
Definition: rlist.c:83
Rlist * RvalRlistValue(Rval rval)
Definition: rlist.c:153
FnCall * RvalFnCallValue(Rval rval)
Definition: rlist.c:141
char * RvalScalarValue(Rval rval)
Definition: rlist.c:129
void RlistWrite(Writer *writer, const Rlist *list)
Definition: rlist.c:1318
void RlistDestroyEntry(Rlist **liststart, Rlist *entry)
Definition: rlist.c:972
char * RvalToString(Rval rval)
Definition: rlist.c:1396
RvalType DataTypeToRvalType(DataType datatype)
Definition: rlist.c:44
void RvalDestroy(Rval rval)
Definition: rlist.c:940
Rval RvalNew(const void *item, RvalType type)
Definition: rlist.c:464
void RlistFlatten(EvalContext *ctx, Rlist **list)
Flattens an Rlist by expanding naked scalar list-variable members. Flattening is only one-level deep.
Definition: rlist.c:1534
Rval RvalCopy(Rval rval)
Definition: rlist.c:474
size_t SeqLength(const Seq *seq)
Length of the sequence.
Definition: sequence.c:354
static void * SeqAt(const Seq *seq, int i)
Definition: sequence.h:57
bool StringSetContains(const StringSet *set, const char *element)
Definition: set.c:34
Buffer * StringSetToBuffer(StringSet *set, const char delimiter)
Definition: set.c:117
void StringSetAdd(const StringSet *set, char *element)
Definition: set.c:34
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
DefineClasses classes
Definition: cf3.defs.h:1568
Definition: buffer.h:50
Definition: policy.h:70
char * name
Definition: policy.h:74
Rval rval
Definition: policy.h:133
SourceOffset offset
Definition: policy.h:138
char * lval
Definition: policy.h:132
Constraint * cp_save
Definition: verify_vars.c:50
FnCallStatus status
Definition: fncall.h:46
Rval rval
Definition: fncall.h:47
DataType dtype
Definition: fncall.h:78
Definition: fncall.h:31
char * name
Definition: fncall.h:32
char * name
Definition: policy.h:103
PromiseType * parent_promise_type
Definition: policy.h:111
const Promise * org_pp
Definition: policy.h:119
Seq * conlist
Definition: policy.h:117
char * promiser
Definition: policy.h:115
char * classes
Definition: policy.h:113
Definition: rlist.h:35
Rlist * next
Definition: rlist.h:37
Definition: cf3.defs.h:614
RvalType type
Definition: cf3.defs.h:616
void * item
Definition: cf3.defs.h:615
size_t line
Definition: policy.h:65
Definition: set.h:138
char * ns
char * scope
size_t num_indices
char * lval
Definition: writer.c:45
void VarRefDestroy(VarRef *ref)
void VarRefSetMeta(VarRef *ref, bool enabled)
VarRef * VarRefParseFromBundle(const char *var_ref_string, const Bundle *bundle)
Parse the variable reference in the context of a bundle. This means that the VarRef will inherit scop...
VarRef * VarRefCopyIndexless(const VarRef *ref)
char * VarRefToString(const VarRef *ref, bool qualified)
bool StringContainsVar(const char *s, const char *v)
Definition: vars.c:79
bool IsCf3VarString(const char *str)
Definition: vars.c:123
static bool CompareRval(const void *rval1_item, RvalType rval1_type, const void *rval2_item, RvalType rval2_type)
Definition: verify_vars.c:519
static bool Epimenides(EvalContext *ctx, const char *ns, const char *scope, const char *var, Rval rval, int level)
Definition: verify_vars.c:556
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, void *param)
Definition: verify_vars.c:109
static bool IsLegalVariableName(EvalContext *ctx, const Promise *pp)
Definition: verify_vars.c:58
static ConvergeVariableOptions CollectConvergeVariableOptions(EvalContext *ctx, const Promise *pp)
Collects variable constraints controlling how the promise should be converged.
Definition: verify_vars.c:618
char * StringWriterClose(Writer *writer)
Definition: writer.c:262
Writer * StringWriter(void)
Definition: writer.c:67