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)  

policy.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 <policy.h>
26 
27 #include <syntax.h>
28 #include <string_lib.h>
29 #include <conversion.h>
30 #include <mutex.h>
31 #include <misc_lib.h>
32 #include <mod_files.h>
33 #include <vars.h>
34 #include <fncall.h>
35 #include <rlist.h>
36 #include <set.h>
37 #include <eval_context.h>
38 #include <promises.h>
39 #include <item_lib.h>
40 #include <hash.h>
41 #include <files_names.h>
42 #include <audit.h>
43 #include <logging.h>
44 #include <expand.h>
45 
46 static const char *const POLICY_ERROR_BUNDLE_NAME_RESERVED =
47  "Use of a reserved container name as a bundle name \"%s\"";
48 static const char *const POLICY_ERROR_BUNDLE_REDEFINITION =
49  "Duplicate definition of bundle %s with type %s";
50 static const char *const POLICY_ERROR_BUNDLE_UNDEFINED =
51  "Undefined bundle %s with type %s";
52 static const char *const POLICY_ERROR_BODY_REDEFINITION =
53  "Duplicate definition of body %s with type %s";
54 static const char *const POLICY_ERROR_BODY_UNDEFINED =
55  "Undefined body %s with type %s";
56 static const char *const POLICY_ERROR_BODY_CONTROL_ARGS =
57  "Control bodies cannot take arguments, body %s control";
58 static const char *const POLICY_ERROR_PROMISE_UNCOMMENTED =
59  "Promise is missing a comment attribute, and comments are required "
60  "by policy";
61 static const char *const POLICY_ERROR_PROMISE_DUPLICATE_HANDLE =
62  "Duplicate promise handle %s found";
63 static const char *const POLICY_ERROR_LVAL_INVALID =
64  "Promise type %s has unknown attribute %s";
65 
66 static const char *const POLICY_ERROR_CONSTRAINT_TYPE_MISMATCH =
67  "Type mismatch in constraint: %s";
68 
69 static const char *const POLICY_ERROR_EMPTY_VARREF =
70  "Empty variable reference";
71 
72 //************************************************************************
73 
74 static void BundleDestroy(Bundle *bundle);
75 static void BodyDestroy(Body *body);
77 static bool PromiseCheck(const Promise *pp, Seq *errors);
78 
79 /*************************************************************************/
80 
81 /**
82  * @brief Return a default bundle name for this method/service
83  */
84 Rval DefaultBundleConstraint(const Promise *pp, char *promisetype)
85 {
86  static char name[CF_BUFSIZE];
87  snprintf(name, CF_BUFSIZE, "%s_%s", promisetype, CanonifyName(pp->promiser));
88  return (Rval) { name, RVAL_TYPE_SCALAR };
89 }
90 
91 /*************************************************************************/
92 
93 const char *NamespaceDefault(void)
94 {
95  return "default";
96 }
97 
98 /*************************************************************************/
99 
101 {
102  Policy *policy = xcalloc(1, sizeof(Policy));
103 
104  policy->release_id = NULL;
105  policy->bundles = SeqNew(100, BundleDestroy);
106  policy->bodies = SeqNew(100, BodyDestroy);
107  policy->policy_files_hashes = NULL;
108 
109  return policy;
110 }
111 
112 /*************************************************************************/
113 
114 int PolicyCompare(const void *a, const void *b)
115 {
116  return a - b;
117 }
118 
119 /*************************************************************************/
120 
121 void PolicyDestroy(Policy *policy)
122 {
123  if (policy)
124  {
125  SeqDestroy(policy->bundles);
126  SeqDestroy(policy->bodies);
127  free(policy->release_id);
128  if (policy->policy_files_hashes != NULL)
129  {
131  }
132 
133  free(policy);
134  }
135 }
136 
137 /*************************************************************************/
138 
139 static unsigned ConstraintHash(const Constraint *cp, unsigned seed)
140 {
141  unsigned hash = seed;
142 
143  hash = StringHash(cp->lval, hash);
144  hash = StringHash(cp->classes, hash);
145  hash = RvalHash(cp->rval, hash);
146 
147  return hash;
148 }
149 
150 /*************************************************************************/
151 
152 static unsigned BodyHash(const Body *body, unsigned seed)
153 {
154  unsigned hash = seed;
155  for (size_t i = 0; i < SeqLength(body->conlist); i++)
156  {
157  const Constraint *cp = SeqAt(body->conlist, i);
158  hash = ConstraintHash(cp, hash);
159  }
160 
161  return hash;
162 }
163 /*************************************************************************/
164 
165 static unsigned PromiseHash(const Promise *pp, unsigned seed)
166 {
167  unsigned hash = seed;
168 
169  hash = StringHash(pp->promiser, seed);
170  hash = RvalHash(pp->promisee, hash);
171 
172  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
173  {
174  const Constraint *cp = SeqAt(pp->conlist, i);
175  hash = ConstraintHash(cp, hash);
176  }
177 
178  return hash;
179 }
180 
181 /*************************************************************************/
182 
183 static unsigned PromiseTypeHash(const PromiseType *pt, unsigned seed)
184 {
185  unsigned hash = seed;
186 
187  hash = StringHash(pt->name, hash);
188  for (size_t i = 0; i < SeqLength(pt->promises); i++)
189  {
190  const Promise *pp = SeqAt(pt->promises, i);
191  hash = PromiseHash(pp, hash);
192  }
193 
194  return hash;
195 }
196 
197 /*************************************************************************/
198 
199 static unsigned BundleHash(const Bundle *bundle, unsigned seed)
200 {
201  unsigned hash = seed;
202 
203  hash = StringHash(bundle->type, hash);
204  hash = StringHash(bundle->ns, hash);
205  hash = StringHash(bundle->name, hash);
206  hash = RlistHash(bundle->args, hash);
207 
208  for (size_t i = 0; i < SeqLength(bundle->promise_types); i++)
209  {
210  const PromiseType *pt = SeqAt(bundle->promise_types, i);
211  hash = PromiseTypeHash(pt, hash);
212  }
213 
214  return hash;
215 }
216 
217 /*************************************************************************/
218 
219 unsigned PolicyHash(const Policy *policy)
220 {
221  unsigned hash = 0;
222 
223  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
224  {
225  const Body *body = SeqAt(policy->bodies, i);
226  hash = BodyHash(body, hash);
227  }
228 
229  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
230  {
231  const Bundle *bundle = SeqAt(policy->bundles, i);
232  hash = BundleHash(bundle, hash);
233  }
234 
235  return hash;
236 }
237 
238 /*************************************************************************/
239 
241 {
242  StringSet *files = StringSetNew();
243 
244  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
245  {
246  const Bundle *bp = SeqAt(policy->bundles, i);
247  if (bp->source_path)
248  {
249  StringSetAdd(files, xstrdup(bp->source_path));
250  }
251  }
252 
253  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
254  {
255  const Bundle *bp = SeqAt(policy->bodies, i);
256  if (bp->source_path)
257  {
258  StringSetAdd(files, xstrdup(bp->source_path));
259  }
260  }
261 
262  return files;
263 }
264 
265 /*************************************************************************/
266 
267 /**
268  * Get hash digest of the given policy file.
269  *
270  * @param policy Policy that is supposed to contain (have loaded) the file
271  * @param policy_file_path Absolute path of the policy file to get the digest for
272  * @return Hash digest of the given policy file or %NULL if unknown
273  * @note The returned hash digest is owned by the policy, **do not free it**.
274  */
275 const char *PolicyGetPolicyFileHash(const Policy *policy, const char *policy_file_path)
276 {
277  return StringMapGet(policy->policy_files_hashes, policy_file_path);
278 }
279 
280 /*************************************************************************/
281 
282 static const char *StripNamespace(const char *full_symbol)
283 {
284  char *sep = strchr(full_symbol, CF_NS);
285 
286  if (sep == NULL)
287  {
288  return full_symbol;
289  }
290  else
291  {
292  return sep + 1;
293  }
294 }
295 
296 /*************************************************************************/
297 
298 /**
299  * @brief Query a policy for a body
300  * @param policy The policy to query
301  * @param ns Namespace filter (optionally NULL)
302  * @param type Body type filter
303  * @param name Body name filter
304  * @return Body child object if found, otherwise NULL
305  */
306 Body *PolicyGetBody(const Policy *policy, const char *ns, const char *type, const char *name)
307 {
308  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
309  {
310  Body *bp = SeqAt(policy->bodies, i);
311  const char *body_symbol = StripNamespace(bp->name);
312 
313  if (strcmp(bp->type, type) == 0 &&
314  strcmp(body_symbol, name) == 0)
315  {
316  // allow namespace to be optionally matched
317  if (ns && strcmp(bp->ns, ns) != 0)
318  {
319  continue;
320  }
321 
322  return bp;
323  }
324  }
325 
326  return NULL;
327 }
328 
329 /*************************************************************************/
330 
331 /**
332  * @brief Query a policy for a bundle
333  * @param policy The policy to query
334  * @param ns Namespace filter (optionally NULL)
335  * @param type Bundle type filter
336  * @param name Bundle name filter
337  * @return Bundle child object if found, otherwise NULL
338  */
339 Bundle *PolicyGetBundle(const Policy *policy, const char *ns, const char *type, const char *name)
340 {
341  const char *bundle_symbol = StripNamespace(name);
342 
343  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
344  {
345  Bundle *bp = SeqAt(policy->bundles, i);
346 
347  if ((type == NULL || strcmp(bp->type, type) == 0)
348  &&
349  ((strcmp(bp->name, bundle_symbol) == 0) ||
350  (strcmp(bp->name, name) == 0)))
351  {
352  // allow namespace to be optionally matched
353  if (ns && strcmp(bp->ns, ns) != 0)
354  {
355  continue;
356  }
357 
358  return bp;
359  }
360  }
361 
362  return NULL;
363 }
364 
365 /*************************************************************************/
366 
367 /**
368  * @brief Check to see if a policy is runnable (contains body common control)
369  * @param policy Policy to check
370  * @return True if policy is runnable
371  */
372 bool PolicyIsRunnable(const Policy *policy)
373 {
374  return PolicyGetBody(policy, NULL, "common", "control") != NULL;
375 }
376 
377 /*************************************************************************/
378 
379 /**
380  * @brief Merge two partial policy objects. The memory for the child objects of the original policies are transferred to the new parent.
381  * @param a
382  * @param b
383  * @return Merged policy
384  */
386 {
387  Policy *result = PolicyNew();
388 
389  SeqAppendSeq(result->bundles, a->bundles);
391  SeqAppendSeq(result->bundles, b->bundles);
393 
394  for (size_t i = 0; i < SeqLength(result->bundles); i++)
395  {
396  Bundle *bp = SeqAt(result->bundles, i);
397  bp->parent_policy = result;
398  }
399 
400  SeqAppendSeq(result->bodies, a->bodies);
402  SeqAppendSeq(result->bodies, b->bodies);
404 
405  for (size_t i = 0; i < SeqLength(result->bodies); i++)
406  {
407  Body *bdp = SeqAt(result->bodies, i);
408  bdp->parent_policy = result;
409  }
410 
411  StringMap *extra_hashes = NULL;
412  if (a->policy_files_hashes != NULL)
413  {
416  extra_hashes = b->policy_files_hashes;
418  }
419  else if (b->policy_files_hashes != NULL)
420  {
423  }
424  else
425  {
426  result->policy_files_hashes = NULL;
427  }
428 
429  if (extra_hashes != NULL)
430  {
431  MapIterator it = MapIteratorInit(extra_hashes->impl);
432  MapKeyValue *item;
433  while ((item = MapIteratorNext(&it)) != NULL)
434  {
435  /* Move data and duplicate just the keys (which are always owned by
436  the map). */
438  xstrdup((char*) item->key), (char*) item->value);
439  }
440  /* Destroy only the map and the keys, data was moved. */
441  StringMapSoftDestroy(extra_hashes);
442  }
443 
444  /* Should result take over a release_id ? */
445  free(a->release_id);
446  free(b->release_id);
447  free(a);
448  free(b);
449 
450  return result;
451 }
452 
453 /*************************************************************************/
454 
455 const char *ConstraintGetNamespace(const Constraint *cp)
456 {
457  switch (cp->type)
458  {
460  return cp->parent.body->ns;
461 
464 
465  default:
466  ProgrammingError("Constraint has parent type: %d", cp->type);
467  }
468 }
469 
470 /*************************************************************************/
471 
472 /**
473  * @brief Convenience function to get the policy object associated with a promise
474  * @param promise
475  * @return Policy object
476  */
477 const Policy *PolicyFromPromise(const Promise *promise)
478 {
479  assert(promise);
480 
481  PromiseType *promise_type = promise->parent_promise_type;
482  assert(promise_type);
483 
484  Bundle *bundle = promise_type->parent_bundle;
485  assert(bundle);
486 
487  return bundle->parent_policy;
488 }
489 
490 char *BundleQualifiedName(const Bundle *bundle)
491 {
492  assert(bundle);
493  if (!bundle)
494  {
495  return NULL;
496  }
497 
498  if (bundle->name)
499  {
500  const char *ns = bundle->ns ? bundle->ns : NamespaceDefault();
501  return StringConcatenate(3, ns, ":", bundle->name); // CF_NS == ':'
502  }
503 
504  return NULL;
505 }
506 
507 static bool RvalTypeCheckDataType(RvalType rval_type, DataType expected_datatype)
508 {
509  if (rval_type == RVAL_TYPE_FNCALL)
510  {
511  return true;
512  }
513 
514  switch (expected_datatype)
515  {
516  case CF_DATA_TYPE_BODY:
517  case CF_DATA_TYPE_BUNDLE:
518  return rval_type == RVAL_TYPE_SCALAR;
519 
522  case CF_DATA_TYPE_INT:
524  case CF_DATA_TYPE_OPTION:
525  case CF_DATA_TYPE_REAL:
527  case CF_DATA_TYPE_STRING:
528  return rval_type == RVAL_TYPE_SCALAR;
529 
535  return (rval_type == RVAL_TYPE_SCALAR) || (rval_type == RVAL_TYPE_LIST);
536 
538  return (rval_type == RVAL_TYPE_CONTAINER);
539 
540  default:
541  ProgrammingError("Unhandled expected datatype in switch: %d", expected_datatype);
542  }
543 }
544 
545 /*************************************************************************/
546 
547 /* Check if a constraint's syntax is correct according to its promise_type and
548  lvalue.
549 */
550 static bool ConstraintCheckSyntax(const Constraint *constraint, Seq *errors)
551 {
552  if (constraint->type != POLICY_ELEMENT_TYPE_PROMISE)
553  {
554  ProgrammingError("Attempted to check the syntax for a constraint"
555  " not belonging to a promise");
556  }
557 
558  const PromiseType *promise_type = constraint->parent.promise->parent_promise_type;
559  const Bundle *bundle = promise_type->parent_bundle;
560 
561  /* Check if lvalue is valid for the bundle's specific promise_type. */
562  const PromiseTypeSyntax *promise_type_syntax = PromiseTypeSyntaxGet(bundle->type, promise_type->name);
563  for (size_t i = 0; promise_type_syntax->constraints[i].lval != NULL; i++)
564  {
565  const ConstraintSyntax *body_syntax = &promise_type_syntax->constraints[i];
566  if (strcmp(body_syntax->lval, constraint->lval) == 0)
567  {
568  if (!RvalTypeCheckDataType(constraint->rval.type, body_syntax->dtype))
569  {
570  SeqAppend(errors,
573  return false;
574  }
575  return true;
576  }
577  }
578  /* FIX: Call a VerifyConstraint() hook for the specific promise_type, defined
579  in verify_TYPE.c, that checks for promise_type-specific constraint syntax. */
580 
581  /* Check if lvalue is valid for all bodies. */
582  for (size_t i = 0; CF_COMMON_BODIES[i].lval != NULL; i++)
583  {
584  if (strcmp(constraint->lval, CF_COMMON_BODIES[i].lval) == 0)
585  {
586  if (!RvalTypeCheckDataType(constraint->rval.type, CF_COMMON_BODIES[i].dtype))
587  {
588  SeqAppend(errors,
591  return false;
592  }
593  return true;
594  }
595  }
596  for (size_t i = 0; CF_COMMON_EDITBODIES[i].lval != NULL; i++)
597  {
598  if (strcmp(constraint->lval, CF_COMMON_EDITBODIES[i].lval) == 0)
599  {
601  {
602  SeqAppend(errors,
605  return false;
606  }
607  return true;
608  }
609  }
610  for (size_t i = 0; CF_COMMON_XMLBODIES[i].lval != NULL; i++)
611  {
612  if (strcmp(constraint->lval, CF_COMMON_XMLBODIES[i].lval) == 0)
613  {
615  {
616  SeqAppend(errors,
619  return false;
620  }
621  return true;
622  }
623  }
624 
625  /* lval is unknown for this promise type */
626  SeqAppend(errors,
629  constraint->parent.promise->parent_promise_type->name,
630  constraint->lval));
631 
632  return false;
633 }
634 
635 /*************************************************************************/
636 
637 static bool PolicyCheckPromiseType(const PromiseType *promise_type, Seq *errors)
638 {
639  assert(promise_type);
640  assert(promise_type->parent_bundle);
641  bool success = true;
642 
643  for (size_t i = 0; i < SeqLength(promise_type->promises); i++)
644  {
645  const Promise *pp = SeqAt(promise_type->promises, i);
646  success &= PromiseCheck(pp, errors);
647  }
648 
649  return success;
650 }
651 
652 /*************************************************************************/
653 
654 static bool PolicyCheckBundle(const Bundle *bundle, Seq *errors)
655 {
656  assert(bundle);
657  bool success = true;
658 
659  // ensure no reserved bundle names are used
660  {
661  static const char *const reserved_names[] =
662  { "sys", "const", "mon", "edit", "match", "mon", "this", NULL };
663  if (IsStrIn(bundle->name, reserved_names))
664  {
667  success = false;
668  }
669  }
670 
671  for (size_t i = 0; i < SeqLength(bundle->promise_types); i++)
672  {
673  const PromiseType *type = SeqAt(bundle->promise_types, i);
674  success &= PolicyCheckPromiseType(type, errors);
675  }
676 
677  return success;
678 }
679 
680 static bool PolicyCheckBody(const Body *body, Seq *errors)
681 {
682  bool success = true;
683 
684  if (strcmp("control", body->name) == 0)
685  {
686  if (RlistLen(body->args) > 0)
687  {
690  body->type));
691  success = false;
692  }
693  }
694 
695  for (size_t i = 0; i < SeqLength(body->conlist); i++)
696  {
697  Constraint *cp = SeqAt(body->conlist, i);
700  {
703  cp->lval));
704  success = false;
705  }
706  }
707 
708  const BodySyntax *body_syntax = BodySyntaxGet(body->type);
709  assert(body_syntax && "Should have been checked at parse time");
710  if (body_syntax->check_body)
711  {
712  success &= body_syntax->check_body(body, errors);
713  }
714 
715  return success;
716 }
717 
718 /*************************************************************************/
719 
720 /* Get the syntax of a constraint according to its promise_type and lvalue.
721  Make sure you've already checked the constraint's validity.
722 */
723 static const ConstraintSyntax *ConstraintGetSyntax(const Constraint *constraint)
724 {
725  if (constraint->type != POLICY_ELEMENT_TYPE_PROMISE)
726  {
727  ProgrammingError("Attempted to get the syntax for a constraint not belonging to a promise");
728  }
729 
730  const Promise *promise = constraint->parent.promise;
731  const PromiseType *promise_type = promise->parent_promise_type;
732  const Bundle *bundle = promise_type->parent_bundle;
733 
734  const PromiseTypeSyntax *promise_type_syntax = PromiseTypeSyntaxGet(bundle->type, promise_type->name);
735 
736  /* Check if lvalue is valid for the bundle's specific promise_type. */
737  for (size_t i = 0; promise_type_syntax->constraints[i].lval != NULL; i++)
738  {
739  const ConstraintSyntax *body_syntax = &promise_type_syntax->constraints[i];
740  if (strcmp(body_syntax->lval, constraint->lval) == 0)
741  {
742  return body_syntax;
743  }
744  }
745 
746  /* Check if lvalue is valid for all bodies. */
747  for (size_t i = 0; CF_COMMON_BODIES[i].lval != NULL; i++)
748  {
749  if (strcmp(constraint->lval, CF_COMMON_BODIES[i].lval) == 0)
750  {
751  return &CF_COMMON_BODIES[i];
752  }
753  }
754  for (size_t i = 0; CF_COMMON_EDITBODIES[i].lval != NULL; i++)
755  {
756  if (strcmp(constraint->lval, CF_COMMON_EDITBODIES[i].lval) == 0)
757  {
758  return &CF_COMMON_EDITBODIES[i];
759  }
760  }
761  for (size_t i = 0; CF_COMMON_XMLBODIES[i].lval != NULL; i++)
762  {
763  if (strcmp(constraint->lval, CF_COMMON_XMLBODIES[i].lval) == 0)
764  {
765  return &CF_COMMON_XMLBODIES[i];
766  }
767  }
768 
769  /* Syntax must have been checked first during PolicyCheckPartial(). */
770  ProgrammingError("ConstraintGetSyntax() was called for constraint with "
771  "invalid lvalue: %s", constraint->lval);
772  return NULL;
773 }
774 
775 /*************************************************************************/
776 
777 /**
778  * @return A reference to the full symbol value of the Rval regardless of type, e.g. "foo:bar""foo:bar"
779  */
780 static const char *RvalFullSymbol(const Rval *rval)
781 {
782  switch (rval->type)
783  {
784  case RVAL_TYPE_SCALAR:
785  return rval->item;
786  break;
787 
788  case RVAL_TYPE_FNCALL:
789  return ((FnCall *)rval->item)->name;
790 
791  default:
792  ProgrammingError("Cannot get full symbol value from Rval of type %c", rval->type);
793  return NULL;
794  }
795 }
796 
797 /**
798  * @return A copy of the namespace component of a qualified name, or NULL. e.g. "foo:bar" -> "foo"
799  */
800 char *QualifiedNameNamespaceComponent(const char *qualified_name)
801 {
802  if (strchr(qualified_name, CF_NS))
803  {
804  char ns[256] = { 0 };
805  sscanf(qualified_name, "%255[^:]", ns);
806 
807  return xstrdup(ns);
808  }
809  else
810  {
811  return NULL;
812  }
813 }
814 
815 /**
816  * @return A copy of the symbol compoent of a qualified name, or NULL. e.g. "foo:bar" -> "bar"
817  */
818 char *QualifiedNameScopeComponent(const char *qualified_name)
819 {
820  char *sep = strchr(qualified_name, CF_NS);
821  if (sep)
822  {
823  return xstrdup(sep + 1);
824  }
825  else
826  {
827  return xstrdup(qualified_name);
828  }
829 }
830 
831 static bool PolicyCheckUndefinedBodies(const Policy *policy, Seq *errors)
832 {
833  bool success = true;
834 
835  for (size_t bpi = 0; bpi < SeqLength(policy->bundles); bpi++)
836  {
837  Bundle *bundle = SeqAt(policy->bundles, bpi);
838 
839  for (size_t sti = 0; sti < SeqLength(bundle->promise_types); sti++)
840  {
841  PromiseType *promise_type = SeqAt(bundle->promise_types, sti);
842 
843  for (size_t ppi = 0; ppi < SeqLength(promise_type->promises); ppi++)
844  {
845  Promise *promise = SeqAt(promise_type->promises, ppi);
846 
847  for (size_t cpi = 0; cpi < SeqLength(promise->conlist); cpi++)
848  {
849  Constraint *constraint = SeqAt(promise->conlist, cpi);
850 
851  const ConstraintSyntax *syntax = ConstraintGetSyntax(constraint);
852  if (syntax->dtype == CF_DATA_TYPE_BODY)
853  {
854  char *ns = QualifiedNameNamespaceComponent(RvalFullSymbol(&constraint->rval));
855  char *symbol = QualifiedNameScopeComponent(RvalFullSymbol(&constraint->rval));
856 
857  Body *referenced_body = PolicyGetBody(policy, ns, constraint->lval, symbol);
858  if (!referenced_body)
859  {
861  POLICY_ERROR_BODY_UNDEFINED, symbol, constraint->lval));
862  success = false;
863  }
864 
865  free(ns);
866  free(symbol);
867  }
868  } // constraints
869  } // promises
870  } // promise_types
871  } // bundles
872 
873  return success;
874 }
875 
876 static bool PolicyCheckUndefinedBundles(const Policy *policy, Seq *errors)
877 {
878  bool success = true;
879 
880  for (size_t bpi = 0; bpi < SeqLength(policy->bundles); bpi++)
881  {
882  Bundle *bundle = SeqAt(policy->bundles, bpi);
883 
884  for (size_t sti = 0; sti < SeqLength(bundle->promise_types); sti++)
885  {
886  PromiseType *promise_type = SeqAt(bundle->promise_types, sti);
887 
888  for (size_t ppi = 0; ppi < SeqLength(promise_type->promises); ppi++)
889  {
890  Promise *promise = SeqAt(promise_type->promises, ppi);
891 
892  for (size_t cpi = 0; cpi < SeqLength(promise->conlist); cpi++)
893  {
894  Constraint *constraint = SeqAt(promise->conlist, cpi);
895 
896  const ConstraintSyntax *syntax = ConstraintGetSyntax(constraint);
897  if (syntax->dtype == CF_DATA_TYPE_BUNDLE &&
898  !IsCf3VarString(RvalFullSymbol(&constraint->rval)))
899  {
900  char *ns = QualifiedNameNamespaceComponent(RvalFullSymbol(&constraint->rval));
901  char *symbol = QualifiedNameScopeComponent(RvalFullSymbol(&constraint->rval));
902 
903  const Bundle *referenced_bundle = NULL;
904  if (strcmp(constraint->lval, "usebundle") == 0 || strcmp(constraint->lval, "home_bundle") == 0)
905  {
906  referenced_bundle = PolicyGetBundle(policy, ns, "agent", symbol);
907  if (!referenced_bundle)
908  {
909  referenced_bundle = PolicyGetBundle(policy, ns, "common", symbol);
910  }
911  }
912  else
913  {
914  referenced_bundle = PolicyGetBundle(policy, ns, constraint->lval, symbol);
915  }
916 
917  if (!referenced_bundle)
918  {
920  POLICY_ERROR_BUNDLE_UNDEFINED, symbol, constraint->lval));
921  success = false;
922  }
923 
924  free(ns);
925  free(symbol);
926  }
927  } // constraints
928  } // promises
929  } // promise_types
930  } // bundles
931 
932  return success;
933 }
934 
935 static bool PolicyCheckRequiredComments(const EvalContext *ctx, const Policy *policy, Seq *errors)
936 {
937  const Body *common_control = PolicyGetBody(policy, NULL, "common", "control");
938  if (common_control)
939  {
940  bool require_comments = ConstraintsGetAsBoolean(ctx, "require_comments", common_control->conlist);
941  if (!require_comments)
942  {
943  return true;
944  }
945 
946  bool success = true;
947 
948  for (size_t bpi = 0; bpi < SeqLength(policy->bundles); bpi++)
949  {
950  Bundle *bundle = SeqAt(policy->bundles, bpi);
951 
952  for (size_t sti = 0; sti < SeqLength(bundle->promise_types); sti++)
953  {
954  PromiseType *promise_type = SeqAt(bundle->promise_types, sti);
955 
956  for (size_t ppi = 0; ppi < SeqLength(promise_type->promises); ppi++)
957  {
958  Promise *promise = SeqAt(promise_type->promises, ppi);
959 
960  bool promise_has_comment = false;
961  for (size_t cpi = 0; cpi < SeqLength(promise->conlist); cpi++)
962  {
963  Constraint *constraint = SeqAt(promise->conlist, cpi);
964 
965  if (strcmp(constraint->lval, "comment") == 0)
966  {
967  promise_has_comment = true;
968  break;
969  }
970  } // constraints
971 
972  if (!promise_has_comment)
973  {
976  success = false;
977  }
978  } // promises
979  } // promise_types
980  } // bundles
981 
982  return success;
983  }
984  else
985  {
986  return true;
987  }
988 }
989 
990 bool PolicyCheckDuplicateHandles(const Policy *policy, Seq *errors)
991 {
992  bool success = true;
993 
995 
996  for (size_t bpi = 0; bpi < SeqLength(policy->bundles); bpi++)
997  {
998  Bundle *bundle = SeqAt(policy->bundles, bpi);
999 
1000  for (size_t sti = 0; sti < SeqLength(bundle->promise_types); sti++)
1001  {
1002  PromiseType *promise_type = SeqAt(bundle->promise_types, sti);
1003 
1004  for (size_t ppi = 0; ppi < SeqLength(promise_type->promises); ppi++)
1005  {
1006  Promise *promise = SeqAt(promise_type->promises, ppi);
1007  const char *handle = PromiseGetHandle(promise);
1008 
1009  if (handle)
1010  {
1011  if (IsCf3VarString(handle))
1012  {
1013  // can't check dynamic handles
1014  continue;
1015  }
1016 
1017  const Promise *other_promise = MapGet(recorded, handle);
1018  if (other_promise)
1019  {
1020  // Need to make this smarter by comparing parsed expressions for equivalency.
1021  if (strcmp(promise->classes, other_promise->classes) == 0)
1022  {
1025  success = false;
1026  }
1027  }
1028  else
1029  {
1030  MapInsert(recorded, (void *)handle, (void *)promise);
1031  }
1032  }
1033  }
1034  }
1035  }
1036 
1037  MapDestroy(recorded);
1038 
1039  return success;
1040 }
1041 
1042 /**
1043  * @brief Check a runnable policy DOM for errors
1044  * @param policy Policy to check
1045  * @param errors Sequence of PolicyError to append errors to
1046  * @param ignore_missing_bundles Whether to ignore missing bundle references
1047  * @return True if no new errors are found
1048  */
1049 bool PolicyCheckRunnable(const EvalContext *ctx, const Policy *policy, Seq *errors, bool ignore_missing_bundles)
1050 {
1051  bool success = true;
1052 
1053  success &= PolicyCheckRequiredComments(ctx, policy, errors);
1054  success &= PolicyCheckUndefinedBodies(policy, errors);
1055 
1056  if (!ignore_missing_bundles)
1057  {
1058  success &= PolicyCheckUndefinedBundles(policy, errors);
1059  }
1060 
1061  success &= PolicyCheckDuplicateHandles(policy, errors);
1062 
1063  return success;
1064 }
1065 
1066 /**
1067  * @brief Check a partial policy DOM for errors
1068  * @param policy Policy to check
1069  * @param errors Sequence of PolicyError to append errors to
1070  * @return True if no new errors are found
1071  */
1072 bool PolicyCheckPartial(const Policy *policy, Seq *errors)
1073 {
1074  bool success = true;
1075 
1076  // ensure bundle names are not duplicated
1077  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
1078  {
1079  Bundle *bp = SeqAt(policy->bundles, i);
1080 
1081  for (size_t j = 0; j < SeqLength(policy->bundles); j++)
1082  {
1083  Bundle *bp2 = SeqAt(policy->bundles, j);
1084 
1085  if (bp != bp2
1086  && strcmp(bp->type, bp2->type) == 0
1087  && strcmp(bp->ns, bp2->ns) == 0
1088  && strcmp(bp->name, bp2->name) == 0)
1089  {
1092  bp->name, bp->type));
1093  success = false;
1094  }
1095  }
1096  }
1097 
1098  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
1099  {
1100  Bundle *bp = SeqAt(policy->bundles, i);
1101  success &= PolicyCheckBundle(bp, errors);
1102  }
1103 
1104 
1105  // ensure body names are not duplicated
1106  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
1107  {
1108  const Body *bp = SeqAt(policy->bodies, i);
1109 
1110  for (size_t j = 0; j < SeqLength(policy->bodies); j++)
1111  {
1112  const Body *bp2 = SeqAt(policy->bodies, j);
1113 
1114  if (bp != bp2
1115  && strcmp(bp->type, bp2->type) == 0
1116  && strcmp(bp->ns, bp2->ns) == 0
1117  && strcmp(bp->name, bp2->name) == 0)
1118  {
1119  if (strcmp(bp->type,"file") != 0)
1120  {
1123  bp->name, bp->type));
1124  success = false;
1125  }
1126  }
1127  }
1128  }
1129 
1130  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
1131  {
1132  const Body *body = SeqAt(policy->bodies, i);
1133  success &= PolicyCheckBody(body, errors);
1134 
1135  }
1136 
1137  success &= PolicyCheckDuplicateHandles(policy, errors);
1138 
1139  return success;
1140 }
1141 
1142 /*************************************************************************/
1143 
1144 PolicyError *PolicyErrorNew(PolicyElementType type, const void *subject, const char *error_msg, ...)
1145 {
1146  PolicyError *error = xmalloc(sizeof(PolicyError));
1147 
1148  error->type = type;
1149  error->subject = subject;
1150 
1151  va_list args;
1152  va_start(args, error_msg);
1153  xvasprintf(&error->message, error_msg, args);
1154  va_end(args);
1155 
1156  return error;
1157 }
1158 
1159 /*************************************************************************/
1160 
1162 {
1163  free(error->message);
1164  free(error);
1165 }
1166 
1167 /*************************************************************************/
1168 
1170 {
1171  assert(element);
1172 
1173  switch (type)
1174  {
1176  {
1177  return (SourceOffset) { 0 };
1178  }
1179 
1181  {
1182  const Bundle *bundle = (const Bundle *)element;
1183  return bundle->offset;
1184  }
1185 
1187  {
1188  const Body *body = (const Body *)element;
1189  return body->offset;
1190  }
1191 
1193  {
1194  const PromiseType *promise_type = (const PromiseType *)element;
1195  return promise_type->offset;
1196  }
1197 
1199  {
1200  const Promise *promise = (const Promise *)element;
1201  return promise->offset;
1202  }
1203 
1205  {
1206  const Constraint *constraint = (const Constraint *)element;
1207  return constraint->offset;
1208  }
1209 
1210  default:
1211  assert(false && "Invalid policy element");
1212  return (SourceOffset) { 0 };
1213  }
1214 }
1215 
1216 /*************************************************************************/
1217 
1218 static const char *PolicyElementSourceFile(PolicyElementType type, const void *element)
1219 {
1220  assert(element);
1221 
1222  switch (type)
1223  {
1225  return "";
1226 
1228  {
1229  const Bundle *bundle = (const Bundle *)element;
1230  return bundle->source_path;
1231  }
1232 
1234  {
1235  const Body *body = (const Body *)element;
1236  return body->source_path;
1237  }
1238 
1240  {
1241  const PromiseType *promise_type = (const PromiseType *)element;
1243  }
1244 
1246  {
1247  const Promise *promise = (const Promise *)element;
1249  }
1250 
1252  {
1253  const Constraint *constraint = (const Constraint *)element;
1254  switch (constraint->type)
1255  {
1258 
1261 
1262  default:
1263  assert(false && "Constraint has invalid parent element type");
1264  return NULL;
1265  }
1266  }
1267 
1268  default:
1269  assert(false && "Invalid policy element");
1270  return NULL;
1271  }
1272 }
1273 
1274 /*************************************************************************/
1275 
1276 void PolicyErrorWrite(Writer *writer, const PolicyError *error)
1277 {
1278  SourceOffset offset = PolicyElementSourceOffset(error->type, error->subject);
1279  const char *path = PolicyElementSourceFile(error->type, error->subject);
1280 
1281  // FIX: need to track columns in SourceOffset
1282  WriterWriteF(writer, "%s:%zu:%zu: error: %s\n", path, offset.line, (size_t)0, error->message);
1283 }
1284 
1285 static char *PolicyErrorToString(const PolicyError *error)
1286 {
1287  SourceOffset offset = PolicyElementSourceOffset(error->type, error->subject);
1288  const char *path = PolicyElementSourceFile(error->type, error->subject);
1289 
1290  Writer *msg = StringWriter();
1291  WriterWriteF(msg, "%s:%zu:%zu: %s.",
1292  path, offset.line,
1293  (size_t)0, error->message);
1294 
1295  switch (error->type)
1296  {
1298  {
1299  const Constraint *cp = error->subject;
1300  WriterWrite(msg, " Given attribute value '");
1301  RvalWrite(msg, cp->rval);
1302  WriterWriteChar(msg, '\'');
1303  }
1304  break;
1305 
1306  default:
1307  break;
1308  }
1309 
1310  return StringWriterClose(msg);
1311 }
1312 
1313 /*************************************************************************/
1314 
1315 void PromiseTypeDestroy(PromiseType *promise_type)
1316 {
1317  if (promise_type)
1318  {
1319  SeqDestroy(promise_type->promises);
1320 
1321  free(promise_type->name);
1322  free(promise_type);
1323  }
1324 }
1325 
1327  const char *ns, const char *name, const char *type,
1328  const Rlist *args, const char *source_path)
1329 {
1330  Bundle *bundle = xcalloc(1, sizeof(Bundle));
1331 
1332  bundle->parent_policy = policy;
1333 
1334  SeqAppend(policy->bundles, bundle);
1335 
1336  bundle->name = xstrdup(name);
1337  bundle->type = xstrdup(type);
1338  bundle->ns = xstrdup(ns);
1339  bundle->args = RlistCopy(args);
1340  bundle->source_path = SafeStringDuplicate(source_path);
1341  bundle->promise_types = SeqNew(10, PromiseTypeDestroy);
1342 
1343  return bundle;
1344 }
1345 
1346 /*******************************************************************/
1347 
1348 Body *PolicyAppendBody(Policy *policy, const char *ns, const char *name, const char *type, Rlist *args, const char *source_path)
1349 {
1350  Body *body = xcalloc(1, sizeof(Body));
1351  body->parent_policy = policy;
1352 
1353  SeqAppend(policy->bodies, body);
1354 
1355  body->name = xstrdup(name);
1356  body->type = xstrdup(type);
1357  body->ns = xstrdup(ns);
1358  body->args = RlistCopy(args);
1359  body->source_path = SafeStringDuplicate(source_path);
1360  body->conlist = SeqNew(10, ConstraintDestroy);
1361 
1362  // TODO: move to standard callback
1363  if (strcmp("service_method", body->name) == 0)
1364  {
1365  Rlist *bundle_args = NULL;
1366  RlistAppendRval(&bundle_args, RvalNew("$(this.promiser)", RVAL_TYPE_SCALAR));
1367  RlistAppendRval(&bundle_args, RvalNew("$(this.service_policy)", RVAL_TYPE_SCALAR));
1368 
1369  FnCall *service_bundle = FnCallNew("standard_services", bundle_args);
1370  BodyAppendConstraint(body, "service_bundle", (Rval) { service_bundle, RVAL_TYPE_FNCALL }, "any", false);
1371  }
1372 
1373  return body;
1374 }
1375 
1376 PromiseType *BundleAppendPromiseType(Bundle *bundle, const char *name)
1377 {
1378  if (bundle == NULL)
1379  {
1380  ProgrammingError("Attempt to add a type without a bundle");
1381  }
1382 
1383  // TODO: review SeqLookup
1384  for (size_t i = 0; i < SeqLength(bundle->promise_types); i++)
1385  {
1386  PromiseType *existing = SeqAt(bundle->promise_types, i);
1387  if (strcmp(existing->name, name) == 0)
1388  {
1389  return existing;
1390  }
1391  }
1392 
1393  PromiseType *tp = xcalloc(1, sizeof(PromiseType));
1394 
1395  tp->parent_bundle = bundle;
1396  tp->name = xstrdup(name);
1397  tp->promises = SeqNew(10, PromiseDestroy);
1398 
1399  SeqAppend(bundle->promise_types, tp);
1400 
1401  return tp;
1402 }
1403 
1404 /*******************************************************************/
1405 
1406 Promise *PromiseTypeAppendPromise(PromiseType *type, const char *promiser, Rval promisee, const char *classes, const char *varclasses)
1407 {
1408  assert(promiser && "Missing promiser");
1409  assert(type && "Missing promise type");
1410 
1411  Promise *pp = xcalloc(1, sizeof(Promise));
1412 
1413  pp->promiser = xstrdup(promiser);
1414 
1415  if (classes && strlen(classes) > 0)
1416  {
1417  pp->classes = xstrdup(classes);
1418  }
1419  else
1420  {
1421  pp->classes = xstrdup("any");
1422  }
1423 
1424  SeqAppend(type->promises, pp);
1425 
1426  pp->parent_promise_type = type;
1427 
1428  pp->promisee = promisee;
1429  pp->conlist = SeqNew(10, ConstraintDestroy);
1430  pp->org_pp = pp;
1431 
1432  if (varclasses != NULL)
1433  {
1434  PromiseAppendConstraint(pp, "ifvarclass", RvalNew(varclasses, RVAL_TYPE_SCALAR), true);
1435  }
1436 
1437  return pp;
1438 }
1439 
1440 static void BundleDestroy(Bundle *bundle)
1441 {
1442  if (bundle)
1443  {
1444  free(bundle->name);
1445  free(bundle->type);
1446  free(bundle->ns);
1447  free(bundle->source_path);
1448 
1449  RlistDestroy(bundle->args);
1450  SeqDestroy(bundle->promise_types);
1451  free(bundle);
1452  }
1453 }
1454 
1455 static void BodyDestroy(Body *body)
1456 {
1457  if (body)
1458  {
1459  free(body->name);
1460  free(body->type);
1461  free(body->ns);
1462  free(body->source_path);
1463 
1464  RlistDestroy(body->args);
1465  SeqDestroy(body->conlist);
1466  free(body);
1467  }
1468 }
1469 
1470 
1472 {
1473  if (pp)
1474  {
1475  free(pp->promiser);
1476 
1477  if (pp->promisee.item)
1478  {
1479  RvalDestroy(pp->promisee);
1480  }
1481 
1482  free(pp->classes);
1483  free(pp->comment);
1484 
1485  SeqDestroy(pp->conlist);
1486 
1487  free(pp);
1488  }
1489 }
1490 
1491 /*******************************************************************/
1492 
1493 static Constraint *ConstraintNew(const char *lval, Rval rval, const char *classes, bool references_body)
1494 {
1495  Constraint *cp = xcalloc(1, sizeof(Constraint));
1496 
1497  cp->lval = SafeStringDuplicate(lval);
1498  cp->rval = rval;
1499 
1500  cp->classes = SafeStringDuplicate(classes);
1501  cp->references_body = references_body;
1502 
1503  return cp;
1504 }
1505 
1506 Constraint *PromiseAppendConstraint(Promise *pp, const char *lval, Rval rval, bool references_body)
1507 {
1508  Constraint *cp = ConstraintNew(lval, rval, "any", references_body);
1510  cp->parent.promise = pp;
1511 
1512  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
1513  {
1514  Constraint *old_cp = SeqAt(pp->conlist, i);
1515  if (strcmp(old_cp->lval, lval) == 0)
1516  {
1517  if (strcmp(old_cp->lval, "ifvarclass") == 0 ||
1518  strcmp(old_cp->lval, "if") == 0)
1519  {
1520  // merge two if/ifvarclass promise attributes this
1521  // only happens in a variable context when we have a
1522  // scalar already in the attribute (old_cp)
1523  switch (rval.type)
1524  {
1525  case RVAL_TYPE_FNCALL: // case 1: merge FnCall with scalar
1526  {
1527  char * rval_string = RvalToString(old_cp->rval);
1528  Log(LOG_LEVEL_DEBUG, "PromiseAppendConstraint: merging PREVIOUS %s string context rval %s", old_cp->lval, rval_string);
1529  Log(LOG_LEVEL_DEBUG, "PromiseAppendConstraint: merging NEW %s rval %s", old_cp->lval, rval_string);
1530  free(rval_string);
1531 
1532  Rlist *synthetic_args = NULL;
1533  RlistAppendScalar(&synthetic_args, RvalScalarValue(old_cp->rval));
1534 
1535  // append the old Rval (a function call) under the arguments of the new one
1536  RlistAppend(&synthetic_args, rval.item, RVAL_TYPE_FNCALL);
1537 
1538  Rval replacement = (Rval) { FnCallNew("and", synthetic_args), RVAL_TYPE_FNCALL };
1539  rval_string = RvalToString(replacement);
1540  Log(LOG_LEVEL_DEBUG, "PromiseAppendConstraint: MERGED %s rval %s", old_cp->lval, rval_string);
1541  free(rval_string);
1542 
1543  // overwrite the old Constraint rval with its replacement
1544  RvalDestroy(cp->rval);
1545  cp->rval = replacement;
1546  }
1547  break;
1548 
1549  case RVAL_TYPE_SCALAR: // case 2: merge scalar with scalar
1550  {
1551  Buffer *grow = BufferNew();
1552  BufferAppendF(grow, "(%s).(%s)",
1553  RvalScalarValue(old_cp->rval),
1554  RvalScalarValue(rval));
1555  RvalDestroy(cp->rval);
1556  rval = RvalNew(BufferData(grow), RVAL_TYPE_SCALAR);
1557  BufferDestroy(grow);
1558  cp->rval = rval;
1559  }
1560  break;
1561 
1562  default:
1563  ProgrammingError("PromiseAppendConstraint: unexpected rval type: %c", rval.type);
1564  break;
1565  }
1566  }
1567  SeqSet(pp->conlist, i, cp);
1568  return cp;
1569  }
1570  }
1571 
1572  SeqAppend(pp->conlist, cp);
1573  return cp;
1574 }
1575 
1576 Constraint *BodyAppendConstraint(Body *body, const char *lval, Rval rval, const char *classes,
1577  bool references_body)
1578 {
1579  Constraint *cp = ConstraintNew(lval, rval, classes, references_body);
1581  cp->parent.body = body;
1582 
1583  for (size_t i = 0; i < SeqLength(body->conlist); i++)
1584  {
1585  Constraint *old_cp = SeqAt(body->conlist, i);
1586  if (strcmp(old_cp->lval, lval) == 0 && strcmp(old_cp->classes, classes) == 0)
1587  {
1588  SeqSet(body->conlist, i, cp);
1589  return cp;
1590  }
1591  }
1592 
1593  SeqAppend(body->conlist, cp);
1594 
1595  return cp;
1596 }
1597 
1598 /*******************************************************************/
1599 
1600 const PromiseType *BundleGetPromiseType(const Bundle *bp, const char *name)
1601 {
1602  // TODO: hiding error, remove and see what will crash
1603  if (bp == NULL)
1604  {
1605  return NULL;
1606  }
1607 
1608  for (size_t i = 0; i < SeqLength(bp->promise_types); i++)
1609  {
1610  PromiseType *sp = SeqAt(bp->promise_types, i);
1611 
1612  if (strcmp(name, sp->name) == 0)
1613  {
1614  return sp;
1615  }
1616  }
1617 
1618  return NULL;
1619 }
1620 
1621 /****************************************************************************/
1622 
1623 static Buffer *EscapeQuotes(const char *raw, Buffer *out)
1624 {
1625  const char *spf;
1626 
1627  for (spf = raw; *spf != '\0'; spf++)
1628  {
1629  switch (*spf)
1630  {
1631  case '\'':
1632  case '\"':
1633  BufferAppendChar(out, '\\');
1634  break;
1635 
1636  default:
1637  break;
1638  }
1639  BufferAppendChar(out, *spf);
1640  }
1641 
1642  return out;
1643 }
1644 
1645 /**
1646  * Converts the given attribute rval to a JSON object.
1647  *
1648  * @return A JsonElement of type JSON_ELEMENT_TYPE_CONTAINER
1649  */
1650 static JsonElement *AttributeValueToJson(Rval rval, bool symbolic_reference)
1651 {
1652  switch (rval.type)
1653  {
1654  case RVAL_TYPE_CONTAINER:
1655  {
1656  return JsonCopy(RvalContainerValue(rval));
1657  }
1658 
1659  case RVAL_TYPE_SCALAR:
1660  {
1661  Buffer *buffer = BufferNewWithCapacity(strlen(rval.item));
1662 
1663  EscapeQuotes((const char *) rval.item, buffer);
1664 
1665  JsonElement *json_attribute = JsonObjectCreate(10);
1666 
1667  if (symbolic_reference)
1668  {
1669  JsonObjectAppendString(json_attribute, "type", "symbol");
1670  }
1671  else
1672  {
1673  JsonObjectAppendString(json_attribute, "type", "string");
1674  }
1675  JsonObjectAppendString(json_attribute, "value", BufferData(buffer));
1676 
1677  BufferDestroy(buffer);
1678 
1679  return json_attribute;
1680  }
1681 
1682 
1683  case RVAL_TYPE_LIST:
1684  {
1685  Rlist *rp = NULL;
1686  JsonElement *list = JsonArrayCreate(10);
1687 
1688  JsonElement *json_attribute = JsonObjectCreate(10);
1689  JsonObjectAppendString(json_attribute, "type", "list");
1690 
1691  for (rp = (Rlist *) rval.item; rp != NULL; rp = rp->next)
1692  {
1693  JsonArrayAppendObject(list, AttributeValueToJson(rp->val, false));
1694  }
1695 
1696  JsonObjectAppendArray(json_attribute, "value", list);
1697  return json_attribute;
1698  }
1699 
1700  case RVAL_TYPE_FNCALL:
1701  {
1702  Rlist *argp = NULL;
1703  FnCall *call = (FnCall *) rval.item;
1704 
1705  JsonElement *json_attribute = JsonObjectCreate(10);
1706  JsonObjectAppendString(json_attribute, "type", "functionCall");
1707  JsonObjectAppendString(json_attribute, "name", call->name);
1708 
1709  {
1710  JsonElement *arguments = JsonArrayCreate(10);
1711 
1712  for (argp = call->args; argp != NULL; argp = argp->next)
1713  {
1714  JsonArrayAppendObject(arguments, AttributeValueToJson(argp->val, false));
1715  }
1716 
1717  JsonObjectAppendArray(json_attribute, "arguments", arguments);
1718  }
1719 
1720  return json_attribute;
1721  }
1722 
1723  case RVAL_TYPE_NOPROMISEE:
1724  ProgrammingError("Attempted to export attribute of type: %c", rval.type);
1725  return NULL;
1726  }
1727 
1728  assert(false);
1729  return NULL;
1730 }
1731 
1732 static JsonElement *CreateContextAsJson(const char *name, const char *children_name, JsonElement *children)
1733 {
1734  JsonElement *json = JsonObjectCreate(10);
1735 
1736  JsonObjectAppendString(json, "name", name);
1737  JsonObjectAppendArray(json, children_name, children);
1738 
1739  return json;
1740 }
1741 
1742 static JsonElement *BodyContextsToJson(const Seq *constraints)
1743 {
1744  JsonElement *json_contexts = JsonArrayCreate(10);
1745  JsonElement *json_attributes = JsonArrayCreate(10);
1746  char *current_context = "any";
1747 
1748  for (size_t i = 0; i < SeqLength(constraints); i++)
1749  {
1750  Constraint *cp = SeqAt(constraints, i);
1751 
1752  JsonElement *json_attribute = JsonObjectCreate(10);
1753 
1754  if (strcmp(current_context, cp->classes) != 0)
1755  {
1756  JsonArrayAppendObject(json_contexts,
1757  CreateContextAsJson(current_context,
1758  "attributes", json_attributes));
1759  json_attributes = JsonArrayCreate(10);
1760  current_context = cp->classes;
1761  }
1762 
1763  JsonObjectAppendInteger(json_attribute, "line", cp->offset.line);
1764 
1765  JsonObjectAppendString(json_attribute, "lval", cp->lval);
1766  JsonObjectAppendObject(json_attribute, "rval", AttributeValueToJson(cp->rval, false));
1767  JsonArrayAppendObject(json_attributes, json_attribute);
1768  }
1769 
1770  JsonArrayAppendObject(json_contexts,
1771  CreateContextAsJson(current_context,
1772  "attributes", json_attributes));
1773 
1774  return json_contexts;
1775 }
1776 
1777 static JsonElement *BundleContextsToJson(const Seq *promises)
1778 {
1779  JsonElement *json_contexts = JsonArrayCreate(10);
1780  JsonElement *json_promises = JsonArrayCreate(10);
1781  char *current_context = NULL;
1782 
1783  for (size_t ppi = 0; ppi < SeqLength(promises); ppi++)
1784  {
1785  Promise *pp = SeqAt(promises, ppi);
1786 
1787  if (!current_context)
1788  {
1789  current_context = pp->classes;
1790  }
1791 
1792  JsonElement *json_promise = JsonObjectCreate(10);
1793 
1794  if (strcmp(current_context, pp->classes) != 0)
1795  {
1796  JsonArrayAppendObject(json_contexts,
1797  CreateContextAsJson(current_context,
1798  "promises", json_promises));
1799  json_promises = JsonArrayCreate(10);
1800  current_context = pp->classes;
1801  }
1802 
1803  JsonObjectAppendInteger(json_promise, "line", pp->offset.line);
1804 
1805  {
1806  JsonElement *json_promise_attributes = JsonArrayCreate(10);
1807 
1808  for (size_t k = 0; k < SeqLength(pp->conlist); k++)
1809  {
1810  Constraint *cp = SeqAt(pp->conlist, k);
1811 
1812  JsonElement *json_attribute = JsonObjectCreate(10);
1813 
1814  JsonObjectAppendInteger(json_attribute, "line", cp->offset.line);
1815 
1816  JsonObjectAppendString(json_attribute, "lval", cp->lval);
1817  JsonElement *json_rval = AttributeValueToJson(cp->rval, cp->references_body);
1819  {
1820  JsonObjectAppendArray(json_attribute, "rval", json_rval);
1821  }
1822  else
1823  {
1824  JsonObjectAppendObject(json_attribute, "rval", json_rval);
1825  }
1826  JsonArrayAppendObject(json_promise_attributes, json_attribute);
1827  }
1828 
1829  JsonObjectAppendString(json_promise, "promiser", pp->promiser);
1830 
1831  switch (pp->promisee.type)
1832  {
1833  case RVAL_TYPE_SCALAR:
1834  JsonObjectAppendString(json_promise, "promisee", pp->promisee.item);
1835  break;
1836 
1837  case RVAL_TYPE_LIST:
1838  {
1839  JsonElement *promisee_list = JsonArrayCreate(10);
1840  for (const Rlist *rp = pp->promisee.item; rp; rp = rp->next)
1841  {
1842  JsonArrayAppendString(promisee_list, RlistScalarValue(rp));
1843  }
1844  JsonObjectAppendArray(json_promise, "promisee", promisee_list);
1845  }
1846  break;
1847 
1848  default:
1849  break;
1850  }
1851 
1852  JsonObjectAppendArray(json_promise, "attributes", json_promise_attributes);
1853  }
1854  JsonArrayAppendObject(json_promises, json_promise);
1855  }
1856 
1857  if (JsonLength(json_promises) > 0)
1858  {
1859  JsonArrayAppendObject(json_contexts,
1860  CreateContextAsJson(current_context,
1861  "promises", json_promises));
1862  }
1863 
1864  return json_contexts;
1865 }
1866 
1867 /**
1868  * @brief Serialize a bundle as JSON
1869  * @param bundle The bundle to serialize
1870  * @return A JsonElement representing the input bundle
1871  */
1873 {
1874  JsonElement *json_bundle = JsonObjectCreate(10);
1875 
1876  if (bundle->source_path)
1877  {
1878  JsonObjectAppendString(json_bundle, "sourcePath", bundle->source_path);
1879  }
1880  JsonObjectAppendInteger(json_bundle, "line", bundle->offset.line);
1881 
1882  JsonObjectAppendString(json_bundle, "namespace", bundle->ns);
1883  JsonObjectAppendString(json_bundle, "name", bundle->name);
1884  JsonObjectAppendString(json_bundle, "bundleType", bundle->type);
1885 
1886  {
1887  JsonElement *json_args = JsonArrayCreate(10);
1888  Rlist *argp = NULL;
1889 
1890  for (argp = bundle->args; argp != NULL; argp = argp->next)
1891  {
1892  JsonArrayAppendString(json_args, RlistScalarValue(argp));
1893  }
1894 
1895  JsonObjectAppendArray(json_bundle, "arguments", json_args);
1896  }
1897 
1898  {
1899  JsonElement *json_promise_types = JsonArrayCreate(10);
1900 
1901  for (size_t i = 0; i < SeqLength(bundle->promise_types); i++)
1902  {
1903  const PromiseType *sp = SeqAt(bundle->promise_types, i);
1904 
1905  JsonElement *json_promise_type = JsonObjectCreate(10);
1906 
1907  JsonObjectAppendInteger(json_promise_type, "line", sp->offset.line);
1908  JsonObjectAppendString(json_promise_type, "name", sp->name);
1909  JsonObjectAppendArray(json_promise_type, "contexts", BundleContextsToJson(sp->promises));
1910 
1911  JsonArrayAppendObject(json_promise_types, json_promise_type);
1912  }
1913 
1914  JsonObjectAppendArray(json_bundle, "promiseTypes", json_promise_types);
1915  }
1916 
1917  return json_bundle;
1918 }
1919 
1920 /**
1921  * @brief Serialize a body as JSON
1922  * @param body The body to serialize
1923  * @return A JsonElement representing the input body
1924  */
1926 {
1927  JsonElement *json_body = JsonObjectCreate(10);
1928 
1929  if (body->source_path)
1930  {
1931  JsonObjectAppendString(json_body, "sourcePath", body->source_path);
1932  }
1933  JsonObjectAppendInteger(json_body, "line", body->offset.line);
1934 
1935  JsonObjectAppendString(json_body, "namespace", body->ns);
1936  JsonObjectAppendString(json_body, "name", body->name);
1937  JsonObjectAppendString(json_body, "bodyType", body->type);
1938 
1939  {
1940  JsonElement *json_args = JsonArrayCreate(10);
1941  Rlist *argp = NULL;
1942 
1943  for (argp = body->args; argp != NULL; argp = argp->next)
1944  {
1945  JsonArrayAppendString(json_args, RlistScalarValue(argp));
1946  }
1947 
1948  JsonObjectAppendArray(json_body, "arguments", json_args);
1949  }
1950 
1951  JsonObjectAppendArray(json_body, "contexts", BodyContextsToJson(body->conlist));
1952 
1953  return json_body;
1954 }
1955 
1956 /**
1957  * @brief Serialize a policy as JSON
1958  * @param policy The policy to serialize
1959  * @return A JsonElement representing the input policy
1960  */
1962 {
1963  JsonElement *json_policy = JsonObjectCreate(10);
1964 
1965  {
1966  JsonElement *json_bundles = JsonArrayCreate(10);
1967 
1968  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
1969  {
1970  const Bundle *bp = SeqAt(policy->bundles, i);
1971  JsonArrayAppendObject(json_bundles, BundleToJson(bp));
1972  }
1973 
1974  JsonObjectAppendArray(json_policy, "bundles", json_bundles);
1975  }
1976 
1977  {
1978  JsonElement *json_bodies = JsonArrayCreate(10);
1979 
1980  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
1981  {
1982  const Body *bdp = SeqAt(policy->bodies, i);
1983 
1984  JsonArrayAppendObject(json_bodies, BodyToJson(bdp));
1985  }
1986 
1987  JsonObjectAppendArray(json_policy, "bodies", json_bodies);
1988  }
1989 
1990  return json_policy;
1991 }
1992 
1993 /****************************************************************************/
1994 
1995 
1996 static void IndentPrint(Writer *writer, int indent_level)
1997 {
1998  static const int PRETTY_PRINT_SPACES_PER_INDENT = 2;
1999 
2000  int i = 0;
2001 
2002  for (i = 0; i < PRETTY_PRINT_SPACES_PER_INDENT * indent_level; i++)
2003  {
2004  WriterWriteChar(writer, ' ');
2005  }
2006 }
2007 
2008 static void AttributeToString(Writer *writer, Constraint *attribute, bool symbolic_reference)
2009 {
2010  WriterWriteF(writer, "%s => ", attribute->lval);
2011  if (symbolic_reference)
2012  {
2013  RvalWrite(writer, attribute->rval);
2014  }
2015  else
2016  {
2017  RvalWriteQuoted(writer, attribute->rval);
2018  }
2019 }
2020 
2021 
2022 static void ArgumentsToString(Writer *writer, Rlist *args)
2023 {
2024  Rlist *argp = NULL;
2025 
2026  WriterWriteChar(writer, '(');
2027  for (argp = args; argp != NULL; argp = argp->next)
2028  {
2029  WriterWriteF(writer, "%s", RlistScalarValue(argp));
2030 
2031  if (argp->next != NULL)
2032  {
2033  WriterWrite(writer, ", ");
2034  }
2035  }
2036  WriterWriteChar(writer, ')');
2037 }
2038 
2039 
2040 void BodyToString(Writer *writer, Body *body)
2041 {
2042  char *current_class = NULL;
2043 
2044  WriterWriteF(writer, "body %s %s", body->type, body->name);
2045  ArgumentsToString(writer, body->args);
2046  WriterWrite(writer, "\n{");
2047 
2048  for (size_t i = 0; i < SeqLength(body->conlist); i++)
2049  {
2050  Constraint *cp = SeqAt(body->conlist, i);
2051 
2052  if (current_class == NULL || strcmp(cp->classes, current_class) != 0)
2053  {
2054  current_class = cp->classes;
2055 
2056  if (strcmp(current_class, "any") == 0)
2057  {
2058  WriterWrite(writer, "\n");
2059  }
2060  else
2061  {
2062  WriterWriteF(writer, "\n\n%s::", current_class);
2063  }
2064  }
2065 
2066  IndentPrint(writer, 1);
2067  AttributeToString(writer, cp, false);
2068  WriterWriteChar(writer, ';');
2069  WriterWriteChar(writer, '\n');
2070  }
2071 
2072  WriterWrite(writer, "\n}\n");
2073 }
2074 
2075 
2076 void BundleToString(Writer *writer, Bundle *bundle)
2077 {
2078  WriterWriteF(writer, "bundle %s %s", bundle->type, bundle->name);
2079  ArgumentsToString(writer, bundle->args);
2080  WriterWrite(writer, "\n{");
2081 
2082  for (size_t i = 0; i < SeqLength(bundle->promise_types); i++)
2083  {
2084  PromiseType *promise_type = SeqAt(bundle->promise_types, i);
2085 
2086  WriterWriteF(writer, "\n%s:\n", promise_type->name);
2087 
2088  char *current_class = NULL;
2089  for (size_t ppi = 0; ppi < SeqLength(promise_type->promises); ppi++)
2090  {
2091  Promise *pp = SeqAt(promise_type->promises, ppi);
2092 
2093  if (current_class == NULL || strcmp(pp->classes, current_class) != 0)
2094  {
2095  current_class = pp->classes;
2096  IndentPrint(writer, 1);
2097  WriterWriteF(writer, "%s::\n", current_class);
2098  }
2099 
2100  IndentPrint(writer, 2);
2101  ScalarWrite(writer, pp->promiser, true);
2102 
2103  /* FIX: add support
2104  *
2105  if (pp->promisee != NULL)
2106  {
2107  fprintf(out, "%s", pp->promisee);
2108  }
2109  */
2110 
2111  for (size_t k = 0; k < SeqLength(pp->conlist); k++)
2112  {
2113  Constraint *cp = SeqAt(pp->conlist, k);
2114 
2115  IndentPrint(writer, 4);
2116  AttributeToString(writer, cp, cp->references_body);
2117  if (k < SeqLength(pp->conlist)-1)
2118  {
2119  WriterWriteChar(writer, ',');
2120  WriterWriteChar(writer, '\n');
2121  }
2122  }
2123  WriterWriteChar(writer, ';');
2124  WriterWriteChar(writer, '\n');
2125  }
2126 
2127  if (i == (SeqLength(bundle->promise_types) - 1))
2128  {
2129  WriterWriteChar(writer, '\n');
2130  }
2131  }
2132 
2133  WriterWrite(writer, "\n}\n");
2134 }
2135 
2136 /**
2137  * @brief Pretty-print a policy
2138  * @param policy The policy to print
2139  * @param writer Writer to write into
2140  */
2141 void PolicyToString(const Policy *policy, Writer *writer)
2142 {
2143  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
2144  {
2145  Bundle *bundle = SeqAt(policy->bundles, i);
2146  BundleToString(writer, bundle);
2147  WriterWriteChar(writer, '\n');
2148  }
2149 
2150  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
2151  {
2152  Body *body = SeqAt(policy->bodies, i);
2153  BodyToString(writer, body);
2154  WriterWriteChar(writer, '\n');
2155  }
2156 
2157 }
2158 
2159 //*****************************************************************************
2160 
2161 static Rval RvalFromJson(JsonElement *json_rval)
2162 {
2163  const char *type = JsonObjectGetAsString(json_rval, "type");
2164 
2165  if (strcmp("string", type) == 0 || strcmp("symbol", type) == 0)
2166  {
2167  const char *value = JsonObjectGetAsString(json_rval, "value");
2168  return ((Rval) { xstrdup(value), RVAL_TYPE_SCALAR });
2169  }
2170  else if (strcmp("list", type) == 0)
2171  {
2172  JsonElement *json_list = JsonObjectGetAsArray(json_rval, "value");
2173  Rlist *rlist = NULL;
2174 
2175  for (size_t i = 0; i < JsonLength(json_list); i++)
2176  {
2177  Rval list_value = RvalFromJson(JsonArrayGetAsObject(json_list, i));
2178  RlistAppend(&rlist, list_value.item, list_value.type);
2179  RvalDestroy(list_value);
2180  }
2181 
2182  return ((Rval) { rlist, RVAL_TYPE_LIST });
2183  }
2184  else if (strcmp("functionCall", type) == 0)
2185  {
2186  const char *name = JsonObjectGetAsString(json_rval, "name");
2187  JsonElement *json_args = JsonObjectGetAsArray(json_rval, "arguments");
2188  Rlist *args = NULL;
2189 
2190  for (size_t i = 0; i < JsonLength(json_args); i++)
2191  {
2192  JsonElement *json_arg = JsonArrayGetAsObject(json_args, i);
2193  Rval arg = RvalFromJson(json_arg);
2194 
2195  RlistAppend(&args, arg.item, arg.type);
2196  RvalDestroy(arg);
2197  }
2198 
2199  FnCall *fn = FnCallNew(name, args);
2200 
2201  return ((Rval) { fn, RVAL_TYPE_FNCALL });
2202  }
2203  else
2204  {
2205  ProgrammingError("Unexpected rval type: %s", type);
2206  }
2207 }
2208 
2209 static Constraint *PromiseAppendConstraintJson(Promise *promise, JsonElement *json_constraint)
2210 {
2211  const char *lval = JsonObjectGetAsString(json_constraint, "lval");
2212 
2213  JsonElement *json_rval = JsonObjectGetAsObject(json_constraint, "rval");
2214  const char *type = JsonObjectGetAsString(json_rval, "type");
2215 
2216  Rval rval = RvalFromJson(json_rval);
2217 
2218  Constraint *cp = PromiseAppendConstraint(promise, lval, rval, (strcmp("symbol", type) == 0));
2219 
2220  return cp;
2221 }
2222 
2223 static Promise *PromiseTypeAppendPromiseJson(PromiseType *promise_type, JsonElement *json_promise, const char *context)
2224 {
2225  const char *promiser = JsonObjectGetAsString(json_promise, "promiser");
2226 
2227  Promise *promise = PromiseTypeAppendPromise(promise_type, promiser, (Rval) { NULL, RVAL_TYPE_NOPROMISEE }, context, NULL);
2228 
2229  JsonElement *json_attributes = JsonObjectGetAsArray(json_promise, "attributes");
2230  for (size_t i = 0; i < JsonLength(json_attributes); i++)
2231  {
2232  JsonElement *json_attribute = JsonArrayGetAsObject(json_attributes, i);
2233  PromiseAppendConstraintJson(promise, json_attribute);
2234  }
2235 
2236  return promise;
2237 }
2238 
2239 static PromiseType *BundleAppendPromiseTypeJson(Bundle *bundle, JsonElement *json_promise_type)
2240 {
2241  const char *name = JsonObjectGetAsString(json_promise_type, "name");
2242 
2243  PromiseType *promise_type = BundleAppendPromiseType(bundle, name);
2244 
2245  JsonElement *json_contexts = JsonObjectGetAsArray(json_promise_type, "contexts");
2246  for (size_t i = 0; i < JsonLength(json_contexts); i++)
2247  {
2248  JsonElement *json_context = JsonArrayGetAsObject(json_contexts, i);
2249 
2250  const char *context = JsonObjectGetAsString(json_context, "name");
2251 
2252  JsonElement *json_context_promises = JsonObjectGetAsArray(json_context, "promises");
2253  for (size_t j = 0; j < JsonLength(json_context_promises); j++)
2254  {
2255  JsonElement *json_promise = JsonArrayGetAsObject(json_context_promises, j);
2256  PromiseTypeAppendPromiseJson(promise_type, json_promise, context);
2257  }
2258  }
2259 
2260  return promise_type;
2261 }
2262 
2263 static Bundle *PolicyAppendBundleJson(Policy *policy, JsonElement *json_bundle)
2264 {
2265  const char *ns = JsonObjectGetAsString(json_bundle, "namespace");
2266  const char *name = JsonObjectGetAsString(json_bundle, "name");
2267  const char *type = JsonObjectGetAsString(json_bundle, "bundleType");
2268  const char *source_path = JsonObjectGetAsString(json_bundle, "sourcePath");
2269 
2270  Rlist *args = NULL;
2271  {
2272  JsonElement *json_args = JsonObjectGetAsArray(json_bundle, "arguments");
2273  for (size_t i = 0; i < JsonLength(json_args); i++)
2274  {
2275  RlistAppendScalar(&args, JsonArrayGetAsString(json_args, i));
2276  }
2277  }
2278 
2279  Bundle *bundle = PolicyAppendBundle(policy, ns, name, type, args, source_path);
2280 
2281  {
2282  JsonElement *json_promise_types = JsonObjectGetAsArray(json_bundle, "promiseTypes");
2283  for (size_t i = 0; i < JsonLength(json_promise_types); i++)
2284  {
2285  JsonElement *json_promise_type = JsonArrayGetAsObject(json_promise_types, i);
2286  BundleAppendPromiseTypeJson(bundle, json_promise_type);
2287  }
2288  }
2289 
2290  return bundle;
2291 }
2292 
2293 static Constraint *BodyAppendConstraintJson(Body *body, JsonElement *json_constraint, const char *context)
2294 {
2295  const char *lval = JsonObjectGetAsString(json_constraint, "lval");
2296 
2297  JsonElement *json_rval = JsonObjectGetAsObject(json_constraint, "rval");
2298  const char *type = JsonObjectGetAsString(json_rval, "type");
2299 
2300  Rval rval = RvalFromJson(json_rval);
2301 
2302  Constraint *cp = BodyAppendConstraint(body, lval, rval, context, (strcmp("symbol", type) == 0));
2303 
2304  return cp;
2305 }
2306 
2307 static Body *PolicyAppendBodyJson(Policy *policy, JsonElement *json_body)
2308 {
2309  const char *ns = JsonObjectGetAsString(json_body, "namespace");
2310  const char *name = JsonObjectGetAsString(json_body, "name");
2311  const char *type = JsonObjectGetAsString(json_body, "bodyType");
2312  const char *source_path = JsonObjectGetAsString(json_body, "sourcePath");
2313 
2314  Rlist *args = NULL;
2315  {
2316  JsonElement *json_args = JsonObjectGetAsArray(json_body, "arguments");
2317  for (size_t i = 0; i < JsonLength(json_args); i++)
2318  {
2319  RlistAppendScalar(&args, JsonArrayGetAsString(json_args, i));
2320  }
2321  }
2322 
2323  Body *body = PolicyAppendBody(policy, ns, name, type, args, source_path);
2324 
2325  {
2326  JsonElement *json_contexts = JsonObjectGetAsArray(json_body, "contexts");
2327  for (size_t i = 0; i < JsonLength(json_contexts); i++)
2328  {
2329  JsonElement *json_context = JsonArrayGetAsObject(json_contexts, i);
2330  const char *context = JsonObjectGetAsString(json_context, "name");
2331 
2332  {
2333  JsonElement *json_attributes = JsonObjectGetAsArray(json_context, "attributes");
2334  for (size_t j = 0; j < JsonLength(json_attributes); j++)
2335  {
2336  JsonElement *json_attribute = JsonArrayGetAsObject(json_attributes, j);
2337  BodyAppendConstraintJson(body, json_attribute, context);
2338  }
2339  }
2340  }
2341  }
2342 
2343  return body;
2344 }
2345 
2346 /**
2347  * @brief Deserialize a policy from JSON
2348  * @param json_policy JSON to deserialize
2349  * @return A policy DOM
2350  */
2352 {
2353  Policy *policy = PolicyNew();
2354 
2355  JsonElement *json_bundles = JsonObjectGetAsArray(json_policy, "bundles");
2356  JsonElement *json_bodies = JsonObjectGetAsArray(json_policy, "bodies");
2357 
2358  if ((json_bundles == NULL) && (json_bodies == NULL))
2359  {
2360  return NULL;
2361  }
2362 
2363  if (json_bundles != NULL)
2364  {
2365  for (size_t i = 0; i < JsonLength(json_bundles); i++)
2366  {
2367  JsonElement *json_bundle = JsonArrayGetAsObject(json_bundles, i);
2368  PolicyAppendBundleJson(policy, json_bundle);
2369  }
2370  }
2371  if (json_bodies != NULL)
2372  {
2373  for (size_t i = 0; i < JsonLength(json_bodies); i++)
2374  {
2375  JsonElement *json_body = JsonArrayGetAsObject(json_bodies, i);
2376  PolicyAppendBodyJson(policy, json_body);
2377  }
2378  }
2379 
2380  return policy;
2381 }
2382 
2383 /**
2384  * @brief A sequence of constraints matching the l-value.
2385  * @param body Body to query
2386  * @param lval l-value to match
2387  * @return Sequence of pointers to the constraints. Destroying it does not alter the DOM.
2388  */
2389 Seq *BodyGetConstraint(Body *body, const char *lval)
2390 {
2391  Seq *matches = SeqNew(5, NULL);
2392 
2393  for (size_t i = 0; i < SeqLength(body->conlist); i++)
2394  {
2395  Constraint *cp = SeqAt(body->conlist, i);
2396  if (strcmp(cp->lval, lval) == 0)
2397  {
2398  SeqAppend(matches, cp);
2399  }
2400  }
2401 
2402  return matches;
2403 }
2404 
2405 bool BodyHasConstraint(const Body *body, const char *lval)
2406 {
2407  for (int i = 0; i < SeqLength(body->conlist); i++)
2408  {
2409  Constraint *cp = SeqAt(body->conlist, i);
2410  if (strcmp(lval, cp->lval) == 0)
2411  {
2412  return true;
2413  }
2414  }
2415 
2416  return false;
2417 }
2418 
2419 /**
2420  * @brief Get the context of the given constraint
2421  * @param cp
2422  * @return context. never returns NULL.
2423  */
2424 const char *ConstraintContext(const Constraint *cp)
2425 {
2426  switch (cp->type)
2427  {
2429  return cp->classes;
2430 
2432  return cp->parent.promise->classes;
2433 
2434  default:
2435  ProgrammingError("Constraint had parent element type: %d", cp->type);
2436  return NULL;
2437  }
2438 }
2439 
2440 /**
2441  * @brief Returns the first effective constraint from a list of candidates, depending on evaluation state.
2442  * @param constraints The list of potential candidates
2443  * @return The effective constraint, or NULL if none are found.
2444  */
2445 Constraint *EffectiveConstraint(const EvalContext *ctx, Seq *constraints)
2446 {
2447  for (size_t i = 0; i < SeqLength(constraints); i++)
2448  {
2449  Constraint *cp = SeqAt(constraints, i);
2450 
2451  const char *context = ConstraintContext(cp);
2452  if (IsDefinedClass(ctx, context))
2453  {
2454  return cp;
2455  }
2456  }
2457 
2458  return NULL;
2459 }
2460 
2462 {
2463  if (cp)
2464  {
2465  RvalDestroy(cp->rval);
2466  free(cp->lval);
2467  free(cp->classes);
2468 
2469  free(cp);
2470  }
2471 }
2472 
2473 /*****************************************************************************/
2474 
2475 /**
2476  * @brief Get the trinary boolean value of the first effective constraint found matching, from a promise
2477  * @param lval
2478  * @param list
2479  * @return True/false, or CF_UNDEFINED if not found
2480  */
2481 int PromiseGetConstraintAsBoolean(const EvalContext *ctx, const char *lval, const Promise *pp)
2482 {
2483  int retval = CF_UNDEFINED;
2484 
2485  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
2486  {
2487  Constraint *cp = SeqAt(pp->conlist, i);
2488 
2489  if (strcmp(cp->lval, lval) == 0)
2490  {
2491  if (IsDefinedClass(ctx, cp->classes))
2492  {
2493  if (retval != CF_UNDEFINED)
2494  {
2495  Log(LOG_LEVEL_ERR, "Multiple '%s' (boolean) constraints break this promise", lval);
2497  }
2498  }
2499  else
2500  {
2501  continue;
2502  }
2503 
2504  if (cp->rval.type != RVAL_TYPE_SCALAR)
2505  {
2506  Log(LOG_LEVEL_ERR, "Type mismatch on rhs - expected type %c for boolean constraint '%s'",
2507  cp->rval.type, lval);
2509  FatalError(ctx, "Aborted");
2510  }
2511 
2512  if (strcmp(cp->rval.item, "true") == 0 || strcmp(cp->rval.item, "yes") == 0)
2513  {
2514  retval = true;
2515  continue;
2516  }
2517 
2518  if (strcmp(cp->rval.item, "false") == 0 || strcmp(cp->rval.item, "no") == 0)
2519  {
2520  retval = false;
2521  }
2522  }
2523  }
2524 
2525  if (retval == CF_UNDEFINED)
2526  {
2527  retval = false;
2528  }
2529 
2530  return retval;
2531 }
2532 
2533 /*****************************************************************************/
2534 
2535 /**
2536  * @brief Get the trinary boolean value of the first effective constraint found matching
2537  * @param lval
2538  * @param constraints
2539  * @return True/false, or CF_UNDEFINED if not found
2540  */
2541 int ConstraintsGetAsBoolean(const EvalContext *ctx, const char *lval, const Seq *constraints)
2542 {
2543  int retval = CF_UNDEFINED;
2544 
2545  for (size_t i = 0; i < SeqLength(constraints); i++)
2546  {
2547  Constraint *cp = SeqAt(constraints, i);
2548 
2549  if (strcmp(cp->lval, lval) == 0)
2550  {
2551  if (IsDefinedClass(ctx, cp->classes))
2552  {
2553  if (retval != CF_UNDEFINED)
2554  {
2555  Log(LOG_LEVEL_ERR, "Multiple '%s' (boolean) body constraints break this promise", lval);
2556  }
2557  }
2558  else
2559  {
2560  continue;
2561  }
2562 
2563  if (cp->rval.type != RVAL_TYPE_SCALAR)
2564  {
2565  Log(LOG_LEVEL_ERR, "Type mismatch - expected type %c for boolean constraint '%s'",
2566  cp->rval.type, lval);
2567  FatalError(ctx, "Aborted");
2568  }
2569 
2570  if (strcmp(cp->rval.item, "true") == 0 || strcmp(cp->rval.item, "yes") == 0)
2571  {
2572  retval = true;
2573  continue;
2574  }
2575 
2576  if (strcmp(cp->rval.item, "false") == 0 || strcmp(cp->rval.item, "no") == 0)
2577  {
2578  retval = false;
2579  }
2580  }
2581  }
2582 
2583  if (retval == CF_UNDEFINED)
2584  {
2585  retval = false;
2586  }
2587 
2588  return retval;
2589 }
2590 
2591 /*****************************************************************************/
2592 
2593 bool PromiseBundleOrBodyConstraintExists(const EvalContext *ctx, const char *lval, const Promise *pp)
2594 {
2595  int retval = CF_UNDEFINED;
2596 
2597  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
2598  {
2599  const Constraint *cp = SeqAt(pp->conlist, i);
2600 
2601  if (strcmp(cp->lval, lval) == 0)
2602  {
2603  if (IsDefinedClass(ctx, cp->classes))
2604  {
2605  if (retval != CF_UNDEFINED)
2606  {
2607  Log(LOG_LEVEL_ERR, "Multiple '%s' constraints break this promise", lval);
2609  }
2610  }
2611  else
2612  {
2613  continue;
2614  }
2615 
2616  if (!(cp->rval.type == RVAL_TYPE_FNCALL || cp->rval.type == RVAL_TYPE_SCALAR))
2617  {
2619  "Anomalous type mismatch - type %c for bundle constraint '%s' did not match internals",
2620  cp->rval.type, lval);
2622  FatalError(ctx, "Aborted");
2623  }
2624 
2625  return true;
2626  }
2627  }
2628 
2629  return false;
2630 }
2631 
2632 static bool CheckScalarNotEmptyVarRef(const char *scalar)
2633 {
2634  return (strcmp("$()", scalar) != 0) && (strcmp("${}", scalar) != 0);
2635 }
2636 
2637 static bool PromiseCheck(const Promise *pp, Seq *errors)
2638 {
2639  bool success = true;
2640 
2642  {
2645  success = false;
2646  }
2647 
2648  // check if promise's constraints are valid
2649  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
2650  {
2651  Constraint *constraint = SeqAt(pp->conlist, i);
2652  success &= ConstraintCheckSyntax(constraint, errors);
2653  }
2654 
2656  pp->parent_promise_type->name);
2657 
2658  if (pts->check_promise)
2659  {
2660  success &= pts->check_promise(pp, errors);
2661  }
2662 
2663  return success;
2664 }
2665 
2666 const char *PromiseGetNamespace(const Promise *pp)
2667 {
2668  return pp->parent_promise_type->parent_bundle->ns;
2669 }
2670 
2672 {
2673  return pp->parent_promise_type->parent_bundle;
2674 }
2675 
2677 {
2678  return PromiseGetBundle(pp)->parent_policy;
2679 }
2680 
2681 static void BundlePath(Writer *w, const Bundle *bp)
2682 {
2683  WriterWriteChar(w, '/');
2684  WriterWrite(w, bp->ns);
2685  WriterWriteChar(w, '/');
2686  WriterWrite(w, bp->name);
2687 }
2688 
2689 static void PromiseTypePath(Writer *w, const PromiseType *pt)
2690 {
2691  BundlePath(w, pt->parent_bundle);
2692  WriterWriteChar(w, '/');
2693  WriterWrite(w, pt->name);
2694 }
2695 
2696 /**
2697  * @brief Write a string describing the promise location in policy, e.g. /default/foo/packages/'emacs'
2698  */
2699 void PromisePath(Writer *w, const Promise *pp)
2700 {
2702  WriterWriteChar(w, '/');
2703  WriterWriteChar(w, '\'');
2704  WriterWrite(w, pp->promiser);
2705  WriterWriteChar(w, '\'');
2706 }
2707 
2708 /**
2709  * @brief Return handle of the promise.
2710  * @param pp
2711  * @return Promise handle or NULL if no handle is provided
2712  */
2713 const char *PromiseGetHandle(const Promise *pp)
2714 {
2715  return (const char *)PromiseGetImmediateRvalValue("handle", pp, RVAL_TYPE_SCALAR);
2716 }
2717 
2718 /**
2719  * @brief Get the int value of the first effective constraint found matching, from a promise
2720  * @param lval
2721  * @param pp
2722  * @return Int value, or CF_NOINT
2723  */
2724 int PromiseGetConstraintAsInt(const EvalContext *ctx, const char *lval, const Promise *pp)
2725 {
2726  int retval = CF_NOINT;
2727  const Constraint *cp = PromiseGetConstraint(pp, lval);
2728  if (cp)
2729  {
2730  if (cp->rval.type != RVAL_TYPE_SCALAR)
2731  {
2733  "Anomalous type mismatch - expected type for int constraint %s did not match internals", lval);
2735  FatalError(ctx, "Aborted");
2736  }
2737 
2738  retval = (int) IntFromString((char *) cp->rval.item);
2739  }
2740 
2741  return retval;
2742 }
2743 
2744 /*****************************************************************************/
2745 
2746 /**
2747  * @brief Get the real value of the first effective constraint found matching, from a promise
2748  * @return true if value could be extracted
2749  */
2750 bool PromiseGetConstraintAsReal(const EvalContext *ctx, const char *lval, const Promise *pp, double *value_out)
2751 {
2752  const Constraint *cp = PromiseGetConstraint(pp, lval);
2753  if (cp)
2754  {
2755  if (cp->rval.type != RVAL_TYPE_SCALAR)
2756  {
2758  "Anomalous type mismatch - expected type for int constraint '%s' did not match internals", lval);
2759  FatalError(ctx, "Aborted");
2760  }
2761 
2762  *value_out = DoubleFromString((char *) cp->rval.item, value_out);
2763  return true;
2764  }
2765 
2766  return false;
2767 }
2768 
2769 /*****************************************************************************/
2770 
2771 /**
2772  * @return true if successful
2773  */
2774 static bool Str2Mode(const char *s, mode_t *mode_out)
2775 {
2776  int a = CF_UNDEFINED;
2777 
2778  if (s == NULL)
2779  {
2780  *mode_out = (mode_t)0;
2781  return true;
2782  }
2783 
2784  sscanf(s, "%o", &a);
2785 
2786  if (a == CF_UNDEFINED)
2787  {
2788  return false;
2789  }
2790 
2791  *mode_out = (mode_t)a;
2792  return true;
2793 }
2794 
2795 /**
2796  * @brief Get the octal value of the first effective constraint found matching, from a promise
2797  * @param lval
2798  * @param list
2799  * @return Double value, or 077 if not found
2800  */
2801 mode_t PromiseGetConstraintAsOctal(const EvalContext *ctx, const char *lval, const Promise *pp)
2802 {
2803  mode_t retval = 077;
2804 
2805 // We could handle units here, like kb,b,mb
2806 
2807  const Constraint *cp = PromiseGetConstraint(pp, lval);
2808  if (cp)
2809  {
2810  if (cp->rval.type != RVAL_TYPE_SCALAR)
2811  {
2813  "Anomalous type mismatch - expected type for int constraint %s did not match internals", lval);
2815  FatalError(ctx, "Aborted");
2816  }
2817 
2818  if (!Str2Mode(cp->rval.item, &retval))
2819  {
2820  Log(LOG_LEVEL_ERR, "Error reading assumed octal value '%s'", (const char *)cp->rval.item);
2822  }
2823  }
2824 
2825  return retval;
2826 }
2827 
2828 /*****************************************************************************/
2829 
2830 #ifdef __MINGW32__
2831 
2832 uid_t PromiseGetConstraintAsUid(const EvalContext *ctx, const char *lval, const Promise *pp)
2833 { // we use sids on windows instead
2834  return CF_SAME_OWNER;
2835 }
2836 
2837 #else /* !__MINGW32__ */
2838 
2839 /**
2840  * @brief Get the uid value of the first effective constraint found matching, from a promise
2841  * @param lval
2842  * @param pp
2843  * @return Uid value, or CF_SAME_OWNER if not found
2844  */
2845 uid_t PromiseGetConstraintAsUid(const EvalContext *ctx, const char *lval, const Promise *pp)
2846 {
2847  int retval = CF_SAME_OWNER;
2848  char buffer[CF_MAXVARSIZE];
2849 
2850  const Constraint *cp = PromiseGetConstraint(pp, lval);
2851  if (cp)
2852  {
2853  if (cp->rval.type != RVAL_TYPE_SCALAR)
2854  {
2856  "Anomalous type mismatch - expected type for owner constraint %s did not match internals",
2857  lval);
2859  FatalError(ctx, "Aborted");
2860  }
2861 
2862  retval = Str2Uid((char *) cp->rval.item, buffer, pp);
2863  }
2864 
2865  return retval;
2866 }
2867 
2868 #endif /* !__MINGW32__ */
2869 
2870 /*****************************************************************************/
2871 
2872 #ifdef __MINGW32__
2873 
2874 gid_t PromiseGetConstraintAsGid(const EvalContext *ctx, char *lval, const Promise *pp)
2875 { // not applicable on windows: processes have no group
2876  return CF_SAME_GROUP;
2877 }
2878 
2879 #else /* !__MINGW32__ */
2880 
2881 /**
2882  * @brief Get the uid value of the first effective constraint found matching, from a promise
2883  * @param lval
2884  * @param pp
2885  * @return Gid value, or CF_SAME_GROUP if not found
2886  */
2887 gid_t PromiseGetConstraintAsGid(const EvalContext *ctx, char *lval, const Promise *pp)
2888 {
2889  int retval = CF_SAME_GROUP;
2890  char buffer[CF_MAXVARSIZE];
2891 
2892  const Constraint *cp = PromiseGetConstraint(pp, lval);
2893  if (cp)
2894  {
2895  if (cp->rval.type != RVAL_TYPE_SCALAR)
2896  {
2898  "Anomalous type mismatch - expected type for group constraint '%s' did not match internals",
2899  lval);
2901  FatalError(ctx, "Aborted");
2902  }
2903 
2904  retval = Str2Gid((char *) cp->rval.item, buffer, pp);
2905  }
2906 
2907  return retval;
2908 }
2909 #endif /* !__MINGW32__ */
2910 
2911 /*****************************************************************************/
2912 
2913 /**
2914  * @brief Get the Rlist value of the first effective constraint found matching, from a promise
2915  * @param lval
2916  * @param list
2917  * @return Rlist or NULL if not found (note: same as empty list)
2918  */
2919 // FIX: promise constrained classed?
2920 Rlist *PromiseGetConstraintAsList(const EvalContext *ctx, const char *lval, const Promise *pp)
2921 {
2922  const Constraint *cp = PromiseGetConstraint(pp, lval);
2923  if (cp)
2924  {
2925  if (cp->rval.type != RVAL_TYPE_LIST)
2926  {
2927  Log(LOG_LEVEL_ERR, "Type mismatch on rhs - expected type for list constraint '%s'", lval);
2929  FatalError(ctx, "Aborted");
2930  }
2931 
2932  return RvalRlistValue(cp->rval);
2933  }
2934 
2935  return NULL;
2936 }
2937 
2938 /**
2939  * @brief Get the first effective constraint from the promise, also does some checking
2940  * @param promise
2941  * @param lval
2942  * @return Effective constraint if found, otherwise NULL
2943  */
2944 Constraint *PromiseGetConstraint(const Promise *pp, const char *lval)
2945 {
2946  if (!pp)
2947  {
2948  return NULL;
2949  }
2950 
2951  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
2952  {
2953  Constraint *cp = SeqAt(pp->conlist, i);
2954 
2955  if (strcmp(cp->lval, lval) == 0)
2956  {
2957  return cp;
2958  }
2959  }
2960 
2961  return NULL;
2962 }
2963 
2964 Constraint *PromiseGetConstraintWithType(const Promise *pp, const char *lval, RvalType type)
2965 {
2966  assert(pp);
2967  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
2968  {
2969  Constraint *cp = SeqAt(pp->conlist, i);
2970  if (cp->rval.type != type) {
2971  continue;
2972  }
2973 
2974  if (strcmp(cp->lval, lval) == 0)
2975  {
2976  return cp;
2977  }
2978  }
2979 
2980  return NULL;
2981 }
2982 
2983 /**
2984  * @brief Get the first constraint from the promise
2985  *
2986  * Kill this function with fire once we have separated promise constraints and body constraints.
2987  *
2988  * @param promise
2989  * @param lval
2990  * @return Constraint if found, otherwise NULL
2991  */
2992 Constraint *PromiseGetImmediateConstraint(const Promise *pp, const char *lval)
2993 {
2994  if (pp == NULL)
2995  {
2996  return NULL;
2997  }
2998 
2999  for (size_t i = 0; i < SeqLength(pp->conlist); ++i)
3000  {
3001  Constraint *cp = SeqAt(pp->conlist, i);
3002 
3003  if (strcmp(cp->lval, lval) == 0)
3004  {
3005  /* It would be nice to check whether the constraint we have asked
3006  for is defined in promise (not in referenced body), but there
3007  seem to be no way to do it easily.
3008 
3009  Checking for absence of classes does not work, as constrains
3010  obtain classes defined on promise itself.
3011  */
3012 
3013  return cp;
3014  }
3015  }
3016 
3017  return NULL;
3018 }
3019 
3020 /**
3021  * @brief Get the Rval value of the first constraint that matches the given
3022  * type. Checks that this constraint does not have any contexts attached.
3023  *
3024  * Kill this function with fire once we have separated body constraints and bundle constraints.
3025  *
3026  * @param lval
3027  * @param promise
3028  * @param type
3029  * @return Rval value if found, NULL otherwise
3030  */
3031 void *PromiseGetImmediateRvalValue(const char *lval, const Promise *pp, RvalType rtype)
3032 {
3033  const Constraint *constraint = PromiseGetImmediateConstraint(pp, lval);
3034 
3035  if (constraint && constraint->rval.type == rtype)
3036  {
3037  return constraint->rval.item;
3038  }
3039  else
3040  {
3041  return NULL;
3042  }
3043 }
3044 
3045 /*****************************************************************************/
3046 
3047 /**
3048  * @brief Get the Rval value of the first effective constraint that matches the given type
3049  * @param lval
3050  * @param promise
3051  * @param type
3052  * @return Rval value if found, NULL otherwise
3053  */
3054 void *PromiseGetConstraintAsRval(const Promise *pp, const char *lval, RvalType rtype)
3055 {
3056  const Constraint *constraint = PromiseGetConstraint(pp, lval);
3057 
3058  if (constraint && constraint->rval.type == rtype)
3059  {
3060  return constraint->rval.item;
3061  }
3062  else
3063  {
3064  return NULL;
3065  }
3066 }
3067 
3068 /*****************************************************************************/
3069 
3070 /*
3071  * Check promise constraints while iterating through all slist/containers
3072  * combinations, called from ExpandPromiseAndDo() during PRE-EVAL. This is
3073  * currently running also in cf-promises, but it's enough if such errors are
3074  * detected in the agent run.
3075  *
3076  * TODO remove CommonEvalPromise() actuator, that all it does is call this
3077  * function, and call this one at the beginning of the main actuators, like
3078  * KeepAgentPromise().
3079  */
3081 {
3082  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
3083  {
3084  Constraint *cp = SeqAt(pp->conlist, i);
3087  {
3088  PolicyError *error =
3090  "In attribute '%s', %s",
3091  cp->lval, SyntaxTypeMatchToString(err));
3092  char *error_str = PolicyErrorToString(error);
3093 
3094  Log(LOG_LEVEL_ERR, "%s", error_str);
3095  PolicyErrorDestroy(error);
3096  free(error_str);
3097 
3098  FatalError(ctx, "Cannot continue");
3099  }
3100  }
3101 
3102  /* Check and warn for non-convergence, see commits
3103  4f8c19b84327b8f3c2e269173196282ccedfdad9 and
3104  30c109d22e170a781a647b04b4b0a4a2f7244871. */
3105  if (strcmp(pp->parent_promise_type->name, "insert_lines") == 0)
3106  {
3107  /* TODO without static var, actually remove this check from here
3108  * completely, do it at the end of PRE-EVAL promise iterations
3109  * (ExpandPromiseAndDo() after the main loop). */
3110  static Item *EDIT_ANCHORS = NULL; /* GLOBAL_X */
3111 
3112  const char *sp = PromiseGetConstraintAsRval(pp, "select_line_matching",
3114  if (sp != NULL && !IsExpandable(sp))
3115  {
3116  /* Avoid adding twice the same select_line_matching anchor. */
3117  const char *bun = PromiseGetBundle(pp)->name;
3118  const Item *ptr = ReturnItemInClass(EDIT_ANCHORS, sp, bun);
3119  if (ptr != NULL)
3120  {
3122  "insert_lines promise uses the same select_line_matching anchor '%s' as another promise."
3123  " This will lead to non-convergent behaviour unless 'empty_file_before_editing' is set",
3124  sp);
3126  return;
3127  }
3128 
3129  PrependItem(&EDIT_ANCHORS, sp, bun);
3130  }
3131  }
3132 }
3133 
3134 /*****************************************************************************/
3135 
3137 {
3138  // Check class
3139  for (size_t i = 0; CF_CLASSBODY[i].lval != NULL; i++)
3140  {
3141  if (strcmp(cp->lval, CF_CLASSBODY[i].lval) == 0)
3142  {
3145  {
3146  return err;
3147  }
3148  }
3149  }
3150 
3151  if (cp->type == POLICY_ELEMENT_TYPE_PROMISE)
3152  {
3153  PromiseType *promise_type = cp->parent.promise->parent_promise_type;
3154 
3155  for (size_t i = 0; i < CF3_MODULES; i++)
3156  {
3157  const PromiseTypeSyntax *ssp = CF_ALL_PROMISE_TYPES[i];
3158  if (!ssp)
3159  {
3160  continue;
3161  }
3162 
3163  for (size_t j = 0; ssp[j].bundle_type != NULL; j++)
3164  {
3165  PromiseTypeSyntax ss = ssp[j];
3166 
3167  if (ss.promise_type != NULL)
3168  {
3169  if (strcmp(ss.promise_type, promise_type->name) == 0)
3170  {
3171  const ConstraintSyntax *bs = ss.constraints;
3172 
3173  for (size_t l = 0; bs[l].lval != NULL; l++)
3174  {
3175  // No validation for CF_DATA_TYPE_BUNDLE here
3176  // see: PolicyCheckUndefinedBundles() etc.
3177  if (bs[l].dtype == CF_DATA_TYPE_BODY)
3178  {
3179  const ConstraintSyntax *bs2 = bs[l].range.body_type_syntax->constraints;
3180 
3181  for (size_t m = 0; bs2[m].lval != NULL; m++)
3182  {
3183  if (strcmp(cp->lval, bs2[m].lval) == 0)
3184  {
3185  return CheckConstraintTypeMatch(cp->lval, cp->rval, bs2[m].dtype, bs2[m].range.validation_string, 0);
3186  }
3187  }
3188  }
3189 
3190  if (strcmp(cp->lval, bs[l].lval) == 0)
3191  {
3192  return CheckConstraintTypeMatch(cp->lval, cp->rval, bs[l].dtype, bs[l].range.validation_string, 0);
3193  }
3194  }
3195  }
3196  }
3197  }
3198  }
3199  }
3200 
3201 /* Now check the functional modules - extra level of indirection */
3202 
3203  for (size_t i = 0; CF_COMMON_BODIES[i].lval != NULL; i++)
3204  {
3205  if (CF_COMMON_BODIES[i].dtype == CF_DATA_TYPE_BODY)
3206  {
3207  continue;
3208  }
3209 
3210  if (strcmp(cp->lval, CF_COMMON_BODIES[i].lval) == 0)
3211  {
3213  }
3214  }
3215 
3216  return SYNTAX_TYPE_MATCH_OK;
3217 }
3218 
3219 /**
3220  * @brief Check whether the promise type is allowed one
3221  */
3222 /* FIXME: need to be done automatically */
3223 bool BundleTypeCheck(const char *name)
3224 {
3225  /* FIXME: export size of CF_AGENTTYPES somewhere */
3226  for (int i = 0; strcmp(CF_AGENTTYPES[i], "<notype>") != 0; ++i)
3227  {
3228  if (!strcmp(CF_AGENTTYPES[i], name))
3229  {
3230  return true;
3231  }
3232  }
3233 
3234  if (!strcmp("knowledge", name))
3235  {
3236  return true;
3237  }
3238 
3239  if (!strcmp("edit_line", name))
3240  {
3241  return true;
3242  }
3243 
3244  if (!strcmp("edit_xml", name))
3245  {
3246  return true;
3247  }
3248 
3249  return false;
3250 }
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xvasprintf(char **strp, const char *fmt, va_list ap)
Definition: alloc.c:82
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
const char * BufferData(const Buffer *buffer)
Provides a pointer to the internal data.
Definition: buffer.c:470
Buffer * BufferNewWithCapacity(unsigned int initial_capacity)
Allocates and setup a buffer with a capacity different than the default capacity.
Definition: buffer.c:35
void BufferAppendF(Buffer *buffer, const char *format,...)
Definition: buffer.c:318
void BufferAppendChar(Buffer *buffer, char byte)
Appends a char to an existing buffer.
Definition: buffer.c:299
const ConstraintSyntax CF_COMMON_BODIES[]
Definition: mod_common.c:487
#define CF_NS
Definition: cf3.defs.h:109
#define CF_UNDEFINED
Definition: cf3.defs.h:338
const ConstraintSyntax CF_CLASSBODY[]
Definition: mod_common.c:217
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
const int CF3_MODULES
Definition: mod_common.c:543
#define CF_SAME_OWNER
Definition: cf3.defs.h:62
const PromiseTypeSyntax *const CF_ALL_PROMISE_TYPES[]
Definition: mod_common.c:524
#define CF_SAME_GROUP
Definition: cf3.defs.h:64
DataType
Definition: cf3.defs.h:368
@ CF_DATA_TYPE_CONTEXT_LIST
Definition: cf3.defs.h:380
@ CF_DATA_TYPE_CONTEXT
Definition: cf3.defs.h:379
@ CF_DATA_TYPE_OPTION_LIST
Definition: cf3.defs.h:376
@ CF_DATA_TYPE_BUNDLE
Definition: cf3.defs.h:378
@ CF_DATA_TYPE_REAL
Definition: cf3.defs.h:371
@ CF_DATA_TYPE_STRING_LIST
Definition: cf3.defs.h:372
@ CF_DATA_TYPE_INT_LIST
Definition: cf3.defs.h:373
@ CF_DATA_TYPE_STRING
Definition: cf3.defs.h:369
@ CF_DATA_TYPE_INT
Definition: cf3.defs.h:370
@ CF_DATA_TYPE_BODY
Definition: cf3.defs.h:377
@ CF_DATA_TYPE_OPTION
Definition: cf3.defs.h:375
@ CF_DATA_TYPE_COUNTER
Definition: cf3.defs.h:383
@ CF_DATA_TYPE_INT_RANGE
Definition: cf3.defs.h:381
@ CF_DATA_TYPE_CONTAINER
Definition: cf3.defs.h:384
@ CF_DATA_TYPE_REAL_RANGE
Definition: cf3.defs.h:382
@ CF_DATA_TYPE_REAL_LIST
Definition: cf3.defs.h:374
#define CF_NOINT
Definition: cf3.defs.h:339
const char *const CF_AGENTTYPES[]
Definition: constants.c:65
void free(void *)
uid_t Str2Uid(const char *uidbuff, char *usercopy, const Promise *pp)
Definition: conversion.c:1087
bool DoubleFromString(const char *s, double *value_out)
Definition: conversion.c:521
long IntFromString(const char *s)
Definition: conversion.c:390
gid_t Str2Gid(const char *gidbuff, char *groupcopy, const Promise *pp)
Definition: conversion.c:1175
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_MAXVARSIZE
Definition: definitions.h:36
static bool IsDefinedClass(const EvalContext *ctx, const char *context)
Definition: eval_context.h:213
bool IsExpandable(const char *str)
Definition: expand.c:1117
char * CanonifyName(const char *str)
Definition: files_names.c:483
FnCall * FnCallNew(const char *name, Rlist *args)
Definition: fncall.c:161
#define NULL
Definition: getopt1.c:56
Item * ReturnItemInClass(Item *list, const char *item, const char *classes)
Definition: item_lib.c:188
Item * PrependItem(Item **liststart, const char *itemstring, const char *classes)
Definition: item_lib.c:372
void JsonArrayAppendObject(JsonElement *const array, JsonElement *const object)
Append an object to an array.
Definition: json.c:1327
JsonElement * JsonObjectCreate(const size_t initialCapacity)
Create a new JSON object.
Definition: json.c:880
void JsonObjectAppendInteger(JsonElement *const object, const char *const key, const int value)
Append an integer field to an object.
Definition: json.c:1062
const char * JsonArrayGetAsString(JsonElement *const array, const size_t index)
Get a string value from an array.
Definition: json.c:1359
JsonElement * JsonCopy(const JsonElement *const element)
Definition: json.c:235
JsonElement * JsonArrayGetAsObject(JsonElement *const array, const size_t index)
Get an object value from an array.
Definition: json.c:1378
JsonElement * JsonArrayCreate(const size_t initialCapacity)
Create a new JSON array.
Definition: json.c:1281
const char * JsonObjectGetAsString(const JsonElement *const object, const char *const key)
Get the value of a field in an object, as a string.
Definition: json.c:1204
JsonContainerType JsonGetContainerType(const JsonElement *const container)
Definition: json.c:685
void JsonArrayAppendString(JsonElement *const array, const char *const value)
Append a string to an array.
Definition: json.c:1287
JsonElement * JsonObjectGetAsArray(JsonElement *const object, const char *const key)
Get the value of a field in an object, as an array.
Definition: json.c:1245
void JsonObjectAppendString(JsonElement *const object, const char *const key, const char *const value)
Append a string field to an object.
Definition: json.c:1055
void JsonObjectAppendArray(JsonElement *const object, const char *const key, JsonElement *const array)
Append an array field to an object.
Definition: json.c:1089
size_t JsonLength(const JsonElement *const element)
Get the length of a JsonElement. This is the number of elements or fields in an array or object respe...
Definition: json.c:531
JsonElement * JsonObjectGetAsObject(JsonElement *const object, const char *const key)
Get the value of a field in an object, as an object.
Definition: json.c:1224
void JsonObjectAppendObject(JsonElement *const object, const char *const key, JsonElement *const childObject)
Append an object field to an object.
Definition: json.c:1099
@ JSON_CONTAINER_TYPE_ARRAY
Definition: json.h:59
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_INFO
Definition: logging.h:45
MapIterator MapIteratorInit(Map *map)
Definition: map.c:325
void StringMapSoftDestroy(StringMap *map)
Definition: map.c:359
void StringMapDestroy(StringMap *map)
Definition: map.c:359
Map * MapNew(MapHashFn hash_fn, MapKeyEqualFn equal_fn, MapDestroyDataFn destroy_key_fn, MapDestroyDataFn destroy_value_fn)
Definition: map.c:81
bool StringMapInsert(const StringMap *map, char *key, char *value)
Definition: map.c:359
bool MapInsert(Map *map, void *key, void *value)
Definition: map.c:161
char * StringMapGet(const StringMap *map, const char *key)
Definition: map.c:359
void * MapGet(Map *map, const void *key)
Definition: map.c:213
MapKeyValue * MapIteratorNext(MapIterator *i)
Definition: map.c:343
void MapDestroy(Map *map)
Definition: map.c:270
#define ProgrammingError(...)
Definition: misc_lib.h:33
const ConstraintSyntax CF_COMMON_XMLBODIES[]
Definition: mod_files.c:365
const ConstraintSyntax CF_COMMON_EDITBODIES[]
Definition: mod_files.c:137
static void BundlePath(Writer *w, const Bundle *bp)
Definition: policy.c:2681
const char * PromiseGetNamespace(const Promise *pp)
Definition: policy.c:2666
bool PolicyCheckPartial(const Policy *policy, Seq *errors)
Check a partial policy DOM for errors.
Definition: policy.c:1072
bool BodyHasConstraint(const Body *body, const char *lval)
Definition: policy.c:2405
Constraint * PromiseGetConstraint(const Promise *pp, const char *lval)
Get the first effective constraint from the promise, also does some checking.
Definition: policy.c:2944
const char * ConstraintGetNamespace(const Constraint *cp)
Definition: policy.c:455
static bool RvalTypeCheckDataType(RvalType rval_type, DataType expected_datatype)
Definition: policy.c:507
Policy * PolicyFromJson(JsonElement *json_policy)
Deserialize a policy from JSON.
Definition: policy.c:2351
static bool ConstraintCheckSyntax(const Constraint *constraint, Seq *errors)
Definition: policy.c:550
Constraint * PromiseGetImmediateConstraint(const Promise *pp, const char *lval)
Get the first constraint from the promise.
Definition: policy.c:2992
static Promise * PromiseTypeAppendPromiseJson(PromiseType *promise_type, JsonElement *json_promise, const char *context)
Definition: policy.c:2223
static SyntaxTypeMatch ConstraintCheckType(const Constraint *cp)
Definition: policy.c:3136
bool BundleTypeCheck(const char *name)
Check whether the promise type is allowed one.
Definition: policy.c:3223
JsonElement * PolicyToJson(const Policy *policy)
Serialize a policy as JSON.
Definition: policy.c:1961
static void IndentPrint(Writer *writer, int indent_level)
Definition: policy.c:1996
static unsigned PromiseTypeHash(const PromiseType *pt, unsigned seed)
Definition: policy.c:183
static JsonElement * CreateContextAsJson(const char *name, const char *children_name, JsonElement *children)
Definition: policy.c:1732
const Policy * PolicyFromPromise(const Promise *promise)
Convenience function to get the policy object associated with a promise.
Definition: policy.c:477
static bool PolicyCheckUndefinedBodies(const Policy *policy, Seq *errors)
Definition: policy.c:831
void PolicyDestroy(Policy *policy)
Definition: policy.c:121
static const char * StripNamespace(const char *full_symbol)
Definition: policy.c:282
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
static const char *const POLICY_ERROR_CONSTRAINT_TYPE_MISMATCH
Definition: policy.c:66
const char * PromiseGetHandle(const Promise *pp)
Return handle of the promise.
Definition: policy.c:2713
static SourceOffset PolicyElementSourceOffset(PolicyElementType type, const void *element)
Definition: policy.c:1169
static void AttributeToString(Writer *writer, Constraint *attribute, bool symbolic_reference)
Definition: policy.c:2008
unsigned PolicyHash(const Policy *policy)
Definition: policy.c:219
static const char *const POLICY_ERROR_PROMISE_UNCOMMENTED
Definition: policy.c:58
static const char *const POLICY_ERROR_LVAL_INVALID
Definition: policy.c:63
static const char *const POLICY_ERROR_BUNDLE_REDEFINITION
Definition: policy.c:48
static const char * RvalFullSymbol(const Rval *rval)
Definition: policy.c:780
bool PolicyCheckDuplicateHandles(const Policy *policy, Seq *errors)
Definition: policy.c:990
Seq * BodyGetConstraint(Body *body, const char *lval)
A sequence of constraints matching the l-value.
Definition: policy.c:2389
PolicyError * PolicyErrorNew(PolicyElementType type, const void *subject, const char *error_msg,...)
Definition: policy.c:1144
bool PromiseGetConstraintAsReal(const EvalContext *ctx, const char *lval, const Promise *pp, double *value_out)
Get the real value of the first effective constraint found matching, from a promise.
Definition: policy.c:2750
uid_t PromiseGetConstraintAsUid(const EvalContext *ctx, const char *lval, const Promise *pp)
Get the uid value of the first effective constraint found matching, from a promise.
Definition: policy.c:2845
static Constraint * PromiseAppendConstraintJson(Promise *promise, JsonElement *json_constraint)
Definition: policy.c:2209
static bool PromiseCheck(const Promise *pp, Seq *errors)
Definition: policy.c:2637
static void BodyDestroy(Body *body)
Definition: policy.c:1455
const char * ConstraintContext(const Constraint *cp)
Get the context of the given constraint.
Definition: policy.c:2424
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
static void ArgumentsToString(Writer *writer, Rlist *args)
Definition: policy.c:2022
static Bundle * PolicyAppendBundleJson(Policy *policy, JsonElement *json_bundle)
Definition: policy.c:2263
static const ConstraintSyntax * ConstraintGetSyntax(const Constraint *constraint)
Definition: policy.c:723
static const char *const POLICY_ERROR_BODY_CONTROL_ARGS
Definition: policy.c:56
static bool PolicyCheckPromiseType(const PromiseType *promise_type, Seq *errors)
Definition: policy.c:637
Bundle * PolicyGetBundle(const Policy *policy, const char *ns, const char *type, const char *name)
Query a policy for a bundle.
Definition: policy.c:339
Body * PolicyAppendBody(Policy *policy, const char *ns, const char *name, const char *type, Rlist *args, const char *source_path)
Definition: policy.c:1348
void PromiseTypeDestroy(PromiseType *promise_type)
Definition: policy.c:1315
const Policy * PromiseGetPolicy(const Promise *pp)
Definition: policy.c:2676
Rval DefaultBundleConstraint(const Promise *pp, char *promisetype)
Return a default bundle name for this method/service.
Definition: policy.c:84
mode_t PromiseGetConstraintAsOctal(const EvalContext *ctx, const char *lval, const Promise *pp)
Get the octal value of the first effective constraint found matching, from a promise.
Definition: policy.c:2801
Bundle * PolicyAppendBundle(Policy *policy, const char *ns, const char *name, const char *type, const Rlist *args, const char *source_path)
Definition: policy.c:1326
static Buffer * EscapeQuotes(const char *raw, Buffer *out)
Definition: policy.c:1623
static unsigned ConstraintHash(const Constraint *cp, unsigned seed)
Definition: policy.c:139
static const char *const POLICY_ERROR_BUNDLE_UNDEFINED
Definition: policy.c:50
int PromiseGetConstraintAsBoolean(const EvalContext *ctx, const char *lval, const Promise *pp)
Get the trinary boolean value of the first effective constraint found matching, from a promise.
Definition: policy.c:2481
const Bundle * PromiseGetBundle(const Promise *pp)
Definition: policy.c:2671
JsonElement * BundleToJson(const Bundle *bundle)
Serialize a bundle as JSON.
Definition: policy.c:1872
static void PromiseTypePath(Writer *w, const PromiseType *pt)
Definition: policy.c:2689
PromiseType * BundleAppendPromiseType(Bundle *bundle, const char *name)
Definition: policy.c:1376
static const char *const POLICY_ERROR_EMPTY_VARREF
Definition: policy.c:69
static JsonElement * AttributeValueToJson(Rval rval, bool symbolic_reference)
Definition: policy.c:1650
static const char *const POLICY_ERROR_PROMISE_DUPLICATE_HANDLE
Definition: policy.c:61
static bool PolicyCheckBundle(const Bundle *bundle, Seq *errors)
Definition: policy.c:654
static Constraint * ConstraintNew(const char *lval, Rval rval, const char *classes, bool references_body)
Definition: policy.c:1493
static JsonElement * BodyContextsToJson(const Seq *constraints)
Definition: policy.c:1742
void PolicyErrorWrite(Writer *writer, const PolicyError *error)
Definition: policy.c:1276
void * PromiseGetConstraintAsRval(const Promise *pp, const char *lval, RvalType rtype)
Get the Rval value of the first effective constraint that matches the given type.
Definition: policy.c:3054
static JsonElement * BundleContextsToJson(const Seq *promises)
Definition: policy.c:1777
Constraint * PromiseAppendConstraint(Promise *pp, const char *lval, Rval rval, bool references_body)
Definition: policy.c:1506
static unsigned PromiseHash(const Promise *pp, unsigned seed)
Definition: policy.c:165
void PolicyToString(const Policy *policy, Writer *writer)
Pretty-print a policy.
Definition: policy.c:2141
Constraint * PromiseGetConstraintWithType(const Promise *pp, const char *lval, RvalType type)
Definition: policy.c:2964
void PolicyErrorDestroy(PolicyError *error)
Definition: policy.c:1161
Constraint * BodyAppendConstraint(Body *body, const char *lval, Rval rval, const char *classes, bool references_body)
Definition: policy.c:1576
static const char * PolicyElementSourceFile(PolicyElementType type, const void *element)
Definition: policy.c:1218
static unsigned BundleHash(const Bundle *bundle, unsigned seed)
Definition: policy.c:199
bool PolicyIsRunnable(const Policy *policy)
Check to see if a policy is runnable (contains body common control)
Definition: policy.c:372
void PromiseRecheckAllConstraints(const EvalContext *ctx, const Promise *pp)
Definition: policy.c:3080
Promise * PromiseTypeAppendPromise(PromiseType *type, const char *promiser, Rval promisee, const char *classes, const char *varclasses)
Definition: policy.c:1406
void ConstraintDestroy(Constraint *cp)
Definition: policy.c:2461
Body * PolicyGetBody(const Policy *policy, const char *ns, const char *type, const char *name)
Query a policy for a body.
Definition: policy.c:306
bool PromiseBundleOrBodyConstraintExists(const EvalContext *ctx, const char *lval, const Promise *pp)
Definition: policy.c:2593
Policy * PolicyMerge(Policy *a, Policy *b)
Merge two partial policy objects. The memory for the child objects of the original policies are trans...
Definition: policy.c:385
bool PolicyCheckRunnable(const EvalContext *ctx, const Policy *policy, Seq *errors, bool ignore_missing_bundles)
Check a runnable policy DOM for errors.
Definition: policy.c:1049
static unsigned BodyHash(const Body *body, unsigned seed)
Definition: policy.c:152
Policy * PolicyNew(void)
Definition: policy.c:100
static char * PolicyErrorToString(const PolicyError *error)
Definition: policy.c:1285
static bool PolicyCheckRequiredComments(const EvalContext *ctx, const Policy *policy, Seq *errors)
Definition: policy.c:935
char * QualifiedNameScopeComponent(const char *qualified_name)
Definition: policy.c:818
static const char *const POLICY_ERROR_BODY_REDEFINITION
Definition: policy.c:52
static bool CheckScalarNotEmptyVarRef(const char *scalar)
Definition: policy.c:2632
void PromisePath(Writer *w, const Promise *pp)
Write a string describing the promise location in policy, e.g. /default/foo/packages/'emacs'.
Definition: policy.c:2699
static Body * PolicyAppendBodyJson(Policy *policy, JsonElement *json_body)
Definition: policy.c:2307
static bool Str2Mode(const char *s, mode_t *mode_out)
Definition: policy.c:2774
void BodyToString(Writer *writer, Body *body)
Definition: policy.c:2040
const char * PolicyGetPolicyFileHash(const Policy *policy, const char *policy_file_path)
Definition: policy.c:275
const PromiseType * BundleGetPromiseType(const Bundle *bp, const char *name)
Definition: policy.c:1600
static const char *const POLICY_ERROR_BODY_UNDEFINED
Definition: policy.c:54
JsonElement * BodyToJson(const Body *body)
Serialize a body as JSON.
Definition: policy.c:1925
static bool PolicyCheckUndefinedBundles(const Policy *policy, Seq *errors)
Definition: policy.c:876
StringSet * PolicySourceFiles(const Policy *policy)
Definition: policy.c:240
static bool PolicyCheckBody(const Body *body, Seq *errors)
Definition: policy.c:680
static Constraint * BodyAppendConstraintJson(Body *body, JsonElement *json_constraint, const char *context)
Definition: policy.c:2293
char * QualifiedNameNamespaceComponent(const char *qualified_name)
Definition: policy.c:800
gid_t PromiseGetConstraintAsGid(const EvalContext *ctx, char *lval, const Promise *pp)
Get the uid value of the first effective constraint found matching, from a promise.
Definition: policy.c:2887
void BundleToString(Writer *writer, Bundle *bundle)
Definition: policy.c:2076
const char * NamespaceDefault(void)
Definition: policy.c:93
char * BundleQualifiedName(const Bundle *bundle)
Definition: policy.c:490
static Rval RvalFromJson(JsonElement *json_rval)
Definition: policy.c:2161
int ConstraintsGetAsBoolean(const EvalContext *ctx, const char *lval, const Seq *constraints)
Get the trinary boolean value of the first effective constraint found matching.
Definition: policy.c:2541
static void BundleDestroy(Bundle *bundle)
Definition: policy.c:1440
void * PromiseGetImmediateRvalValue(const char *lval, const Promise *pp, RvalType rtype)
Get the Rval value of the first constraint that matches the given type. Checks that this constraint d...
Definition: policy.c:3031
int PolicyCompare(const void *a, const void *b)
Definition: policy.c:114
static const char *const POLICY_ERROR_BUNDLE_NAME_RESERVED
Definition: policy.c:46
static PromiseType * BundleAppendPromiseTypeJson(Bundle *bundle, JsonElement *json_promise_type)
Definition: policy.c:2239
void PromiseDestroy(Promise *pp)
Definition: policy.c:1471
Constraint * EffectiveConstraint(const EvalContext *ctx, Seq *constraints)
Returns the first effective constraint from a list of candidates, depending on evaluation state.
Definition: policy.c:2445
PolicyElementType
Definition: policy.h:36
@ POLICY_ELEMENT_TYPE_BODY
Definition: policy.h:39
@ POLICY_ELEMENT_TYPE_BUNDLE
Definition: policy.h:38
@ POLICY_ELEMENT_TYPE_CONSTRAINT
Definition: policy.h:42
@ POLICY_ELEMENT_TYPE_PROMISE
Definition: policy.h:41
@ POLICY_ELEMENT_TYPE_PROMISE_TYPE
Definition: policy.h:40
@ POLICY_ELEMENT_TYPE_POLICY
Definition: policy.h:37
void PromiseRef(LogLevel level, const Promise *pp)
Definition: promises.c:769
void RvalWriteQuoted(Writer *writer, Rval rval)
Definition: rlist.c:1391
Rlist * RlistAppendRval(Rlist **start, Rval rval)
Definition: rlist.c:321
JsonElement * RvalContainerValue(Rval rval)
Definition: rlist.c:165
char * RlistScalarValue(const Rlist *rlist)
Definition: rlist.c:83
Rlist * RvalRlistValue(Rval rval)
Definition: rlist.c:153
void RvalWrite(Writer *writer, Rval rval)
Definition: rlist.c:1386
char * RvalScalarValue(Rval rval)
Definition: rlist.c:129
unsigned RvalHash(Rval rval, unsigned seed)
Definition: rlist.c:1410
Rlist * RlistAppend(Rlist **start, const void *item, RvalType type)
Definition: rlist.c:560
char * RvalToString(Rval rval)
Definition: rlist.c:1396
void RlistDestroy(Rlist *rl)
Definition: rlist.c:501
void RvalDestroy(Rval rval)
Definition: rlist.c:940
Rval RvalNew(const void *item, RvalType type)
Definition: rlist.c:464
Rlist * RlistAppendScalar(Rlist **start, const char *scalar)
Definition: rlist.c:545
unsigned int RlistHash(const Rlist *list, unsigned seed)
Definition: rlist.c:1428
int RlistLen(const Rlist *start)
Definition: rlist.c:672
void ScalarWrite(Writer *writer, const char *s, bool quote)
Definition: rlist.c:1335
Rlist * RlistCopy(const Rlist *rp)
Definition: rlist.c:494
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 SeqSet(Seq *seq, size_t index, void *item)
Definition: sequence.c:93
void SeqSoftDestroy(Seq *seq)
Destroy an existing Sequence without destroying its items.
Definition: sequence.c:72
void SeqDestroy(Seq *seq)
Destroy an existing Sequence.
Definition: sequence.c:60
void SeqAppendSeq(Seq *seq, const Seq *items)
Append a sequence to this sequence. Only copies pointers.
Definition: sequence.c:130
void SeqAppend(Seq *seq, void *item)
Append a new item to the Sequence.
Definition: sequence.c:104
static void * SeqAt(const Seq *seq, int i)
Definition: sequence.h:57
StringSet * StringSetNew(void)
Definition: set.c:34
void StringSetAdd(const StringSet *set, char *element)
Definition: set.c:34
char * SafeStringDuplicate(const char *str)
Definition: string_lib.c:172
bool IsStrIn(const char *str, const char *const strs[])
Definition: string_lib.c:782
bool StringEqual_untyped(const void *a, const void *b)
Definition: string_lib.c:306
unsigned int StringHash_untyped(const void *str, unsigned int seed)
Definition: string_lib.c:114
unsigned int StringHash(const char *str, unsigned int seed)
Definition: string_lib.c:90
char * StringConcatenate(size_t count, const char *first,...)
Definition: string_lib.c:348
const ConstraintSyntax * constraints
Definition: cf3.defs.h:670
BodyCheckFn check_body
Definition: cf3.defs.h:671
Definition: policy.h:85
char * type
Definition: policy.h:88
SourceOffset offset
Definition: policy.h:96
char * source_path
Definition: policy.h:95
char * ns
Definition: policy.h:90
Seq * conlist
Definition: policy.h:93
Policy * parent_policy
Definition: policy.h:86
Rlist * args
Definition: policy.h:91
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
SourceOffset offset
Definition: policy.h:81
Seq * promise_types
Definition: policy.h:78
char * ns
Definition: policy.h:75
char * source_path
Definition: policy.h:80
Policy * parent_policy
Definition: policy.h:71
Rlist * args
Definition: policy.h:76
const char * lval
Definition: cf3.defs.h:656
const char * validation_string
Definition: cf3.defs.h:660
const BodySyntax * body_type_syntax
Definition: cf3.defs.h:661
const DataType dtype
Definition: cf3.defs.h:657
union ConstraintSyntax_::@11 range
Body * body
Definition: policy.h:129
Rval rval
Definition: policy.h:133
SourceOffset offset
Definition: policy.h:138
Promise * promise
Definition: policy.h:128
char * classes
Definition: policy.h:135
char * lval
Definition: policy.h:132
bool references_body
Definition: policy.h:136
union Constraint_::@22 parent
PolicyElementType type
Definition: policy.h:126
Definition: fncall.h:31
char * name
Definition: fncall.h:32
Rlist * args
Definition: fncall.h:33
Definition: item_lib.h:33
void * key
Definition: map_common.h:35
void * value
Definition: map_common.h:36
Definition: map.c:46
char * message
Definition: policy.h:49
const void * subject
Definition: policy.h:48
PolicyElementType type
Definition: policy.h:47
Definition: policy.h:53
Seq * bundles
Definition: policy.h:56
char * release_id
Definition: policy.h:54
StringMap * policy_files_hashes
Definition: policy.h:58
Seq * bodies
Definition: policy.h:57
const PromiseCheckFn check_promise
Definition: cf3.defs.h:680
const char * bundle_type
Definition: cf3.defs.h:677
const ConstraintSyntax * constraints
Definition: cf3.defs.h:679
const char * promise_type
Definition: cf3.defs.h:678
Seq * promises
Definition: policy.h:104
SourceOffset offset
Definition: policy.h:106
Bundle * parent_bundle
Definition: policy.h:101
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 * comment
Definition: policy.h:114
char * promiser
Definition: policy.h:115
char * classes
Definition: policy.h:113
Rval promisee
Definition: policy.h:116
SourceOffset offset
Definition: policy.h:121
Definition: rlist.h:35
Rval val
Definition: rlist.h:36
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
Definition: map.h:212
Map * impl
Definition: map.h:212
Definition: set.h:138
Definition: writer.c:45
const BodySyntax * BodySyntaxGet(const char *body_type)
Definition: syntax.c:149
const PromiseTypeSyntax * PromiseTypeSyntaxGet(const char *bundle_type, const char *promise_type)
Definition: syntax.c:75
const char * SyntaxTypeMatchToString(SyntaxTypeMatch result)
Definition: syntax.c:262
SyntaxTypeMatch CheckConstraintTypeMatch(const char *lval, Rval rval, DataType dt, const char *range, int level)
Definition: syntax.c:300
SyntaxTypeMatch
Definition: syntax.h:41
@ SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED
Definition: syntax.h:44
@ SYNTAX_TYPE_MATCH_OK
Definition: syntax.h:42
bool IsCf3VarString(const char *str)
Definition: vars.c:123
size_t WriterWrite(Writer *writer, const char *str)
Definition: writer.c:193
char * StringWriterClose(Writer *writer)
Definition: writer.c:262
size_t WriterWriteChar(Writer *writer, char c)
Definition: writer.c:200
size_t WriterWriteF(Writer *writer, const char *fmt,...)
Definition: writer.c:144
Writer * StringWriter(void)
Definition: writer.c:67