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)  

expand.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 <expand.h>
26 
27 #include <misc_lib.h>
28 #include <eval_context.h>
29 #include <policy.h>
30 #include <promises.h>
31 #include <vars.h>
32 #include <syntax.h>
33 #include <files_names.h>
34 #include <scope.h>
35 #include <matching.h>
36 #include <unix.h>
37 #include <attributes.h>
38 #include <fncall.h>
39 #include <iteration.h>
40 #include <audit.h>
41 #include <verify_vars.h>
42 #include <string_lib.h>
43 #include <conversion.h>
44 #include <verify_classes.h>
45 
46 /**
47  * VARIABLES AND PROMISE EXPANSION
48  *
49  * Expanding variables is easy -- expanding lists automagically requires
50  * some thought. Remember that
51  *
52  * promiser <=> RVAL_TYPE_SCALAR
53  * promisee <=> RVAL_TYPE_LIST
54  *
55  * For bodies we have
56  *
57  * lval <=> RVAL_TYPE_LIST | RVAL_TYPE_SCALAR
58  *
59  * Any list or container variable occurring within a scalar or in place of a
60  * scalar is assumed to be iterated i.e. $(name). See comments in iteration.c.
61  *
62  * Any list variable @(name) is *not iterated*, but dropped into place (see
63  * DeRefCopyPromise()).
64  *
65  * Please note that bodies cannot contain iterators.
66  *
67  * The full process of promise and variable expansion is mostly outlined in
68  * ExpandPromise() and ExpandPromiseAndDo() and the basic steps are:
69  *
70  * + Skip everything if the class guard is not defined.
71  *
72  * + DeRefCopyPromise(): *Copy the promise* while expanding '@' slists and body
73  * arguments and handling body inheritance. This requires one round of
74  * expansion with scopeid "body".
75  *
76  * + Push promise frame
77  *
78  * + MapIteratorsFromRval(): Parse all strings (promiser-promisee-constraints),
79  * find all unexpanded variables, mangle them if needed (if they are
80  * namespaced/scoped), and *initialise the wheels* in the iteration engine
81  * (iterctx) to iterate over iterable variables (slists and containers). See
82  * comments in iteration.c for further details.
83  *
84  * + For every iteration:
85  *
86  * - Push iteration frame
87  *
88  * - EvalContextStackPushPromiseIterationFrame()->ExpandDeRefPromise(): Make
89  * another copy of the promise with all constraints evaluated and variables
90  * expanded.
91  *
92  * -- NOTE: As a result all *functions are also evaluated*, even if they are
93  * not to be used immediately (for example promises that the actuator skips
94  * because of ifvarclass, see promises.c:ExpandDeRefPromise() ).
95  *
96  * -- (TODO IS IT CORRECT?) In a sub-bundle, create a new context and make
97  * hashes of the the transferred variables in the temporary context
98  *
99  * - Run the actuator (=act_on_promise= i.e. =VerifyWhateverPromise()=)
100  *
101  * - Pop iteration frame
102  *
103  * + Pop promise frame
104  *
105  */
106 
107 static inline char opposite(char c);
108 
109 static void PutHandleVariable(EvalContext *ctx, const Promise *pp)
110 {
111  char *handle_s;
112  const char *existing_handle = PromiseGetHandle(pp);
113 
114  if (existing_handle != NULL)
115  {
116  // This ordering is necessary to get automated canonification
117  handle_s = ExpandScalar(ctx, NULL, "this", existing_handle, NULL);
118  CanonifyNameInPlace(handle_s);
119  }
120  else
121  {
122  handle_s = xstrdup(PromiseID(pp)); /* default handle */
123  }
124 
126  "handle", handle_s,
127  CF_DATA_TYPE_STRING, "source=promise");
128  free(handle_s);
129 }
130 
131 /**
132  * Recursively go down the #rval and run PromiseIteratorPrepare() to take note
133  * of all iterables and mangle all rvals than need to be mangled before
134  * iterating.
135  */
137  PromiseIterator *iterctx,
138  Rval rval)
139 {
140  switch (rval.type)
141  {
142 
143  case RVAL_TYPE_SCALAR:
144  PromiseIteratorPrepare(iterctx, ctx, RvalScalarValue(rval));
145  break;
146 
147  case RVAL_TYPE_LIST:
148  for (const Rlist *rp = RvalRlistValue(rval);
149  rp != NULL; rp = rp->next)
150  {
151  MapIteratorsFromRval(ctx, iterctx, rp->val);
152  }
153  break;
154 
155  case RVAL_TYPE_FNCALL:
156  {
157  char *fn_name = RvalFnCallValue(rval)->name;
158 
159  /* Check function name. */
160  PromiseIteratorPrepare(iterctx, ctx, fn_name);
161 
162  /* Check each of the function arguments. */
163  /* EXCEPT on functions that use special variables: the mangled
164  * variables would never be resolved if they contain inner special
165  * variables (for example "$(bundle.A[$(this.k)])" and the returned
166  * slist would contained mangled vars like "bundle#A[1]" which would
167  * never resolve in future iterations. By skipping the iteration
168  * engine for now, the function returns an slist with unmangled
169  * entries, and the iteration engine works correctly on the next
170  * pass! */
171  if (strcmp(fn_name, "maplist") != 0 &&
172  strcmp(fn_name, "mapdata") != 0 &&
173  strcmp(fn_name, "maparray")!= 0)
174  {
175  for (Rlist *rp = RvalFnCallValue(rval)->args;
176  rp != NULL; rp = rp->next)
177  {
178  MapIteratorsFromRval(ctx, iterctx, rp->val);
179  }
180  }
181  break;
182  }
183 
184  case RVAL_TYPE_CONTAINER:
186  break;
187  }
188 }
189 
191  PromiseActuator *act_on_promise, void *param,
192  bool actuate_ifelse)
193 {
195 
196  /* In the case of ifelse() we must always include an extra round of "actuation"
197  * in the while loop below. PromiseIteratorNext() will return false in the case
198  * that there are doubly-unresolved Rvals like $($(missing)).
199  * We can't add an empty wheel because that is skipped as well as noted in
200  * libpromises/iteration.c ShouldAddVariableAsIterationWheel(). */
201  bool ifelse_actuated = !actuate_ifelse;
202 
203  /* TODO this loop could be completely skipped for for non vars/classes if
204  * act_on_promise is CommonEvalPromise(). */
205  while (PromiseIteratorNext(iterctx, ctx) || !ifelse_actuated)
206  {
207  /*
208  * ACTUAL WORK PART 1: Get a (another) copy of the promise.
209  *
210  * Basically this evaluates all constraints. As a result it evaluates
211  * all functions, even if they are not to be used immediately (for
212  * example promises that the actuator skips because of ifvarclass).
213  */
214  const Promise *pexp = /* expanded promise */
216  if (pexp == NULL) /* is the promise excluded? */
217  {
219  ifelse_actuated = true;
220  continue;
221  }
222 
223  /* ACTUAL WORK PART 2: run the actuator */
224  PromiseResult iteration_result = act_on_promise(ctx, pexp, param);
225 
226  /* iteration_result is always NOOP for PRE-EVAL. */
227  result = PromiseResultUpdate(result, iteration_result);
228 
229  /* Redmine#6484: Do not store promise handles during PRE-EVAL, to
230  * avoid package promise always running. */
231  if (act_on_promise != &CommonEvalPromise)
232  {
233  NotifyDependantPromises(ctx, pexp, iteration_result);
234  }
235 
236  /* EVALUATE VARS PROMISES again, allowing redefinition of
237  * variables. The theory behind this is that the "sampling rate" of
238  * vars promise needs to be double than the rest. */
239  if (strcmp(pexp->parent_promise_type->name, "vars") == 0 ||
240  strcmp(pexp->parent_promise_type->name, "meta") == 0)
241  {
242  if (act_on_promise != &VerifyVarPromise)
243  {
244  VerifyVarPromise(ctx, pexp, NULL);
245  }
246  }
247 
248  /* Why do we push/pop an iteration frame, if all iterated variables
249  * are Put() on the previous scope? */
251  ifelse_actuated = true;
252  }
253 
254  return result;
255 }
256 
258  PromiseActuator *act_on_promise, void *param)
259 {
260  if (!IsDefinedClass(ctx, pp->classes))
261  {
262  return PROMISE_RESULT_SKIPPED;
263  }
264 
265  /* 1. Copy the promise while expanding '@' slists and body arguments
266  * (including body inheritance). */
267  Promise *pcopy = DeRefCopyPromise(ctx, pp);
268 
270  PromiseIterator *iterctx = PromiseIteratorNew(pcopy);
271 
272  /* 2. Parse all strings (promiser-promisee-constraints), find all
273  unexpanded variables, mangle them if needed (if they are
274  namespaced/scoped), and start the iteration engine (iterctx) to
275  iterate over slists and containers. */
276 
277  MapIteratorsFromRval(ctx, iterctx,
278  (Rval) { pcopy->promiser, RVAL_TYPE_SCALAR });
279 
280  if (pcopy->promisee.item != NULL)
281  {
282  MapIteratorsFromRval(ctx, iterctx, pcopy->promisee);
283  }
284 
285  bool actuate_ifelse = false;
286  for (size_t i = 0; i < SeqLength(pcopy->conlist); i++)
287  {
288  Constraint *cp = SeqAt(pcopy->conlist, i);
289  if (cp->rval.type == RVAL_TYPE_FNCALL &&
290  strcmp(RvalFnCallValue(cp->rval)->name, "ifelse") == 0)
291  {
292  actuate_ifelse = true;
293  }
294  MapIteratorsFromRval(ctx, iterctx, cp->rval);
295  }
296 
297  /* 3. GO! */
298  PutHandleVariable(ctx, pcopy);
299  PromiseResult result = ExpandPromiseAndDo(ctx, iterctx,
300  act_on_promise, param, actuate_ifelse);
301 
303  PromiseIteratorDestroy(iterctx);
304  PromiseDestroy(pcopy);
305 
306  return result;
307 }
308 
309 
310 /*********************************************************************/
311 /*********************************************************************/
312 
314  const char *ns, const char *scope,
315  const void *rval_item, RvalType rval_type)
316 {
317  Rval returnval;
318  returnval.item = NULL;
319  returnval.type = RVAL_TYPE_NOPROMISEE;
320 
321  switch (rval_type)
322  {
323  case RVAL_TYPE_SCALAR:
324  returnval.item = ExpandScalar(ctx, ns, scope, rval_item, NULL);
325  returnval.type = RVAL_TYPE_SCALAR;
326  break;
327  case RVAL_TYPE_LIST:
328  returnval.item = ExpandList(ctx, ns, scope, rval_item, true);
329  returnval.type = RVAL_TYPE_LIST;
330  break;
331 
332  case RVAL_TYPE_FNCALL:
333  returnval.item = ExpandFnCall(ctx, ns, scope, rval_item);
334  returnval.type = RVAL_TYPE_FNCALL;
335  break;
336 
337  case RVAL_TYPE_CONTAINER:
338  returnval = RvalNew(rval_item, RVAL_TYPE_CONTAINER);
339  break;
340 
342  break;
343  }
344 
345  return returnval;
346 }
347 
348 /**
349  * Detects a variable expansion inside of a data/list reference, for example
350  * "@(${container_name})" or "@(prefix${container_name})" or
351  * "@(nspace:${container_name})" or "@(container_name[${field}])".
352  *
353  * @note This function doesn't have to be bullet-proof, it only needs to
354  * properly detect valid cases. The rest is left to the parser and code
355  * expanding variables.
356  */
357 static inline bool VariableDataOrListReference(const char *str)
358 {
359  assert(str != NULL);
360 
361  size_t len = strlen(str);
362 
363  /* at least '@($(X))' is needed */
364  if (len < 7)
365  {
366  return false;
367  }
368 
369  if (!((str[0] == '@') &&
370  ((str[1] == '{') || (str[1] == '('))))
371  {
372  return false;
373  }
374 
375  /* Check if, after '@(', there are only
376  * - characters allowed in data/list names or
377  * - ':' to separate namespace from the name or
378  * - '.' to separate bundle and variable name or,
379  * - '[' for data/list field/index specification,
380  * followed by "$(" or "${" with a matching close bracket somewhere. */
381  for (size_t i = 2; i < len; i++)
382  {
383  if (!(isalnum((int) str[i]) || (str[i] == '_') ||
384  (str[i] == ':') || (str[i] == '$') || (str[i] == '.') || (str[i] == '[')))
385  {
386  return false;
387  }
388 
389  if (str[i] == '$')
390  {
391  if (((i + 1) < len) && ((str[i + 1] == '{') || (str[i + 1] == '(')))
392  {
393  int close_bracket = (int) opposite(str[i+1]);
394  return (strchr(str + i + 2, close_bracket) != NULL);
395  }
396  else
397  {
398  return false;
399  }
400  }
401  }
402 
403  return false;
404 }
405 
407  const char *ns, const char *scope,
408  int expandnaked, Rval entry)
409 {
410  Rval expanded_data_list = {0};
411  /* If rval is something like '@($(container_name).field)', we need to expand
412  * the nested variable first. */
413  if (entry.type == RVAL_TYPE_SCALAR &&
415  {
416  entry = ExpandPrivateRval(ctx, ns, scope, entry.item, entry.type);
417  expanded_data_list = entry;
418  }
419 
420  if (entry.type == RVAL_TYPE_SCALAR &&
421  IsNakedVar(entry.item, '@'))
422  {
423  if (expandnaked)
424  {
425  char naked[CF_MAXVARSIZE];
426  GetNaked(naked, entry.item);
427 
428  if (IsExpandable(naked))
429  {
430  char *exp = ExpandScalar(ctx, ns, scope, naked, NULL);
431  strlcpy(naked, exp, sizeof(naked)); /* TODO err */
432  free(exp);
433  }
434 
435  /* Check again, it might have changed. */
436  if (!IsExpandable(naked))
437  {
438  VarRef *ref = VarRefParseFromScope(naked, scope);
439 
440  DataType value_type;
441  const void *value = EvalContextVariableGet(ctx, ref, &value_type);
442  VarRefDestroy(ref);
443 
444  if (value_type != CF_DATA_TYPE_NONE) /* variable found? */
445  {
446  Rval ret = ExpandPrivateRval(ctx, ns, scope, value,
447  DataTypeToRvalType(value_type));
448  RvalDestroy(expanded_data_list);
449  return ret;
450  }
451  }
452  }
453  else
454  {
455  Rval ret = RvalNew(entry.item, RVAL_TYPE_SCALAR);
456  RvalDestroy(expanded_data_list);
457  return ret;
458  }
459  }
460 
461  Rval ret = ExpandPrivateRval(ctx, ns, scope, entry.item, entry.type);
462  RvalDestroy(expanded_data_list);
463  return ret;
464 }
465 
467  const char *ns, const char *scope,
468  const Rlist *list, int expandnaked)
469 {
470  Rlist *start = NULL;
471 
472  for (const Rlist *rp = list; rp != NULL; rp = rp->next)
473  {
474  Rval returnval = ExpandListEntry(ctx, ns, scope, expandnaked, rp->val);
475  RlistAppend(&start, returnval.item, returnval.type);
476  RvalDestroy(returnval);
477  }
478 
479  return start;
480 }
481 
482 /*********************************************************************/
483 
485  const char *ns, const char *scope,
486  Rval rval)
487 {
488  // Allocates new memory for the copy
489  switch (rval.type)
490  {
491  case RVAL_TYPE_SCALAR:
492  return (Rval) { ExpandScalar(ctx, ns, scope, RvalScalarValue(rval), NULL),
494 
495  case RVAL_TYPE_FNCALL:
496  return (Rval) { ExpandFnCall(ctx, ns, scope, RvalFnCallValue(rval)),
498 
499  case RVAL_TYPE_CONTAINER:
500  case RVAL_TYPE_LIST:
503  }
504 
505  assert(false);
507 }
508 
509 /**
510  * Expand a #string into Buffer #out, returning the pointer to the string
511  * itself, inside the Buffer #out. If #out is NULL then the buffer will be
512  * created and destroyed internally.
513  *
514  * @retval NULL something went wrong
515  */
516 char *ExpandScalar(const EvalContext *ctx, const char *ns, const char *scope,
517  const char *string, Buffer *out)
518 {
519  bool out_belongs_to_us = false;
520 
521  if (out == NULL)
522  {
523  out = BufferNew();
524  out_belongs_to_us = true;
525  }
526 
527  assert(string != NULL);
528  assert(out != NULL);
529  Buffer *current_item = BufferNew();
530 
531  for (const char *sp = string; *sp != '\0'; sp++)
532  {
533  BufferClear(current_item);
534  ExtractScalarPrefix(current_item, sp, strlen(sp));
535 
536  BufferAppend(out, BufferData(current_item), BufferSize(current_item));
537  sp += BufferSize(current_item);
538  if (*sp == '\0')
539  {
540  break;
541  }
542 
543  BufferClear(current_item);
544  char varstring = sp[1];
545  ExtractScalarReference(current_item, sp, strlen(sp), true);
546  sp += BufferSize(current_item) + 2;
547 
548  if (IsCf3VarString(BufferData(current_item)))
549  {
550  Buffer *temp = BufferCopy(current_item);
551  BufferClear(current_item);
552  ExpandScalar(ctx, ns, scope, BufferData(temp), current_item);
553  BufferDestroy(temp);
554  }
555 
556  if (!IsExpandable(BufferData(current_item)))
557  {
559  BufferData(current_item),
560  ns, scope, CF_NS, '.');
561  DataType value_type;
562  const void *value = EvalContextVariableGet(ctx, ref, &value_type);
563  VarRefDestroy(ref);
564 
565  switch (DataTypeToRvalType(value_type))
566  {
567  case RVAL_TYPE_SCALAR:
568  assert(value != NULL);
569  BufferAppendString(out, value);
570  continue;
571  break;
572 
573  case RVAL_TYPE_CONTAINER:
574  {
575  assert(value != NULL);
576  const JsonElement *jvalue = value; /* instead of casts */
578  {
580  continue;
581  }
582  break;
583  }
584  default:
585  /* TODO Log() */
586  break;
587  }
588  }
589 
590  if (varstring == '{')
591  {
592  BufferAppendF(out, "${%s}", BufferData(current_item));
593  }
594  else
595  {
596  BufferAppendF(out, "$(%s)", BufferData(current_item));
597  }
598  }
599 
600  BufferDestroy(current_item);
601 
602  LogDebug(LOG_MOD_EXPAND, "ExpandScalar( %s : %s . %s ) => %s",
603  SAFENULL(ns), SAFENULL(scope), string, BufferData(out));
604 
605  return out_belongs_to_us ? BufferClose(out) : BufferGet(out);
606 }
607 
608 /*********************************************************************/
609 
611  const char *ns, const char *scope,
612  Rval rval, bool forcelist, const Promise *pp)
613 {
614  assert(ctx);
615  assert(policy);
616  Rval returnval;
617 
618  /* Treat lists specially. */
619  if (rval.type == RVAL_TYPE_SCALAR && IsNakedVar(rval.item, '@'))
620  {
621  char naked[CF_MAXVARSIZE];
622  GetNaked(naked, rval.item);
623 
624  if (IsExpandable(naked)) /* example: @(blah_$(blue)) */
625  {
626  returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
627  }
628  else
629  {
630  VarRef *ref = VarRefParseFromScope(naked, scope);
631  DataType value_type;
632  const void *value = EvalContextVariableGet(ctx, ref, &value_type);
633  VarRefDestroy(ref);
634 
635  if (DataTypeToRvalType(value_type) == RVAL_TYPE_LIST)
636  {
637  returnval.item = ExpandList(ctx, ns, scope, value, true);
638  returnval.type = RVAL_TYPE_LIST;
639  }
640  else
641  {
642  returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
643  }
644  }
645  }
646  else if (forcelist) /* We are replacing scalar @(name) with list */
647  {
648  returnval = ExpandPrivateRval(ctx, ns, scope, rval.item, rval.type);
649  }
650  else if (FnCallIsBuiltIn(rval))
651  {
652  returnval = RvalCopy(rval);
653  }
654  else
655  {
656  returnval = ExpandPrivateRval(ctx, NULL, "this", rval.item, rval.type);
657  }
658 
659  switch (returnval.type)
660  {
661  case RVAL_TYPE_SCALAR:
662  case RVAL_TYPE_CONTAINER:
663  break;
664 
665  case RVAL_TYPE_LIST:
666  for (Rlist *rp = RvalRlistValue(returnval); rp; rp = rp->next)
667  {
668  switch (rp->val.type)
669  {
670  case RVAL_TYPE_FNCALL:
671  {
672  FnCall *fp = RlistFnCallValue(rp);
673  rp->val = FnCallEvaluate(ctx, policy, fp, pp).rval;
674  FnCallDestroy(fp);
675  break;
676  }
677  case RVAL_TYPE_SCALAR:
680  {
681  void *prior = rp->val.item;
682  rp->val = ExpandPrivateRval(ctx, NULL, "this",
683  prior, RVAL_TYPE_SCALAR);
684  free(prior);
685  }
686  /* else: returnval unchanged. */
687  break;
688  default:
689  assert(!"Bad type for entry in Rlist");
690  }
691  }
692  break;
693 
694  case RVAL_TYPE_FNCALL:
695  if (FnCallIsBuiltIn(returnval))
696  {
697  FnCall *fp = RvalFnCallValue(returnval);
698  returnval = FnCallEvaluate(ctx, policy, fp, pp).rval;
699  FnCallDestroy(fp);
700  }
701  break;
702 
703  default:
704  assert(returnval.item == NULL); /* else we're leaking it */
705  returnval.item = NULL;
706  returnval.type = RVAL_TYPE_NOPROMISEE;
707  break;
708  }
709 
710  return returnval;
711 }
712 
713 /*********************************************************************/
714 
715 void BundleResolvePromiseType(EvalContext *ctx, const Bundle *bundle, const char *type, PromiseActuator *actuator)
716 {
717  for (size_t j = 0; j < SeqLength(bundle->promise_types); j++)
718  {
719  PromiseType *pt = SeqAt(bundle->promise_types, j);
720 
721  if (strcmp(pt->name, type) == 0)
722  {
724  for (size_t i = 0; i < SeqLength(pt->promises); i++)
725  {
726  Promise *pp = SeqAt(pt->promises, i);
727  ExpandPromise(ctx, pp, actuator, NULL);
728  }
730  }
731  }
732 }
733 
734 static int PointerCmp(const void *a, const void *b, ARG_UNUSED void *user_data)
735 {
736  if (a < b)
737  {
738  return -1;
739  }
740  else if (a == b)
741  {
742  return 0;
743  }
744  else
745  {
746  return 1;
747  }
748 }
749 
750 static void RemoveRemotelyInjectedVars(const EvalContext *ctx, const Bundle *bundle)
751 {
752  const Seq *remote_var_promises = EvalContextGetRemoteVarPromises(ctx, bundle->name);
753  if ((remote_var_promises == NULL) || SeqLength(remote_var_promises) == 0)
754  {
755  /* nothing to do here */
756  return;
757  }
758 
759  size_t promises_length = SeqLength(remote_var_promises);
760  Seq *remove_vars = SeqNew(promises_length, NULL);
761 
762  /* remove variables that have been attempted to be inserted into this
763  * bundle */
764  /* TODO: this is expensive and should be removed! */
765  for (size_t i = 0; i < promises_length; i++)
766  {
767  const Promise *pp = (Promise *) SeqAt(remote_var_promises, i);
768 
770  const Variable *var = VariableTableIteratorNext(iter);
771  while (var != NULL)
772  {
773  /* variables are stored together with their original promises (org_pp) */
774  if (var->promise && var->promise->org_pp == pp)
775  {
776  Log(LOG_LEVEL_ERR, "Ignoring remotely-injected variable '%s'",
777  var->ref->lval);
778  /* avoid modifications of the variable table being iterated
779  * over and avoid trying to remove the same variable twice */
780  SeqAppendOnce(remove_vars, (void *) var, PointerCmp);
781  }
782  var = VariableTableIteratorNext(iter);
783  }
785  }
786 
787  /* iteration over the variable table done, time to remove the variables */
788  size_t remove_vars_length = SeqLength(remove_vars);
789  for (size_t i = 0; i < remove_vars_length; i++)
790  {
791  Variable *var = (Variable *) SeqAt(remove_vars, i);
792  if (var->ref != NULL)
793  {
794  EvalContextVariableRemove(ctx, var->ref);
795  }
796  }
797  SeqDestroy(remove_vars);
798 }
799 
800 void BundleResolve(EvalContext *ctx, const Bundle *bundle)
801 {
803  "Resolving classes and variables in 'bundle %s %s'",
804  bundle->type, bundle->name);
805 
806  /* first check if some variables were injected remotely into this bundle and
807  * remove them (CFE-1915) */
808  RemoveRemotelyInjectedVars(ctx, bundle);
809 
810  /* PRE-EVAL: evaluate classes of common bundles. */
811  if (strcmp(bundle->type, "common") == 0)
812  {
813  /* Necessary to parse vars *before* classes for cases like this:
814  * 00_basics/04_bundles/dynamic_bundlesequence/dynamic_inputs_based_on_class_set_using_variable_file_control_extends_inputs.cf.sub
815  * -- see bundle "classify". */
816  BundleResolvePromiseType(ctx, bundle, "vars", VerifyVarPromise);
817 
818  BundleResolvePromiseType(ctx, bundle, "classes", VerifyClassPromise);
819  }
820 
821  /* Necessary to also parse vars *after* classes,
822  * because "inputs" might be affected in cases like:
823  * 00_basics/04_bundles/dynamic_bundlesequence/dynamic_inputs_based_on_list_variable_dependent_on_class.cf */
824  BundleResolvePromiseType(ctx, bundle, "vars", VerifyVarPromise);
825 }
826 
827 /**
828  * Evaluate the relevant control body, and set the
829  * relevant fields in #ctx and #config.
830  */
832  const Body *control_body)
833 {
834  const char *filename = control_body->source_path;
835 
836  assert(CFG_CONTROLBODY[COMMON_CONTROL_MAX].lval == NULL);
837 
838  const ConstraintSyntax *body_syntax = NULL;
839  for (int i = 0; CONTROL_BODIES[i].constraints != NULL; i++)
840  {
841  body_syntax = CONTROL_BODIES[i].constraints;
842 
843  if (strcmp(control_body->type, CONTROL_BODIES[i].body_type) == 0)
844  {
845  break;
846  }
847  }
848  if (body_syntax == NULL)
849  {
850  FatalError(ctx, "Unknown control body: %s", control_body->type);
851  }
852 
853  char *scope;
854  assert(strcmp(control_body->name, "control") == 0);
855  xasprintf(&scope, "control_%s", control_body->type);
856 
857  Log(LOG_LEVEL_DEBUG, "Initiate control variable convergence for scope '%s'", scope);
858 
859  EvalContextStackPushBodyFrame(ctx, NULL, control_body, NULL);
860 
861  for (size_t i = 0; i < SeqLength(control_body->conlist); i++)
862  {
863  const char *lval;
864  Rval evaluated_rval;
865  size_t lineno;
866 
867  /* Use nested scope to constrain cp. */
868  {
869  Constraint *cp = SeqAt(control_body->conlist, i);
870  lval = cp->lval;
871  lineno = cp->offset.line;
872 
873  if (!IsDefinedClass(ctx, cp->classes))
874  {
875  continue;
876  }
877 
878  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_BUNDLESEQUENCE].lval) == 0)
879  {
880  evaluated_rval = ExpandPrivateRval(ctx, NULL, scope,
881  cp->rval.item, cp->rval.type);
882  }
883  else
884  {
885  evaluated_rval = EvaluateFinalRval(ctx, control_body->parent_policy,
886  NULL, scope, cp->rval,
887  true, NULL);
888  }
889 
890  } /* Close scope: assert we only use evaluated_rval, not cp->rval. */
891 
892  VarRef *ref = VarRefParseFromScope(lval, scope);
893  EvalContextVariableRemove(ctx, ref);
894 
895  DataType rval_proper_datatype =
896  ConstraintSyntaxGetDataType(body_syntax, lval);
897  if (evaluated_rval.type != DataTypeToRvalType(rval_proper_datatype))
898  {
900  "Attribute '%s' in %s:%zu is of wrong type, skipping",
901  lval, filename, lineno);
902  VarRefDestroy(ref);
903  RvalDestroy(evaluated_rval);
904  continue;
905  }
906 
907  bool success = EvalContextVariablePut(
908  ctx, ref, evaluated_rval.item, rval_proper_datatype,
909  "source=promise");
910  if (!success)
911  {
913  "Attribute '%s' in %s:%zu can't be added, skipping",
914  lval, filename, lineno);
915  VarRefDestroy(ref);
916  RvalDestroy(evaluated_rval);
917  continue;
918  }
919 
920  VarRefDestroy(ref);
921 
922  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_OUTPUT_PREFIX].lval) == 0)
923  {
924  strlcpy(VPREFIX, RvalScalarValue(evaluated_rval),
925  sizeof(VPREFIX));
926  }
927 
928  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_DOMAIN].lval) == 0)
929  {
930  strlcpy(VDOMAIN, RvalScalarValue(evaluated_rval),
931  sizeof(VDOMAIN));
932  Log(LOG_LEVEL_VERBOSE, "SET domain = %s", VDOMAIN);
933 
936  snprintf(VFQNAME, CF_MAXVARSIZE, "%s.%s", VUQNAME, VDOMAIN);
939  "inventory,source=agent,attribute_name=Host name");
942  "source=agent");
943  EvalContextClassPutHard(ctx, VDOMAIN, "source=agent");
944  }
945 
946  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_INPUTS].lval) == 0)
947  {
948  Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_inputs %s",
949  RvalScalarValue(evaluated_rval));
951  RvalScalarValue(evaluated_rval));
952  }
953 
954  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_BUNDLES].lval) == 0)
955  {
956  Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_bundles %s",
957  RvalScalarValue(evaluated_rval));
959  RvalScalarValue(evaluated_rval));
960  }
961 
962  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_CACHE_SYSTEM_FUNCTIONS].lval) == 0)
963  {
964  Log(LOG_LEVEL_VERBOSE, "SET cache_system_functions %s",
965  RvalScalarValue(evaluated_rval));
966  bool cache_system_functions = BooleanFromString(
967  RvalScalarValue(evaluated_rval));
969  cache_system_functions);
970  }
971 
972  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PROTOCOL_VERSION].lval) == 0)
973  {
975  RvalScalarValue(evaluated_rval));
976  Log(LOG_LEVEL_VERBOSE, "SET common protocol_version: %s",
978  }
979 
980  /* Those are package_inventory and package_module common control body options */
981  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PACKAGE_INVENTORY].lval) == 0)
982  {
983  AddDefaultInventoryToContext(ctx, RvalRlistValue(evaluated_rval));
984  Log(LOG_LEVEL_VERBOSE, "SET common package_inventory list");
985  }
986  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_PACKAGE_MODULE].lval) == 0)
987  {
989  Log(LOG_LEVEL_VERBOSE, "SET common package_module: %s",
990  RvalScalarValue(evaluated_rval));
991  }
992 
993  if (strcmp(lval, CFG_CONTROLBODY[COMMON_CONTROL_GOALPATTERNS].lval) == 0)
994  {
995  /* Ignored */
996  }
997 
998  RvalDestroy(evaluated_rval);
999  }
1000 
1002  free(scope);
1003 }
1004 
1005 static void ResolvePackageManagerBody(EvalContext *ctx, const Body *pm_body)
1006 {
1007  PackageModuleBody *new_manager = xcalloc(1, sizeof(PackageModuleBody));
1008  new_manager->name = SafeStringDuplicate(pm_body->name);
1009 
1010  for (size_t i = 0; i < SeqLength(pm_body->conlist); i++)
1011  {
1012  Constraint *cp = SeqAt(pm_body->conlist, i);
1013 
1014  Rval returnval = {0};
1015 
1016  if (IsDefinedClass(ctx, cp->classes))
1017  {
1018  returnval = ExpandPrivateRval(ctx, NULL, "body",
1019  cp->rval.item, cp->rval.type);
1020  }
1021 
1022  if (returnval.item == NULL || returnval.type == RVAL_TYPE_NOPROMISEE)
1023  {
1024  Log(LOG_LEVEL_VERBOSE, "have invalid constraint while resolving"
1025  "package promise body: %s", cp->lval);
1026 
1027  RvalDestroy(returnval);
1028  continue;
1029  }
1030 
1031  if (strcmp(cp->lval, "query_installed_ifelapsed") == 0)
1032  {
1033  new_manager->installed_ifelapsed =
1034  (int)IntFromString(RvalScalarValue(returnval));
1035  }
1036  else if (strcmp(cp->lval, "query_updates_ifelapsed") == 0)
1037  {
1038  new_manager->updates_ifelapsed =
1039  (int)IntFromString(RvalScalarValue(returnval));
1040  }
1041  else if (strcmp(cp->lval, "default_options") == 0)
1042  {
1043  new_manager->options = RlistCopy(RvalRlistValue(returnval));
1044  }
1045  else if (strcmp(cp->lval, "interpreter") == 0)
1046  {
1047  assert(new_manager->interpreter == NULL);
1048  new_manager->interpreter = SafeStringDuplicate(RvalScalarValue(returnval));
1049  }
1050  else if (strcmp(cp->lval, "module_path") == 0)
1051  {
1052  assert(new_manager->module_path == NULL);
1053  new_manager->module_path = SafeStringDuplicate(RvalScalarValue(returnval));
1054  }
1055  else
1056  {
1057  /* This should be handled by the parser. */
1058  assert(0);
1059  }
1060  RvalDestroy(returnval);
1061  }
1062  AddPackageModuleToContext(ctx, new_manager);
1063 }
1064 
1065 void PolicyResolve(EvalContext *ctx, const Policy *policy,
1066  GenericAgentConfig *config)
1067 {
1068  /* PRE-EVAL: common bundles: classes,vars. */
1069  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
1070  {
1071  Bundle *bundle = SeqAt(policy->bundles, i);
1072  if (strcmp("common", bundle->type) == 0)
1073  {
1074  EvalContextStackPushBundleFrame(ctx, bundle, NULL, false);
1075  BundleResolve(ctx, bundle); /* PRE-EVAL classes,vars */
1077  }
1078  }
1079 
1080 /*
1081  * HACK: yet another pre-eval pass here, WHY? TODO remove, but test fails:
1082  * 00_basics/03_bodies/dynamic_inputs_findfiles.cf
1083  */
1084 #if 1
1085 
1086  /* PRE-EVAL: non-common bundles: only vars. */
1087  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
1088  {
1089  Bundle *bundle = SeqAt(policy->bundles, i);
1090  if (strcmp("common", bundle->type) != 0)
1091  {
1092  EvalContextStackPushBundleFrame(ctx, bundle, NULL, false);
1093  BundleResolve(ctx, bundle); /* PRE-EVAL vars */
1095  }
1096  }
1097 
1098 #endif
1099 
1100  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
1101  {
1102  Body *bdp = SeqAt(policy->bodies, i);
1103 
1104  if (strcmp(bdp->name, "control") == 0)
1105  {
1106  ResolveControlBody(ctx, config, bdp);
1107  }
1108  /* Collect all package managers data from policy as we don't know yet
1109  * which ones we will use. */
1110  else if (strcmp(bdp->type, "package_module") == 0)
1111  {
1112  ResolvePackageManagerBody(ctx, bdp);
1113  }
1114  }
1115 }
1116 
1117 bool IsExpandable(const char *str)
1118 {
1119  char left = 'x', right = 'x';
1120  int dollar = false;
1121  int bracks = 0, vars = 0;
1122 
1123  for (const char *sp = str; *sp != '\0'; sp++) /* check for varitems */
1124  {
1125  switch (*sp)
1126  {
1127  case '$':
1128  if (*(sp + 1) == '{' || *(sp + 1) == '(')
1129  {
1130  dollar = true;
1131  }
1132  break;
1133  case '(':
1134  case '{':
1135  if (dollar)
1136  {
1137  left = *sp;
1138  bracks++;
1139  }
1140  break;
1141  case ')':
1142  case '}':
1143  if (dollar)
1144  {
1145  bracks--;
1146  right = *sp;
1147  }
1148  break;
1149  }
1150 
1151  if (left == '(' && right == ')' && dollar && (bracks == 0))
1152  {
1153  vars++;
1154  dollar = false;
1155  }
1156 
1157  if (left == '{' && right == '}' && dollar && (bracks == 0))
1158  {
1159  vars++;
1160  dollar = false;
1161  }
1162  }
1163 
1164  if (bracks != 0)
1165  {
1166  Log(LOG_LEVEL_DEBUG, "If this is an expandable variable string then it contained syntax errors");
1167  return false;
1168  }
1169 
1170  if (vars > 0)
1171  {
1173  "Expanding variable '%s': found %d variables", str, vars);
1174  }
1175  return (vars > 0);
1176 }
1177 
1178 /*********************************************************************/
1179 
1180 static inline char opposite(char c)
1181 {
1182  switch (c)
1183  {
1184  case '(': return ')';
1185  case '{': return '}';
1186  default : ProgrammingError("Was expecting '(' or '{' but got: '%c'", c);
1187  }
1188  return 0;
1189 }
1190 
1191 /**
1192  * Check if #str contains one and only one variable expansion of #vtype kind
1193  * (it's usually either '$' or '@'). It can contain nested expansions which
1194  * are not checked properly. Examples:
1195  * true: "$(whatever)", "${whatever}", "$(blah$(blue))"
1196  * false: "$(blah)blue", "blah$(blue)", "$(blah)$(blue)", "$(blah}"
1197  */
1198 bool IsNakedVar(const char *str, char vtype)
1199 {
1200  size_t len = strlen(str);
1201  char last = len > 0 ? str[len-1] : '\0';
1202 
1203  if (len < 3
1204  || str[0] != vtype
1205  || (str[1] != '(' && str[1] != '{')
1206  || last != opposite(str[1]))
1207  {
1208  return false;
1209  }
1210 
1211  /* TODO check if nesting happens correctly? Is it needed? */
1212  size_t count = 0;
1213  for (const char *sp = str; *sp != '\0'; sp++)
1214  {
1215  switch (*sp)
1216  {
1217  case '(':
1218  case '{':
1219  count++;
1220  break;
1221  case ')':
1222  case '}':
1223  count--;
1224 
1225  /* Make sure the end of the variable is the last character. */
1226  if (count == 0 && sp[1] != '\0')
1227  {
1228  return false;
1229  }
1230 
1231  break;
1232  }
1233  }
1234 
1235  if (count != 0)
1236  {
1237  return false;
1238  }
1239 
1240  return true;
1241 }
1242 
1243 /*********************************************************************/
1244 
1245 /**
1246  * Copy @(listname) -> listname.
1247  *
1248  * This function performs no validations, it is necessary to call the
1249  * validation functions before calling this function.
1250  *
1251  * @NOTE make sure sizeof(dst) >= sizeof(s)
1252  */
1253 void GetNaked(char *dst, const char *s)
1254 {
1255  size_t s_len = strlen(s);
1256 
1257  if (s_len < 4 || s_len + 3 >= CF_MAXVARSIZE)
1258  {
1260  "@(variable) expected, but got malformed: %s", s);
1261  strlcpy(dst, s, CF_MAXVARSIZE);
1262  return;
1263  }
1264 
1265  memcpy(dst, &s[2], s_len - 3);
1266  dst[s_len - 3] = '\0';
1267 }
1268 
1269 /*********************************************************************/
1270 
1271 /**
1272  * Checks if a variable is an @-list and returns true or false.
1273  */
1274 bool IsVarList(const char *var)
1275 {
1276  if ('@' != var[0])
1277  {
1278  return false;
1279  }
1280  /*
1281  * Minimum size for a list is 4:
1282  * '@' + '(' + name + ')'
1283  */
1284  if (strlen(var) < 4)
1285  {
1286  return false;
1287  }
1288  return true;
1289 }
1290 
1292  ARG_UNUSED void *param)
1293 {
1294  assert(param == NULL);
1295 
1297 
1298  return PROMISE_RESULT_NOOP;
1299 }
PromiseResult PromiseResultUpdate(PromiseResult prior, PromiseResult evidence)
Definition: actuator.c:28
PromiseResult PromiseActuator(EvalContext *ctx, const Promise *pp, void *param)
Definition: actuator.h:30
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
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
unsigned int BufferSize(const Buffer *buffer)
Returns the size of the buffer.
Definition: buffer.c:464
void BufferClear(Buffer *buffer)
Clears the buffer.
Definition: buffer.c:457
void BufferAppendF(Buffer *buffer, const char *format,...)
Definition: buffer.c:318
void BufferAppend(Buffer *buffer, const char *bytes, unsigned int length)
Definition: buffer.c:269
char * BufferClose(Buffer *buffer)
Destroys a buffer structure returning the its contents.
Definition: buffer.c:81
Buffer * BufferCopy(const Buffer *source)
Creates a shallow copy of the source buffer.
Definition: buffer.c:90
void BufferAppendString(Buffer *buffer, const char *str)
Definition: buffer.c:246
#define ARG_UNUSED
Definition: cf-net.c:47
#define CF_NS
Definition: cf3.defs.h:109
const BodySyntax CONTROL_BODIES[]
Definition: mod_common.c:458
const ConstraintSyntax CFG_CONTROLBODY[]
Definition: mod_common.c:245
@ COMMON_CONTROL_OUTPUT_PREFIX
Definition: cf3.defs.h:423
@ COMMON_CONTROL_DOMAIN
Definition: cf3.defs.h:424
@ COMMON_CONTROL_PACKAGE_INVENTORY
Definition: cf3.defs.h:436
@ COMMON_CONTROL_IGNORE_MISSING_INPUTS
Definition: cf3.defs.h:419
@ COMMON_CONTROL_CACHE_SYSTEM_FUNCTIONS
Definition: cf3.defs.h:432
@ COMMON_CONTROL_MAX
Definition: cf3.defs.h:438
@ COMMON_CONTROL_PROTOCOL_VERSION
Definition: cf3.defs.h:433
@ COMMON_CONTROL_BUNDLESEQUENCE
Definition: cf3.defs.h:416
@ COMMON_CONTROL_GOALPATTERNS
Definition: cf3.defs.h:417
@ COMMON_CONTROL_IGNORE_MISSING_BUNDLES
Definition: cf3.defs.h:418
@ COMMON_CONTROL_PACKAGE_MODULE
Definition: cf3.defs.h:437
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_SKIPPED
Definition: cf3.defs.h:123
DataType
Definition: cf3.defs.h:368
@ CF_DATA_TYPE_NONE
Definition: cf3.defs.h:385
@ CF_DATA_TYPE_STRING
Definition: cf3.defs.h:369
char VUQNAME[]
Definition: cf3globals.c:59
void free(void *)
char VDOMAIN[]
Definition: cf3globals.c:60
char VFQNAME[]
Definition: cf3globals.c:58
long IntFromString(const char *s)
Definition: conversion.c:390
bool BooleanFromString(const char *s)
Definition: conversion.c:354
DataType ConstraintSyntaxGetDataType(const ConstraintSyntax *body_syntax, const char *lval)
Definition: conversion.c:337
#define CF_MAXVARSIZE
Definition: definitions.h:36
void AddPackageModuleToContext(const EvalContext *ctx, PackageModuleBody *pm)
Definition: eval_context.c:226
bool EvalContextVariableRemoveSpecial(const EvalContext *ctx, SpecialScope scope, const char *lval)
void AddDefaultInventoryToContext(const EvalContext *ctx, Rlist *inventory)
Definition: eval_context.c:210
void AddDefaultPackageModuleToContext(const EvalContext *ctx, char *name)
Definition: eval_context.c:200
void EvalContextStackPushPromiseFrame(EvalContext *ctx, const Promise *owner)
void EvalContextStackPushPromiseTypeFrame(EvalContext *ctx, const PromiseType *owner)
void NotifyDependantPromises(EvalContext *ctx, const Promise *pp, PromiseResult result)
Promise * EvalContextStackPushPromiseIterationFrame(EvalContext *ctx, const PromiseIterator *iter_ctx)
void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, const Rlist *args, bool inherits_previous)
bool EvalContextClassPutHard(EvalContext *ctx, const char *name, const char *tags)
const void * EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, DataType *type_out)
bool EvalContextVariableRemove(const EvalContext *ctx, const VarRef *ref)
const Promise * EvalContextStackCurrentPromise(const EvalContext *ctx)
void EvalContextStackPushBodyFrame(EvalContext *ctx, const Promise *caller, const Body *body, const Rlist *args)
void EvalContextStackPopFrame(EvalContext *ctx)
void EvalContextSetEvalOption(EvalContext *ctx, EvalContextOption option, bool value)
bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const char *lval, const void *value, DataType type, const char *tags)
const Seq * EvalContextGetRemoteVarPromises(const EvalContext *ctx, const char *bundle_name)
bool EvalContextVariablePut(EvalContext *ctx, const VarRef *ref, const void *value, DataType type, const char *tags)
VariableTableIterator * EvalContextVariableTableIteratorNew(const EvalContext *ctx, const char *ns, const char *scope, const char *lval)
static bool IsDefinedClass(const EvalContext *ctx, const char *context)
Definition: eval_context.h:213
@ EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS
Definition: eval_context.h:109
bool IsVarList(const char *var)
Definition: expand.c:1274
static Rval ExpandListEntry(EvalContext *ctx, const char *ns, const char *scope, int expandnaked, Rval entry)
Definition: expand.c:406
Rlist * ExpandList(EvalContext *ctx, const char *ns, const char *scope, const Rlist *list, int expandnaked)
Definition: expand.c:466
static PromiseResult ExpandPromiseAndDo(EvalContext *ctx, PromiseIterator *iterctx, PromiseActuator *act_on_promise, void *param, bool actuate_ifelse)
Definition: expand.c:190
void PolicyResolve(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
Definition: expand.c:1065
static char opposite(char c)
Definition: expand.c:1180
void GetNaked(char *dst, const char *s)
Definition: expand.c:1253
static bool VariableDataOrListReference(const char *str)
Definition: expand.c:357
static void ResolvePackageManagerBody(EvalContext *ctx, const Body *pm_body)
Definition: expand.c:1005
void BundleResolve(EvalContext *ctx, const Bundle *bundle)
Definition: expand.c:800
static void PutHandleVariable(EvalContext *ctx, const Promise *pp)
Definition: expand.c:109
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
static void RemoveRemotelyInjectedVars(const EvalContext *ctx, const Bundle *bundle)
Definition: expand.c:750
static void ResolveControlBody(EvalContext *ctx, GenericAgentConfig *config, const Body *control_body)
Definition: expand.c:831
PromiseResult CommonEvalPromise(EvalContext *ctx, const Promise *pp, void *param)
Definition: expand.c:1291
static int PointerCmp(const void *a, const void *b, void *user_data)
Definition: expand.c:734
static void MapIteratorsFromRval(EvalContext *ctx, PromiseIterator *iterctx, Rval rval)
Definition: expand.c:136
Rval ExpandBundleReference(EvalContext *ctx, const char *ns, const char *scope, Rval rval)
Definition: expand.c:484
PromiseResult ExpandPromise(EvalContext *ctx, const Promise *pp, PromiseActuator *act_on_promise, void *param)
Definition: expand.c:257
bool IsExpandable(const char *str)
Definition: expand.c:1117
void BundleResolvePromiseType(EvalContext *ctx, const Bundle *bundle, const char *type, PromiseActuator *actuator)
Definition: expand.c:715
Rval ExpandPrivateRval(EvalContext *ctx, const char *ns, const char *scope, const void *rval_item, RvalType rval_type)
Definition: expand.c:313
FnCall * ExpandFnCall(EvalContext *ctx, const char *ns, const char *scope, const FnCall *f)
Definition: fncall.c:202
void FnCallDestroy(FnCall *fp)
Definition: fncall.c:185
FnCallResult FnCallEvaluate(EvalContext *ctx, const Policy *policy, FnCall *fp, const Promise *caller)
Definition: fncall.c:309
bool FnCallIsBuiltIn(Rval rval)
Definition: fncall.c:138
#define NULL
Definition: getopt1.c:56
void PromiseIteratorPrepare(PromiseIterator *iterctx, const EvalContext *evalctx, char *s)
Fills up the wheels of the iterator according to the variables found in #s. Also mangles all namespac...
Definition: iteration.c:632
bool PromiseIteratorNext(PromiseIterator *iterctx, EvalContext *evalctx)
Definition: iteration.c:991
PromiseIterator * PromiseIteratorNew(const Promise *pp)
Definition: iteration.c:201
void PromiseIteratorDestroy(PromiseIterator *iterctx)
Definition: iteration.c:211
JsonElementType JsonGetElementType(const JsonElement *const element)
Definition: json.c:667
const char * JsonPrimitiveGetAsString(const JsonElement *const primitive)
Definition: json.c:701
@ JSON_ELEMENT_TYPE_PRIMITIVE
Definition: json.h:53
@ LogDebug
Definition: log.h:34
char VPREFIX[1024]
Definition: logging.c:33
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_MOD_EXPAND
Definition: logging.h:59
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
#define ProgrammingError(...)
Definition: misc_lib.h:33
const char * PromiseGetHandle(const Promise *pp)
Return handle of the promise.
Definition: policy.c:2713
void PromiseRecheckAllConstraints(const EvalContext *ctx, const Promise *pp)
Definition: policy.c:3080
void PromiseDestroy(Promise *pp)
Definition: policy.c:1471
const char * PromiseID(const Promise *pp)
Definition: promises.c:814
Promise * DeRefCopyPromise(EvalContext *ctx, const Promise *pp)
Definition: promises.c:205
#define ProtocolVersionParse
static const char * ProtocolVersionString(const ProtocolVersion p)
FnCall * RlistFnCallValue(const Rlist *rlist)
Definition: rlist.c:105
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
Rlist * RlistAppend(Rlist **start, const void *item, RvalType type)
Definition: rlist.c:560
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
Rlist * RlistCopy(const Rlist *rp)
Definition: rlist.c:494
Rval RvalCopy(Rval rval)
Definition: rlist.c:474
@ SPECIAL_SCOPE_THIS
Definition: scope.h:39
@ SPECIAL_SCOPE_SYS
Definition: scope.h:38
void SeqAppendOnce(Seq *seq, void *item, SeqItemComparator Compare)
Append a new item to the Sequence if it's not already present in the Sequence.
Definition: sequence.c:113
size_t SeqLength(const Seq *seq)
Length of the sequence.
Definition: sequence.c:354
Seq * SeqNew(size_t initialCapacity, void(ItemDestroy)(void *item))
Definition: sequence.c:31
void SeqDestroy(Seq *seq)
Destroy an existing Sequence.
Definition: sequence.c:60
static void * SeqAt(const Seq *seq, int i)
Definition: sequence.h:57
char * SafeStringDuplicate(const char *str)
Definition: string_lib.c:172
void CanonifyNameInPlace(char *s)
Definition: string_lib.c:1574
#define SAFENULL(str)
Definition: string_lib.h:52
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
const char * body_type
Definition: cf3.defs.h:669
const ConstraintSyntax * constraints
Definition: cf3.defs.h:670
Definition: policy.h:85
char * type
Definition: policy.h:88
char * source_path
Definition: policy.h:95
Seq * conlist
Definition: policy.h:93
Policy * parent_policy
Definition: policy.h:86
char * name
Definition: policy.h:89
Definition: buffer.h:50
Definition: policy.h:70
char * name
Definition: policy.h:74
char * type
Definition: policy.h:73
Seq * promise_types
Definition: policy.h:78
Rval rval
Definition: policy.h:133
SourceOffset offset
Definition: policy.h:138
char * classes
Definition: policy.h:135
char * lval
Definition: policy.h:132
Rval rval
Definition: fncall.h:47
Definition: fncall.h:31
char * name
Definition: fncall.h:32
ProtocolVersion protocol_version
Definition: generic_agent.h:66
char * module_path
Definition: cf3.defs.h:1366
char * interpreter
Definition: cf3.defs.h:1365
Definition: policy.h:53
Seq * bundles
Definition: policy.h:56
Seq * bodies
Definition: policy.h:57
Seq * promises
Definition: policy.h:104
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
Rval promisee
Definition: policy.h:116
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
Sequence data-structure.
Definition: sequence.h:50
size_t line
Definition: policy.h:65
char * lval
VarRef * ref
Definition: variable.h:33
const Promise * promise
Definition: variable.h:37
VarRef * VarRefParseFromScope(const char *var_ref_string, const char *scope)
void VarRefDestroy(VarRef *ref)
VarRef * VarRefParseFromNamespaceAndScope(const char *qualified_name, const char *_ns, const char *_scope, char ns_separator, char scope_separator)
Variable * VariableTableIteratorNext(VariableTableIterator *iter)
Definition: variable.c:283
void VariableTableIteratorDestroy(VariableTableIterator *iter)
Definition: variable.c:336
bool ExtractScalarReference(Buffer *out, const char *str, size_t len, bool extract_inner)
Definition: vars.c:379
size_t ExtractScalarPrefix(Buffer *out, const char *str, size_t len)
Definition: vars.c:280
bool IsCf3VarString(const char *str)
Definition: vars.c:123
PromiseResult VerifyClassPromise(EvalContext *ctx, const Promise *pp, void *param)
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, void *param)
Definition: verify_vars.c:109