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)  

generic_agent.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 
26 #include <generic_agent.h>
27 
28 #include <bootstrap.h>
29 #include <policy_server.h>
30 #include <sysinfo.h>
31 #include <known_dirs.h>
32 #include <eval_context.h>
33 #include <policy.h>
34 #include <promises.h>
35 #include <files_lib.h>
36 #include <files_names.h>
37 #include <files_interfaces.h>
38 #include <hash.h>
39 #include <parser.h>
40 #include <dbm_api.h>
41 #include <crypto.h>
42 #include <vars.h>
43 #include <syntax.h>
44 #include <conversion.h>
45 #include <expand.h>
46 #include <locks.h>
47 #include <scope.h>
48 #include <cleanup.h>
49 #include <unix.h>
50 #include <client_code.h>
51 #include <string_lib.h>
52 #include <regex.h> // pcre
53 #include <writer.h>
54 #include <exec_tools.h>
55 #include <list.h>
56 #include <misc_lib.h>
57 #include <fncall.h>
58 #include <rlist.h>
59 #include <syslog_client.h>
60 #include <audit.h>
61 #include <verify_classes.h>
62 #include <verify_vars.h>
63 #include <timeout.h>
64 #include <time_classes.h>
65 #include <constants.h>
66 #include <ornaments.h>
67 #include <cf-windows-functions.h>
68 #include <loading.h>
69 #include <signals.h>
70 #include <addr_lib.h>
71 #include <openssl/evp.h>
72 #include <libcrypto-compat.h>
73 #include <libgen.h>
74 #include <cleanup.h>
75 
76 static pthread_once_t pid_cleanup_once = PTHREAD_ONCE_INIT; /* GLOBAL_T */
77 
78 static char PIDFILE[CF_BUFSIZE] = ""; /* GLOBAL_C */
79 
80 /* Used for 'ident' argument to openlog() */
81 static char CF_PROGRAM_NAME[256] = "";
82 
83 static void CheckWorkingDirectories(EvalContext *ctx);
84 
85 static void GetAutotagDir(char *dirname, size_t max_size, const char *maybe_dirname);
86 static void GetPromisesValidatedFile(char *filename, size_t max_size, const GenericAgentConfig *config, const char *maybe_dirname);
87 static bool WriteReleaseIdFile(const char *filename, const char *dirname);
88 static bool GeneratePolicyReleaseIDFromGit(char *release_id_out, size_t out_size,
89  const char *policy_dir);
90 static bool GeneratePolicyReleaseID(char *release_id_out, size_t out_size,
91  const char *policy_dir);
92 static char* ReadReleaseIdFromReleaseIdFileMasterfiles(const char *maybe_dirname);
93 
94 static bool MissingInputFile(const char *input_file);
95 
96 static bool LoadAugmentsFiles(EvalContext *ctx, const char* filename);
97 
98 #if !defined(__MINGW32__)
99 static void OpenLog(int facility);
100 #endif
101 
102 static JsonElement *ReadJsonFile(const char *filename, LogLevel log_level)
103 {
104  struct stat sb;
105  if (stat(filename, &sb) == -1)
106  {
107  Log(log_level, "Could not open JSON file %s", filename);
108  return NULL;
109  }
110 
111  JsonElement *doc = NULL;
112  // 5 MB should be enough for most reasonable def.json data
113  JsonParseError err = JsonParseFile(filename, 5 * 1024 * 1024, &doc);
114 
115  if (err != JSON_PARSE_OK ||
116  doc == NULL)
117  {
118  Log(log_level, "Could not parse JSON file %s: %s", filename, JsonParseErrorToString(err));
119  }
120 
121  return doc;
122 }
123 
124 /*****************************************************************************/
125 
126 static void SanitizeEnvironment()
127 {
128  /* ps(1) and other utilities invoked by CFEngine may be affected */
129  unsetenv("COLUMNS");
130 
131  /* Make sure subprocesses output is not localized */
132  unsetenv("LANG");
133  unsetenv("LANGUAGE");
134  unsetenv("LC_MESSAGES");
135 }
136 
137 /*****************************************************************************/
138 
140 {
141  *digest = HASH_METHOD_MD5;
142  *digest_len = CF_MD5_LEN;
143 }
144 
146 {
147  EvalContextClassPutHard(ctx, "am_policy_hub",
148  "source=bootstrap,deprecated,alias=policy_server");
149  Log(LOG_LEVEL_VERBOSE, "Additional class defined: am_policy_hub");
150  EvalContextClassPutHard(ctx, "policy_server",
151  "inventory,attribute_name=CFEngine roles,source=bootstrap");
152  Log(LOG_LEVEL_VERBOSE, "Additional class defined: policy_server");
153 }
154 
155 Policy *SelectAndLoadPolicy(GenericAgentConfig *config, EvalContext *ctx, bool validate_policy, bool write_validated_file)
156 {
157  Policy *policy = NULL;
158 
159  if (GenericAgentCheckPolicy(config, validate_policy, write_validated_file))
160  {
161  policy = LoadPolicy(ctx, config);
162  }
163  else if (config->tty_interactive)
164  {
166  "Failsafe condition triggered. Interactive session detected, skipping failsafe.cf execution.");
167  }
168  else
169  {
170  Log(LOG_LEVEL_ERR, "CFEngine was not able to get confirmation of promises from cf-promises, so going to failsafe");
171  EvalContextClassPutHard(ctx, "failsafe_fallback", "report,attribute_name=Errors,source=agent");
172 
173  if (CheckAndGenerateFailsafe(GetInputDir(), "failsafe.cf"))
174  {
175  GenericAgentConfigSetInputFile(config, GetInputDir(), "failsafe.cf");
176  Log(LOG_LEVEL_ERR, "CFEngine failsafe.cf: %s %s", config->input_dir, config->input_file);
177  policy = LoadPolicy(ctx, config);
178 
179  /* Doing failsafe, set the release_id to "failsafe" and also
180  * overwrite the cfe_release_id file so that sub-agent executed as
181  * part of failsafe can just pick it up and then rewrite it with the
182  * actual value from masterfiles. */
183  free(policy->release_id);
184  policy->release_id = xstrdup("failsafe");
185 
186  char filename[PATH_MAX];
187  GetReleaseIdFile(GetInputDir(), filename, sizeof(filename));
188  FILE *release_id_stream = safe_fopen_create_perms(filename, "w",
190  if (release_id_stream == NULL)
191  {
192  Log(LOG_LEVEL_ERR, "Failed to open the release_id file for writing during failsafe");
193  }
194  else
195  {
196  Writer *release_id_writer = FileWriter(release_id_stream);
197  WriterWrite(release_id_writer, "{ releaseId: \"failsafe\" }\n");
198  WriterClose(release_id_writer);
199  }
200  }
201  }
202  return policy;
203 }
204 
205 static bool CheckContextClassmatch(EvalContext *ctx, const char *class_str)
206 {
207  if (StringEndsWith(class_str, "::")) // Treat as class expression, not regex
208  {
209  const size_t length = strlen(class_str);
210  if (length <= 2)
211  {
212  assert(length == 2); // True because StringEndsWith
214  "Invalid class expression in augments: '%s'",
215  class_str);
216  return false;
217  }
218 
219  char *const tmp_class_str = xstrdup(class_str);
220  assert(strlen(tmp_class_str) == length);
221 
222  tmp_class_str[length - 2] = '\0'; // 2 = strlen("::")
223  const bool found = IsDefinedClass(ctx, tmp_class_str);
224 
225  free(tmp_class_str);
226  return found;
227  }
228 
230  StringSet *global_matches = ClassesMatching(ctx, iter, class_str, NULL, true); // returns early
231 
232  const bool found = (StringSetSize(global_matches) > 0);
233 
234  StringSetDestroy(global_matches);
236 
237  return found;
238 }
239 
240 static bool LoadAugmentsData(EvalContext *ctx, const char *filename, const JsonElement* augment)
241 {
242  bool loaded = false;
243 
246  {
247  Log(LOG_LEVEL_ERR, "Invalid augments file contents in '%s', must be a JSON object", filename);
248  }
249  else
250  {
251  loaded = true;
252  Log(LOG_LEVEL_VERBOSE, "Loaded augments file '%s', installing contents", filename);
253 
254  JsonIterator iter = JsonIteratorInit(augment);
255  const char *key;
256  while ((key = JsonIteratorNextKey(&iter)))
257  {
258  if (!(StringEqual(key, "vars") ||
259  StringEqual(key, "classes") ||
260  StringEqual(key, "inputs") ||
261  StringEqual(key, "augments")))
262  {
263  Log(LOG_LEVEL_VERBOSE, "Unknown augments key '%s' in file '%s', skipping it",
264  key, filename);
265  }
266  }
267 
268  /* load variables (if any) */
269  JsonElement *element = JsonObjectGet(augment, "vars");
270  if (element != NULL)
271  {
272  JsonElement* vars = JsonExpandElement(ctx, element);
273 
274  if (vars == NULL ||
277  {
278  Log(LOG_LEVEL_ERR, "Invalid augments vars in '%s', must be a JSON object", filename);
279  goto vars_cleanup;
280  }
281 
282  JsonIterator iter = JsonIteratorInit(vars);
283  const char *vkey;
284  while ((vkey = JsonIteratorNextKey(&iter)))
285  {
286  JsonElement *data = JsonObjectGet(vars, vkey);
288  {
289  char *value = JsonPrimitiveToString(data);
290  Log(LOG_LEVEL_VERBOSE, "Installing augments variable '%s.%s=%s' from file '%s'",
291  SpecialScopeToString(SPECIAL_SCOPE_DEF), vkey, value, filename);
292  EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_DEF, vkey, value, CF_DATA_TYPE_STRING, "source=augments_file");
293  free(value);
294  }
298  {
299  // map to slist if the data only has primitives
300  Log(LOG_LEVEL_VERBOSE, "Installing augments slist variable '%s.%s' from file '%s'",
301  SpecialScopeToString(SPECIAL_SCOPE_DEF), vkey, filename);
302 
303  Rlist *data_as_rlist = RlistFromContainer(data);
305  vkey, data_as_rlist,
307  "source=augments_file");
308  RlistDestroy(data_as_rlist);
309  }
310  else // install as a data container
311  {
312  Log(LOG_LEVEL_VERBOSE, "Installing augments data container variable '%s.%s' from file '%s'",
313  SpecialScopeToString(SPECIAL_SCOPE_DEF), vkey, filename);
315  vkey, data,
317  "source=augments_file");
318  }
319  }
320 
321  vars_cleanup:
322  JsonDestroy(vars);
323  }
324 
325  /* load classes (if any) */
326  element = JsonObjectGet(augment, "classes");
327  if (element != NULL)
328  {
329  JsonElement* classes = JsonExpandElement(ctx, element);
330 
333  {
334  Log(LOG_LEVEL_ERR, "Invalid augments classes in '%s', must be a JSON object", filename);
335  goto classes_cleanup;
336  }
337 
338  const char tags[] = "source=augments_file";
339  JsonIterator iter = JsonIteratorInit(classes);
340  const char *ckey;
341  while ((ckey = JsonIteratorNextKey(&iter)))
342  {
343  JsonElement *data = JsonObjectGet(classes, ckey);
345  {
346  char *check = JsonPrimitiveToString(data);
347  // check if class is true
348  if (CheckContextClassmatch(ctx, check))
349  {
350  Log(LOG_LEVEL_VERBOSE, "Installing augments class '%s' (checked '%s') from file '%s'",
351  ckey, check, filename);
352  EvalContextClassPutHard(ctx, ckey, tags);
353  }
354  free(check);
355  }
359  {
360  // check if each class is true
361  JsonIterator iter = JsonIteratorInit(data);
362  const JsonElement *el;
363  while ((el = JsonIteratorNextValueByType(&iter, JSON_ELEMENT_TYPE_PRIMITIVE, true)))
364  {
365  char *check = JsonPrimitiveToString(el);
366  if (CheckContextClassmatch(ctx, check))
367  {
368  Log(LOG_LEVEL_VERBOSE, "Installing augments class '%s' (checked array entry '%s') from file '%s'",
369  ckey, check, filename);
370  EvalContextClassPutHard(ctx, ckey, tags);
371  free(check);
372  break;
373  }
374 
375  free(check);
376  }
377  }
378  else
379  {
380  Log(LOG_LEVEL_ERR, "Invalid augments class data for class '%s' in '%s', must be a JSON object",
381  ckey, filename);
382  }
383  }
384 
385  classes_cleanup:
386  JsonDestroy(classes);
387  }
388 
389  /* load inputs (if any) */
390  element = JsonObjectGet(augment, "inputs");
391  if (element != NULL)
392  {
393  JsonElement* inputs = JsonExpandElement(ctx, element);
394 
398  {
399  Log(LOG_LEVEL_VERBOSE, "Installing augments def.augments_inputs from file '%s'",
400  filename);
401  Rlist *rlist = RlistFromContainer(inputs);
403  "augments_inputs", rlist,
405  "source=augments_file");
406  RlistDestroy(rlist);
407  }
408  else
409  {
410  Log(LOG_LEVEL_ERR, "Trying to augment inputs in '%s' but the value was not a list of strings",
411  filename);
412  }
413 
414  JsonDestroy(inputs);
415  }
416 
417  /* load further def.json files (if any) */
418  element = JsonObjectGet(augment, "augments");
419  if (element != NULL)
420  {
421  JsonElement* further_augments = element;
422  assert(further_augments != NULL);
423 
424  if (JsonGetElementType(further_augments) == JSON_ELEMENT_TYPE_CONTAINER &&
425  JsonGetContainerType(further_augments) == JSON_CONTAINER_TYPE_ARRAY &&
426  JsonArrayContainsOnlyPrimitives(further_augments))
427  {
428  JsonIterator iter = JsonIteratorInit(further_augments);
429  const JsonElement *el;
430  while ((el = JsonIteratorNextValueByType(&iter, JSON_ELEMENT_TYPE_PRIMITIVE, true)) != NULL)
431  {
432  char *nested_filename = JsonPrimitiveToString(el);
433  bool further_loaded = LoadAugmentsFiles(ctx, nested_filename);
434  if (further_loaded)
435  {
436  Log(LOG_LEVEL_VERBOSE, "Completed augmenting from file '%s'", nested_filename);
437  }
438  else
439  {
440  Log(LOG_LEVEL_ERR, "Could not load requested further augments from file '%s'", nested_filename);
441  }
442  free(nested_filename);
443  }
444  }
445  else
446  {
447  Log(LOG_LEVEL_ERR, "Trying to augment inputs in '%s' but the value was not a list of strings",
448  filename);
449  }
450  }
451  }
452 
453  return loaded;
454 }
455 
456 static bool LoadAugmentsFiles(EvalContext *ctx, const char *unexpanded_filename)
457 {
458  bool loaded = false;
459 
460  char *filename = ExpandScalar(ctx, NULL, "this", unexpanded_filename, NULL);
461 
462  if (strstr(filename, "/.json"))
463  {
465  "Skipping augments file '%s' because it failed to expand the base filename, resulting in '%s'",
466  filename, filename);
467  }
468  else
469  {
470  Log(LOG_LEVEL_DEBUG, "Searching for augments file '%s' (original '%s')", filename, filename);
471  if (FileCanOpen(filename, "r"))
472  {
473  JsonElement* augment = ReadJsonFile(filename, LOG_LEVEL_ERR);
474  if (augment != NULL)
475  {
476  loaded = LoadAugmentsData(ctx, filename, augment);
477  JsonDestroy(augment);
478  }
479  }
480  else
481  {
482  Log(LOG_LEVEL_VERBOSE, "could not load JSON augments from '%s'", filename);
483  }
484  }
485 
486  free(filename);
487  return loaded;
488 }
489 
491 {
492  char* def_json = StringFormat("%s%c%s", config->input_dir, FILE_SEPARATOR, "def.json");
493  Log(LOG_LEVEL_VERBOSE, "Loading JSON augments from '%s' (input dir '%s', input file '%s'", def_json, config->input_dir, config->input_file);
494  LoadAugmentsFiles(ctx, def_json);
495  free(def_json);
496 }
497 
498 static void AddPolicyEntryVariables (EvalContext *ctx, const GenericAgentConfig *config)
499 {
500  char *abs_input_path = GetAbsolutePath(config->input_file);
501  /* both dirname() and basename() may actually modify the string they are given (see man:basename(3)) */
502  char *dirname_path = xstrdup(abs_input_path);
503  char *basename_path = xstrdup(abs_input_path);
504  EvalContextSetEntryPoint(ctx, abs_input_path);
506  "policy_entry_filename",
507  abs_input_path,
508  CF_DATA_TYPE_STRING, "source=agent");
510  "policy_entry_dirname",
511  dirname(dirname_path),
512  CF_DATA_TYPE_STRING, "source=agent");
514  "policy_entry_basename",
515  basename(basename_path),
516  CF_DATA_TYPE_STRING, "source=agent");
517  free(abs_input_path);
518  free(dirname_path);
519  free(basename_path);
520 }
521 
523  const char *program_name)
524 {
525  strcpy(VPREFIX, "");
526  if (program_name != NULL)
527  {
528  strncpy(CF_PROGRAM_NAME, program_name, sizeof(CF_PROGRAM_NAME));
529  }
530 
531  Log(LOG_LEVEL_VERBOSE, " %s", NameVersion());
532  Banner("Initialization preamble");
533 
535  GenericAgentInitialize(ctx, config);
536 
537  time_t t = SetReferenceTime();
538  UpdateTimeClasses(ctx, t);
540 
541  THIS_AGENT_TYPE = config->agent_type;
544  "cfe_internal,source=agent");
545 
546  DetectEnvironment(ctx);
547  AddPolicyEntryVariables(ctx, config);
548 
550  LoadSystemConstants(ctx);
551 
552  const char *bootstrap_arg =
554  const char *bootstrap_ip =
556 
557  /* Are we bootstrapping the agent? */
558  if (config->agent_type == AGENT_TYPE_AGENT && bootstrap_arg != NULL)
559  {
560  EvalContextClassPutHard(ctx, "bootstrap_mode", "report,source=environment");
561 
563  {
564  EvalContextClassPutHard(ctx, "skip_policy_on_bootstrap", "report,source=environment");
565  }
566 
568  {
570  "Error removing existing input files prior to bootstrap");
571  DoCleanupAndExit(EXIT_FAILURE);
572  }
573 
575  {
577  "Error writing builtin failsafe to inputs prior to bootstrap");
578  DoCleanupAndExit(EXIT_FAILURE);
579  }
580  GenericAgentConfigSetInputFile(config, GetInputDir(), "failsafe.cf");
581 
582  char canonified_ipaddr[strlen(bootstrap_ip) + 1];
583  StringCanonify(canonified_ipaddr, bootstrap_ip);
584 
585  bool am_policy_server =
586  EvalContextClassGet(ctx, NULL, canonified_ipaddr) != NULL;
587 
588  if (am_policy_server)
589  {
590  Log(LOG_LEVEL_INFO, "Assuming role as policy server,"
591  " with policy distribution point at: %s", GetMasterDir());
592  MarkAsPolicyServer(ctx);
593 
595  {
596  Log(LOG_LEVEL_ERR, "In order to bootstrap as a policy server,"
597  " the file '%s/promises.cf' must exist.", GetMasterDir());
598  DoCleanupAndExit(EXIT_FAILURE);
599  }
600 
602  }
603  else
604  {
605  Log(LOG_LEVEL_INFO, "Assuming role as regular client,"
606  " bootstrapping to policy server: %s", bootstrap_arg);
607 
609  {
610  EvalContextClassPutHard(ctx, "trust_server", "source=agent");
612  "Bootstrap mode: implicitly trusting server, "
613  "use --trust-server=no if server trust is already established");
614  }
615  }
616 
617  WriteAmPolicyHubFile(am_policy_server);
618 
619  PolicyServerWriteFile(GetWorkDir(), bootstrap_arg);
620  EvalContextSetPolicyServer(ctx, bootstrap_arg);
621  char *const bootstrap_id = CreateBootstrapIDFile(GetWorkDir());
622  if (bootstrap_id != NULL)
623  {
624  EvalContextSetBootstrapID(ctx, bootstrap_id);
625  free(bootstrap_id);
626  }
627 
628  /* FIXME: Why it is called here? Can't we move both invocations to before if? */
630  }
631  else
632  {
633  char *existing_policy_server = PolicyServerReadFile(GetWorkDir());
634  if (existing_policy_server)
635  {
636  Log(LOG_LEVEL_VERBOSE, "This agent is bootstrapped to: %s",
637  existing_policy_server);
638  EvalContextSetPolicyServer(ctx, existing_policy_server);
639  char *const bootstrap_id = ReadBootstrapIDFile(GetWorkDir());
640  if (bootstrap_id != NULL)
641  {
642  EvalContextSetBootstrapID(ctx, bootstrap_id);
643  free(bootstrap_id);
644  }
645  free(existing_policy_server);
647  if (GetAmPolicyHub())
648  {
649  MarkAsPolicyServer(ctx);
650 
651  /* Should this go in MarkAsPolicyServer() ? */
653  }
654  }
655  else
656  {
657  Log(LOG_LEVEL_VERBOSE, "This agent is not bootstrapped -"
658  " can't find policy_server.dat in: %s", GetWorkDir());
659  }
660  }
661 
662  /* load augments here so that they can make use of the classes added above
663  * (especially 'am_policy_hub' and 'policy_server') */
664  LoadAugments(ctx, config);
665 }
666 
667 static bool IsPolicyPrecheckNeeded(GenericAgentConfig *config, bool force_validation)
668 {
669  bool check_policy = false;
670 
672  {
673  check_policy = true;
674  Log(LOG_LEVEL_VERBOSE, "Input file is outside default repository, validating it");
675  }
677  {
678  check_policy = true;
679  Log(LOG_LEVEL_VERBOSE, "Input file is changed since last validation, validating it");
680  }
681  if (force_validation)
682  {
683  check_policy = true;
684  Log(LOG_LEVEL_VERBOSE, "always_validate is set, forcing policy validation");
685  }
686 
687  return check_policy;
688 }
689 
690 bool GenericAgentCheckPolicy(GenericAgentConfig *config, bool force_validation, bool write_validated_file)
691 {
692  if (!MissingInputFile(config->input_file))
693  {
694  {
695  if (config->agent_type == AGENT_TYPE_SERVER ||
696  config->agent_type == AGENT_TYPE_MONITOR ||
697  config->agent_type == AGENT_TYPE_EXECUTOR)
698  {
699  time_t validated_at = ReadTimestampFromPolicyValidatedFile(config, NULL);
700  config->agent_specific.daemon.last_validated_at = validated_at;
701  }
702  }
703 
704  if (IsPolicyPrecheckNeeded(config, force_validation))
705  {
706  bool policy_check_ok = GenericAgentArePromisesValid(config);
707  if (policy_check_ok && write_validated_file)
708  {
710  NULL, // use GetAutotagDir
711  write_validated_file, // true
712  GetAmPolicyHub()); // write release ID?
713  }
714 
715  if (config->agent_specific.agent.bootstrap_argument && !policy_check_ok)
716  {
717  Log(LOG_LEVEL_VERBOSE, "Policy is not valid, but proceeding with bootstrap");
718  return true;
719  }
720 
721  return policy_check_ok;
722  }
723  else
724  {
725  Log(LOG_LEVEL_VERBOSE, "Policy is already validated");
726  return true;
727  }
728  }
729  return false;
730 }
731 
732 static JsonElement *ReadPolicyValidatedFile(const char *filename)
733 {
734  bool missing = true;
735  struct stat sb;
736  if (stat(filename, &sb) != -1)
737  {
738  missing = false;
739  }
740 
741  JsonElement *validated_doc = ReadJsonFile(filename, LOG_LEVEL_DEBUG);
742  if (validated_doc == NULL)
743  {
744  Log(missing ? LOG_LEVEL_DEBUG : LOG_LEVEL_VERBOSE, "Could not parse policy_validated JSON file '%s', using dummy data", filename);
745  validated_doc = JsonObjectCreate(2);
746  if (missing)
747  {
748  JsonObjectAppendInteger(validated_doc, "timestamp", 0);
749  }
750  else
751  {
752  JsonObjectAppendInteger(validated_doc, "timestamp", sb.st_mtime);
753  }
754  }
755 
756  return validated_doc;
757 }
758 
759 static JsonElement *ReadPolicyValidatedFileFromMasterfiles(const GenericAgentConfig *config, const char *maybe_dirname)
760 {
761  char filename[CF_MAXVARSIZE];
762 
763  GetPromisesValidatedFile(filename, sizeof(filename), config, maybe_dirname);
764 
765  return ReadPolicyValidatedFile(filename);
766 }
767 
768 /**
769  * @brief Writes a file with a contained timestamp to mark a policy file as validated
770  * @param filename the filename
771  * @return True if successful.
772  */
773 static bool WritePolicyValidatedFile(ARG_UNUSED const GenericAgentConfig *config, const char *filename)
774 {
775  if (!MakeParentDirectory(filename, true))
776  {
778  "Could not write policy validated marker file: %s", filename);
779  return false;
780  }
781 
782  int fd = creat(filename, CF_PERMS_DEFAULT);
783  if (fd == -1)
784  {
785  Log(LOG_LEVEL_ERR, "While writing policy validated marker file '%s', could not create file (create: %s)", filename, GetErrorStr());
786  return false;
787  }
788 
789  JsonElement *info = JsonObjectCreate(3);
790  JsonObjectAppendInteger(info, "timestamp", time(NULL));
791 
792  Writer *w = FileWriter(fdopen(fd, "w"));
793  JsonWrite(w, info, 0);
794 
795  WriterClose(w);
796  JsonDestroy(info);
797 
798  Log(LOG_LEVEL_VERBOSE, "Saved policy validated marker file '%s'", filename);
799  return true;
800 }
801 
802 /**
803  * @brief Writes the policy validation file and release ID to a directory
804  * @return True if successful.
805  */
806 bool GenericAgentTagReleaseDirectory(const GenericAgentConfig *config, const char *dirname, bool write_validated, bool write_release)
807 {
808  char local_dirname[PATH_MAX + 1];
809  if (dirname == NULL)
810  {
811  GetAutotagDir(local_dirname, PATH_MAX, NULL);
812  dirname = local_dirname;
813  }
814 
815  char filename[CF_MAXVARSIZE];
816  char git_checksum[GENERIC_AGENT_CHECKSUM_SIZE];
817  bool have_git_checksum = GeneratePolicyReleaseIDFromGit(git_checksum, sizeof(git_checksum), dirname);
818 
819  Log(LOG_LEVEL_DEBUG, "Tagging directory %s for release (write_validated: %s, write_release: %s)",
820  dirname,
821  write_validated ? "yes" : "no",
822  write_release ? "yes" : "no");
823 
824  if (write_release)
825  {
826  // first, tag the release ID
827  GetReleaseIdFile(dirname, filename, sizeof(filename));
828  char *id = ReadReleaseIdFromReleaseIdFileMasterfiles(dirname);
829  if (id == NULL
830  || (have_git_checksum &&
831  strcmp(id, git_checksum) != 0))
832  {
833  if (id == NULL)
834  {
835  Log(LOG_LEVEL_DEBUG, "The release_id of %s was missing", dirname);
836  }
837  else
838  {
839  Log(LOG_LEVEL_DEBUG, "The release_id of %s needs to be updated", dirname);
840  }
841 
842  bool wrote_release = WriteReleaseIdFile(filename, dirname);
843  if (!wrote_release)
844  {
845  Log(LOG_LEVEL_VERBOSE, "The release_id file %s was NOT updated", filename);
846  free(id);
847  return false;
848  }
849  else
850  {
851  Log(LOG_LEVEL_DEBUG, "The release_id file %s was updated", filename);
852  }
853  }
854 
855  free(id);
856  }
857 
858  // now, tag the promises_validated
859  if (write_validated)
860  {
861  Log(LOG_LEVEL_DEBUG, "Tagging directory %s for validation", dirname);
862 
863  GetPromisesValidatedFile(filename, sizeof(filename), config, dirname);
864 
865  bool wrote_validated = WritePolicyValidatedFile(config, filename);
866 
867  if (!wrote_validated)
868  {
869  Log(LOG_LEVEL_VERBOSE, "The promises_validated file %s was NOT updated", filename);
870  return false;
871  }
872 
873  Log(LOG_LEVEL_DEBUG, "The promises_validated file %s was updated", filename);
874  return true;
875  }
876 
877  return true;
878 }
879 
880 /**
881  * @brief Writes a file with a contained release ID based on git SHA,
882  * or file checksum if git SHA is not available.
883  * @param filename the release_id file
884  * @param dirname the directory to checksum or get the Git hash
885  * @return True if successful
886  */
887 static bool WriteReleaseIdFile(const char *filename, const char *dirname)
888 {
889  char release_id[GENERIC_AGENT_CHECKSUM_SIZE];
890 
891  bool have_release_id =
892  GeneratePolicyReleaseID(release_id, sizeof(release_id), dirname);
893 
894  if (!have_release_id)
895  {
896  return false;
897  }
898 
899  int fd = creat(filename, CF_PERMS_DEFAULT);
900  if (fd == -1)
901  {
902  Log(LOG_LEVEL_ERR, "While writing policy release ID file '%s', could not create file (create: %s)", filename, GetErrorStr());
903  return false;
904  }
905 
906  JsonElement *info = JsonObjectCreate(3);
907  JsonObjectAppendString(info, "releaseId", release_id);
908 
909  Writer *w = FileWriter(fdopen(fd, "w"));
910  JsonWrite(w, info, 0);
911 
912  WriterClose(w);
913  JsonDestroy(info);
914 
915  Log(LOG_LEVEL_VERBOSE, "Saved policy release ID file '%s'", filename);
916  return true;
917 }
918 
920 {
921  char cmd[CF_BUFSIZE];
922  const char* const bindir = GetBinDir();
923 
924  Log(LOG_LEVEL_VERBOSE, "Verifying the syntax of the inputs...");
925  {
926  char cfpromises[CF_MAXVARSIZE];
927 
928  snprintf(cfpromises, sizeof(cfpromises), "%s%ccf-promises%s",
929  bindir, FILE_SEPARATOR, EXEC_SUFFIX);
930 
931  struct stat sb;
932  if (stat(cfpromises, &sb) == -1)
933  {
935  "cf-promises%s needs to be installed in %s for pre-validation of full configuration",
936  EXEC_SUFFIX, bindir);
937 
938  return false;
939  }
940 
941  if (config->bundlesequence)
942  {
943  snprintf(cmd, sizeof(cmd), "\"%s\" \"", cfpromises);
944  }
945  else
946  {
947  snprintf(cmd, sizeof(cmd), "\"%s\" -c \"", cfpromises);
948  }
949  }
950 
951  strlcat(cmd, config->input_file, CF_BUFSIZE);
952 
953  strlcat(cmd, "\"", CF_BUFSIZE);
954 
955  if (config->bundlesequence)
956  {
957  strlcat(cmd, " -b \"", CF_BUFSIZE);
958  for (const Rlist *rp = config->bundlesequence; rp; rp = rp->next)
959  {
960  const char *bundle_ref = RlistScalarValue(rp);
961  strlcat(cmd, bundle_ref, CF_BUFSIZE);
962 
963  if (rp->next)
964  {
965  strlcat(cmd, ",", CF_BUFSIZE);
966  }
967  }
968  strlcat(cmd, "\"", CF_BUFSIZE);
969  }
970 
971  Log(LOG_LEVEL_VERBOSE, "Checking policy with command '%s'", cmd);
972 
973  if (!ShellCommandReturnsZero(cmd, true))
974  {
975  Log(LOG_LEVEL_ERR, "Policy failed validation with command '%s'", cmd);
976  return false;
977  }
978 
979  return true;
980 }
981 
982 
983 
984 
985 /*****************************************************************************/
986 
987 #if !defined(__MINGW32__)
988 static void OpenLog(int facility)
989 {
990  openlog(CF_PROGRAM_NAME, LOG_PID | LOG_NOWAIT | LOG_ODELAY, facility);
991 }
992 #endif
993 
994 /*****************************************************************************/
995 
996 #if !defined(__MINGW32__)
997 void CloseLog(void)
998 {
999  closelog();
1000 }
1001 #endif
1002 
1004 {
1005  EvalContextClassPutHard(ctx, "community_edition", "inventory,attribute_name=none,source=agent");
1006 }
1007 
1009 {
1010  int force = false;
1011  struct stat statbuf, sb;
1012  char vbuff[CF_BUFSIZE];
1013  char ebuff[CF_EXPANDSIZE];
1014 
1015 #ifdef __MINGW32__
1016  InitializeWindows();
1017 #endif
1018 
1019  /* Set output to line-buffered to avoid truncated debug logs. */
1020 
1021  /* Bug on HP-UX: Buffered output is discarded if you switch buffering mode
1022  without flushing the buffered output first. This will happen anyway when
1023  switching modes, so no performance is lost. */
1024  fflush(stdout);
1025 
1026 #ifndef SUNOS_5
1027  setlinebuf(stdout);
1028 #else
1029  /* CFE-2527: On Solaris we avoid calling setlinebuf, since fprintf() on
1030  Solaris 10 and 11 truncates output under certain conditions. We fully
1031  disable buffering to avoid truncated debug logs; performance impact
1032  should be minimal because we mostly write full lines anyway. */
1033  setvbuf(stdout, NULL, _IONBF, 0);
1034 #endif
1035 
1037 
1038  EvalContextClassPutHard(ctx, "any", "source=agent");
1039 
1041 
1042 /* Define trusted directories */
1043 
1044  const char *workdir = GetWorkDir();
1045  const char *bindir = GetBinDir();
1046 
1047  if (!workdir)
1048  {
1049  FatalError(ctx, "Error determining working directory");
1050  }
1051 
1052  OpenLog(LOG_USER);
1053  SetSyslogFacility(LOG_USER);
1054 
1055  Log(LOG_LEVEL_VERBOSE, "Work directory is %s", workdir);
1056 
1057  snprintf(vbuff, CF_BUFSIZE, "%s%cupdate.conf", GetInputDir(), FILE_SEPARATOR);
1058  MakeParentDirectory(vbuff, force);
1059  snprintf(vbuff, CF_BUFSIZE, "%s%ccf-agent", bindir, FILE_SEPARATOR);
1060  MakeParentDirectory(vbuff, force);
1061  snprintf(vbuff, CF_BUFSIZE, "%s%coutputs%cspooled_reports", workdir, FILE_SEPARATOR, FILE_SEPARATOR);
1062  MakeParentDirectory(vbuff, force);
1063  snprintf(vbuff, CF_BUFSIZE, "%s%clastseen%cintermittencies", workdir, FILE_SEPARATOR, FILE_SEPARATOR);
1064  MakeParentDirectory(vbuff, force);
1065  snprintf(vbuff, CF_BUFSIZE, "%s%creports%cvarious", workdir, FILE_SEPARATOR, FILE_SEPARATOR);
1066  MakeParentDirectory(vbuff, force);
1067 
1068  snprintf(vbuff, CF_BUFSIZE, "%s%c.", GetLogDir(), FILE_SEPARATOR);
1069  MakeParentDirectory(vbuff, force);
1070  snprintf(vbuff, CF_BUFSIZE, "%s%c.", GetPidDir(), FILE_SEPARATOR);
1071  MakeParentDirectory(vbuff, force);
1072  snprintf(vbuff, CF_BUFSIZE, "%s%c.", GetStateDir(), FILE_SEPARATOR);
1073  MakeParentDirectory(vbuff, force);
1074 
1075  MakeParentDirectory(GetLogDir(), force);
1076 
1077  snprintf(vbuff, CF_BUFSIZE, "%s", GetInputDir());
1078 
1079  if (stat(vbuff, &sb) == -1)
1080  {
1081  FatalError(ctx, " No access to WORKSPACE/inputs dir");
1082  }
1083 
1084  /* ensure WORKSPACE/inputs directory has all user bits set (u+rwx) */
1085  if ((sb.st_mode & 0700) != 0700)
1086  {
1087  chmod(vbuff, sb.st_mode | 0700);
1088  }
1089 
1090  snprintf(vbuff, CF_BUFSIZE, "%s%coutputs", workdir, FILE_SEPARATOR);
1091 
1092  if (stat(vbuff, &sb) == -1)
1093  {
1094  FatalError(ctx, " No access to WORKSPACE/outputs dir");
1095  }
1096 
1097  /* ensure WORKSPACE/outputs directory has all user bits set (u+rwx) */
1098  if ((sb.st_mode & 0700) != 0700)
1099  {
1100  chmod(vbuff, sb.st_mode | 0700);
1101  }
1102 
1103  const char* const statedir = GetStateDir();
1104 
1105  snprintf(ebuff, sizeof(ebuff), "%s%ccf_procs",
1106  statedir, FILE_SEPARATOR);
1107  MakeParentDirectory(ebuff, force);
1108 
1109  if (stat(ebuff, &statbuf) == -1)
1110  {
1111  CreateEmptyFile(ebuff);
1112  }
1113 
1114  snprintf(ebuff, sizeof(ebuff), "%s%ccf_rootprocs",
1115  statedir, FILE_SEPARATOR);
1116 
1117  if (stat(ebuff, &statbuf) == -1)
1118  {
1119  CreateEmptyFile(ebuff);
1120  }
1121 
1122  snprintf(ebuff, sizeof(ebuff), "%s%ccf_otherprocs",
1123  statedir, FILE_SEPARATOR);
1124 
1125  if (stat(ebuff, &statbuf) == -1)
1126  {
1127  CreateEmptyFile(ebuff);
1128  }
1129 
1130  snprintf(ebuff, sizeof(ebuff), "%s%cprevious_state%c",
1131  statedir, FILE_SEPARATOR, FILE_SEPARATOR);
1132  MakeParentDirectory(ebuff, force);
1133 
1134  snprintf(ebuff, sizeof(ebuff), "%s%cdiff%c",
1135  statedir, FILE_SEPARATOR, FILE_SEPARATOR);
1136  MakeParentDirectory(ebuff, force);
1137 
1138  snprintf(ebuff, sizeof(ebuff), "%s%cuntracked%c",
1139  statedir, FILE_SEPARATOR, FILE_SEPARATOR);
1140  MakeParentDirectory(ebuff, force);
1141 
1142  OpenNetwork();
1143  CryptoInitialize();
1144 
1146 
1147  /* Initialize keys and networking. cf-key, doesn't need keys. In fact it
1148  must function properly even without them, so that it generates them! */
1149  if (config->agent_type != AGENT_TYPE_KEYGEN)
1150  {
1152  char *ipaddr = NULL, *port = NULL;
1153  PolicyServerLookUpFile(workdir, &ipaddr, &port);
1154  PolicyHubUpdateKeys(ipaddr);
1155  free(ipaddr);
1156  free(port);
1157  }
1158 
1159  size_t cwd_size = PATH_MAX;
1160  while (true)
1161  {
1162  char cwd[cwd_size];
1163  if (!getcwd(cwd, cwd_size))
1164  {
1165  if (errno == ERANGE)
1166  {
1167  cwd_size *= 2;
1168  continue;
1169  }
1170  else
1171  {
1173  "Could not determine current directory (getcwd: %s)",
1174  GetErrorStr());
1175  break;
1176  }
1177  }
1178 
1180  break;
1181  }
1182 
1183  if (!MINUSF)
1184  {
1185  GenericAgentConfigSetInputFile(config, GetInputDir(), "promises.cf");
1186  }
1187 }
1188 
1190 {
1191  /* TODO, FIXME: what else from the above do we need to undo here ? */
1192  if (config->agent_type != AGENT_TYPE_KEYGEN)
1193  {
1194  cfnet_shut();
1195  }
1197  GenericAgentConfigDestroy(config);
1198  EvalContextDestroy(ctx);
1199 }
1200 
1201 static bool MissingInputFile(const char *input_file)
1202 {
1203  struct stat sb;
1204 
1205  if (stat(input_file, &sb) == -1)
1206  {
1207  Log(LOG_LEVEL_ERR, "There is no readable input file at '%s'. (stat: %s)", input_file, GetErrorStr());
1208  return true;
1209  }
1210 
1211  return false;
1212 }
1213 
1214 // Git only.
1215 static bool GeneratePolicyReleaseIDFromGit(char *release_id_out,
1216 #ifdef NDEBUG /* out_size is only used in an assertion */
1217  ARG_UNUSED
1218 #endif
1219  size_t out_size,
1220  const char *policy_dir)
1221 {
1222  char git_filename[PATH_MAX + 1];
1223  snprintf(git_filename, PATH_MAX, "%s/.git/HEAD", policy_dir);
1224  MapName(git_filename);
1225 
1226  // Note: Probably we should not be reading all of these filenames directly,
1227  // and should instead use git plumbing commands to retrieve the data.
1228  FILE *git_file = safe_fopen(git_filename, "r");
1229  if (git_file)
1230  {
1231  char git_head[128];
1232  int scanned = fscanf(git_file, "ref: %127s", git_head);
1233 
1234  if (scanned == 1)
1235  // Found HEAD Reference which means we are on a checked out branch
1236  {
1237  fclose(git_file);
1238  snprintf(git_filename, PATH_MAX, "%s/.git/%s",
1239  policy_dir, git_head);
1240  git_file = safe_fopen(git_filename, "r");
1241  Log(LOG_LEVEL_DEBUG, "Found a git HEAD ref");
1242  }
1243  else
1244  {
1246  "Unable to find HEAD ref in '%s', looking for commit instead",
1247  git_filename);
1248  assert(out_size > 40);
1249  fseek(git_file, 0, SEEK_SET);
1250  scanned = fscanf(git_file, "%40s", release_id_out);
1251  fclose(git_file);
1252 
1253  if (scanned == 1)
1254  {
1256  "Found current git checkout pointing to: %s",
1257  release_id_out);
1258  return true;
1259  }
1260  else
1261  {
1262  /* We didn't find a commit sha in .git/HEAD, so we assume the
1263  * git information is invalid. */
1264  git_file = NULL;
1265  }
1266  }
1267  if (git_file)
1268  {
1269  assert(out_size > 40);
1270  scanned = fscanf(git_file, "%40s", release_id_out);
1271  fclose(git_file);
1272  return scanned == 1;
1273  }
1274  else
1275  {
1276  Log(LOG_LEVEL_DEBUG, "While generating policy release ID, found git head ref '%s', but unable to open (errno: %s)",
1277  policy_dir, GetErrorStr());
1278  }
1279  }
1280  else
1281  {
1282  Log(LOG_LEVEL_DEBUG, "While generating policy release ID, directory is '%s' not a git repository",
1283  policy_dir);
1284  }
1285 
1286  return false;
1287 }
1288 
1289 static bool GeneratePolicyReleaseIDFromTree(char *release_id_out, size_t out_size,
1290  const char *policy_dir)
1291 {
1292  if (access(policy_dir, R_OK) != 0)
1293  {
1294  Log(LOG_LEVEL_ERR, "Cannot access policy directory '%s' to generate release ID", policy_dir);
1295  return false;
1296  }
1297 
1298  // fallback, produce some pseudo sha1 hash
1299  const EVP_MD *const md = HashDigestFromId(GENERIC_AGENT_CHECKSUM_METHOD);
1300  if (md == NULL)
1301  {
1303  "Could not determine function for file hashing");
1304  return false;
1305  }
1306 
1307  EVP_MD_CTX *crypto_ctx = EVP_MD_CTX_new();
1308  if (crypto_ctx == NULL)
1309  {
1310  Log(LOG_LEVEL_ERR, "Could not allocate openssl hash context");
1311  return false;
1312  }
1313 
1314  EVP_DigestInit(crypto_ctx, md);
1315 
1316  bool success = HashDirectoryTree(policy_dir,
1317  (const char *[]) { ".cf", ".dat", ".txt", ".conf", ".mustache", ".json", ".yaml", NULL},
1318  crypto_ctx);
1319 
1320  int md_len;
1321  unsigned char digest[EVP_MAX_MD_SIZE + 1] = { 0 };
1322  EVP_DigestFinal(crypto_ctx, digest, &md_len);
1323  EVP_MD_CTX_free(crypto_ctx);
1324 
1325  HashPrintSafe(release_id_out, out_size, digest,
1327  return success;
1328 }
1329 
1330 static bool GeneratePolicyReleaseID(char *release_id_out, size_t out_size,
1331  const char *policy_dir)
1332 {
1333  if (GeneratePolicyReleaseIDFromGit(release_id_out, out_size, policy_dir))
1334  {
1335  return true;
1336  }
1337 
1338  return GeneratePolicyReleaseIDFromTree(release_id_out, out_size,
1339  policy_dir);
1340 }
1341 
1342 /**
1343  * @brief Gets the promises_validated file name depending on context and options
1344  */
1345 static void GetPromisesValidatedFile(char *filename, size_t max_size, const GenericAgentConfig *config, const char *maybe_dirname)
1346 {
1347  char dirname[max_size];
1348 
1349  /* TODO overflow error checking! */
1350  GetAutotagDir(dirname, max_size, maybe_dirname);
1351 
1352  if (maybe_dirname == NULL && MINUSF)
1353  {
1354  snprintf(filename, max_size, "%s/validated_%s", dirname, CanonifyName(config->original_input_file));
1355  }
1356  else
1357  {
1358  snprintf(filename, max_size, "%s/cf_promises_validated", dirname);
1359  }
1360 
1361  MapName(filename);
1362 }
1363 
1364  /**
1365  * @brief Gets the promises_validated file name depending on context and options
1366  */
1367 static void GetAutotagDir(char *dirname, size_t max_size, const char *maybe_dirname)
1368 {
1369  if (maybe_dirname != NULL)
1370  {
1371  strlcpy(dirname, maybe_dirname, max_size);
1372  }
1373  else if (MINUSF)
1374  {
1375  strlcpy(dirname, GetStateDir(), max_size);
1376  }
1377  else
1378  {
1379  strlcpy(dirname, GetMasterDir(), max_size);
1380  }
1381 
1382  MapName(dirname);
1383 }
1384 
1385 /**
1386  * @brief Gets the release_id file name in the given base_path.
1387  */
1388 void GetReleaseIdFile(const char *base_path, char *filename, size_t max_size)
1389 {
1390  snprintf(filename, max_size, "%s/cf_promises_release_id", base_path);
1391  MapName(filename);
1392 }
1393 
1394 static JsonElement *ReadReleaseIdFileFromMasterfiles(const char *maybe_dirname)
1395 {
1396  char filename[CF_MAXVARSIZE];
1397 
1398  GetReleaseIdFile((maybe_dirname == NULL) ? GetMasterDir() : maybe_dirname,
1399  filename, sizeof(filename));
1400 
1401  JsonElement *doc = ReadJsonFile(filename, LOG_LEVEL_DEBUG);
1402  if (doc == NULL)
1403  {
1404  Log(LOG_LEVEL_VERBOSE, "Could not parse release_id JSON file %s", filename);
1405  }
1406 
1407  return doc;
1408 }
1409 
1410 static char* ReadReleaseIdFromReleaseIdFileMasterfiles(const char *maybe_dirname)
1411 {
1412  JsonElement *doc = ReadReleaseIdFileFromMasterfiles(maybe_dirname);
1413  char *id = NULL;
1414  if (doc)
1415  {
1416  JsonElement *jid = JsonObjectGet(doc, "releaseId");
1417  if (jid)
1418  {
1419  id = xstrdup(JsonPrimitiveGetAsString(jid));
1420  }
1421  JsonDestroy(doc);
1422  }
1423 
1424  return id;
1425 }
1426 
1427 // TODO: refactor Read*FromPolicyValidatedMasterfiles
1428 time_t ReadTimestampFromPolicyValidatedFile(const GenericAgentConfig *config, const char *maybe_dirname)
1429 {
1430  time_t validated_at = 0;
1431  {
1432  JsonElement *validated_doc = ReadPolicyValidatedFileFromMasterfiles(config, maybe_dirname);
1433  if (validated_doc)
1434  {
1435  JsonElement *timestamp = JsonObjectGet(validated_doc, "timestamp");
1436  if (timestamp)
1437  {
1438  validated_at = JsonPrimitiveGetAsInteger(timestamp);
1439  }
1440  JsonDestroy(validated_doc);
1441  }
1442  }
1443 
1444  return validated_at;
1445 }
1446 
1447 // TODO: refactor Read*FromPolicyValidatedMasterfiles
1448 char* ReadChecksumFromPolicyValidatedMasterfiles(const GenericAgentConfig *config, const char *maybe_dirname)
1449 {
1450  char *checksum_str = NULL;
1451 
1452  {
1453  JsonElement *validated_doc = ReadPolicyValidatedFileFromMasterfiles(config, maybe_dirname);
1454  if (validated_doc)
1455  {
1456  JsonElement *checksum = JsonObjectGet(validated_doc, "checksum");
1457  if (checksum )
1458  {
1459  checksum_str = xstrdup(JsonPrimitiveGetAsString(checksum));
1460  }
1461  JsonDestroy(validated_doc);
1462  }
1463  }
1464 
1465  return checksum_str;
1466 }
1467 
1468 /**
1469  * @NOTE Updates the config->agent_specific.daemon.last_validated_at timestamp
1470  * used by serverd, execd etc daemons when checking for new policies.
1471  */
1473 {
1474  time_t validated_at = ReadTimestampFromPolicyValidatedFile(config, NULL);
1475  time_t now = time(NULL);
1476 
1477  if (validated_at > now)
1478  {
1480  "Clock seems to have jumped back in time, mtime of %jd is newer than current time %jd, touching it",
1481  (intmax_t) validated_at, (intmax_t) now);
1482 
1484  NULL, // use GetAutotagDir
1485  true, // write validated
1486  false); // write release ID
1487  return true;
1488  }
1489 
1490  {
1491  struct stat sb;
1492  if (stat(config->input_file, &sb) == -1)
1493  {
1494  Log(LOG_LEVEL_VERBOSE, "There is no readable input file at '%s'. (stat: %s)", config->input_file, GetErrorStr());
1495  return true;
1496  }
1497  else if (sb.st_mtime > validated_at)
1498  {
1499  Log(LOG_LEVEL_VERBOSE, "Input file '%s' has changed since the last policy read attempt (file is newer than previous)", config->input_file);
1500  return true;
1501  }
1502  }
1503 
1504  // Check the directories first for speed and because non-input/data files should trigger an update
1505  {
1506  if (IsNewerFileTree( (char *)GetInputDir(), validated_at))
1507  {
1508  Log(LOG_LEVEL_VERBOSE, "Quick search detected file changes");
1509  return true;
1510  }
1511  }
1512 
1513  {
1514  char filename[MAX_FILENAME];
1515  snprintf(filename, MAX_FILENAME, "%s/policy_server.dat", GetWorkDir());
1516  MapName(filename);
1517 
1518  struct stat sb;
1519  if ((stat(filename, &sb) != -1) && (sb.st_mtime > validated_at))
1520  {
1521  return true;
1522  }
1523  }
1524 
1525  return false;
1526 }
1527 
1528 /*******************************************************************/
1529 
1531 {
1532  for (size_t i = 0; i < SeqLength(policy->bodies); i++)
1533  {
1534  const Body *body = SeqAt(policy->bodies, i);
1535 
1536  if (strcmp(body->type, CF_AGENTTYPES[agent]) == 0)
1537  {
1538  if (strcmp(body->name, "control") == 0)
1539  {
1540  return body->conlist;
1541  }
1542  }
1543  }
1544 
1545  return NULL;
1546 }
1547 
1548 /*******************************************************************/
1549 
1550 static int ParseFacility(const char *name)
1551 {
1552  if (strcmp(name, "LOG_USER") == 0)
1553  {
1554  return LOG_USER;
1555  }
1556  if (strcmp(name, "LOG_DAEMON") == 0)
1557  {
1558  return LOG_DAEMON;
1559  }
1560  if (strcmp(name, "LOG_LOCAL0") == 0)
1561  {
1562  return LOG_LOCAL0;
1563  }
1564  if (strcmp(name, "LOG_LOCAL1") == 0)
1565  {
1566  return LOG_LOCAL1;
1567  }
1568  if (strcmp(name, "LOG_LOCAL2") == 0)
1569  {
1570  return LOG_LOCAL2;
1571  }
1572  if (strcmp(name, "LOG_LOCAL3") == 0)
1573  {
1574  return LOG_LOCAL3;
1575  }
1576  if (strcmp(name, "LOG_LOCAL4") == 0)
1577  {
1578  return LOG_LOCAL4;
1579  }
1580  if (strcmp(name, "LOG_LOCAL5") == 0)
1581  {
1582  return LOG_LOCAL5;
1583  }
1584  if (strcmp(name, "LOG_LOCAL6") == 0)
1585  {
1586  return LOG_LOCAL6;
1587  }
1588  if (strcmp(name, "LOG_LOCAL7") == 0)
1589  {
1590  return LOG_LOCAL7;
1591  }
1592  return -1;
1593 }
1594 
1595 void SetFacility(const char *retval)
1596 {
1597  Log(LOG_LEVEL_VERBOSE, "SET Syslog FACILITY = %s", retval);
1598 
1599  CloseLog();
1600  OpenLog(ParseFacility(retval));
1602 }
1603 
1605 /* NOTE: We do not care about permissions (ACLs) in windows */
1606 {
1607  struct stat statbuf;
1608  char vbuff[CF_BUFSIZE];
1609 
1610  const char* const workdir = GetWorkDir();
1611  const char* const statedir = GetStateDir();
1612 
1613  if (uname(&VSYSNAME) == -1)
1614  {
1615  Log(LOG_LEVEL_ERR, "Couldn't get kernel name info. (uname: %s)", GetErrorStr());
1616  memset(&VSYSNAME, 0, sizeof(VSYSNAME));
1617  }
1618 
1619  snprintf(vbuff, CF_BUFSIZE, "%s%c.", workdir, FILE_SEPARATOR);
1620  MakeParentDirectory(vbuff, false);
1621 
1622  /* check that GetWorkDir() exists */
1623  if (stat(GetWorkDir(), &statbuf) == -1)
1624  {
1625  FatalError(ctx,"Unable to stat working directory '%s'! (stat: %s)\n",
1626  GetWorkDir(), GetErrorStr());
1627  }
1628 
1629  Log(LOG_LEVEL_VERBOSE, "Making sure that internal directories are private...");
1630 
1631  Log(LOG_LEVEL_VERBOSE, "Checking integrity of the trusted workdir");
1632 
1633  /* fix any improper uid/gid ownership on workdir */
1634  if (statbuf.st_uid != getuid() || statbuf.st_gid != getgid())
1635  {
1636  if (chown(workdir, getuid(), getgid()) == -1)
1637  {
1638  const char* error_reason = GetErrorStr();
1639 
1640  Log(LOG_LEVEL_ERR, "Unable to set ownership on '%s' to '%ju.%ju'. (chown: %s)",
1641  workdir, (uintmax_t)getuid(), (uintmax_t)getgid(), error_reason);
1642  }
1643  }
1644 
1645  /* ensure workdir permissions are go-w */
1646  if ((statbuf.st_mode & 022) != 0)
1647  {
1648  if (chmod(workdir, (mode_t) (statbuf.st_mode & ~022)) == -1)
1649  {
1650  Log(LOG_LEVEL_ERR, "Unable to set permissions on '%s' to go-w. (chmod: %s)",
1651  workdir, GetErrorStr());
1652  }
1653  }
1654 
1655  MakeParentDirectory(GetStateDir(), false);
1656  Log(LOG_LEVEL_VERBOSE, "Checking integrity of the state database");
1657 
1658  snprintf(vbuff, CF_BUFSIZE, "%s", statedir);
1659 
1660  if (stat(vbuff, &statbuf) == -1)
1661  {
1662  snprintf(vbuff, CF_BUFSIZE, "%s%c", statedir, FILE_SEPARATOR);
1663  MakeParentDirectory(vbuff, false);
1664 
1665  if (chown(vbuff, getuid(), getgid()) == -1)
1666  {
1667  Log(LOG_LEVEL_ERR, "Unable to set owner on '%s' to '%ju.%ju'. (chown: %s)", vbuff,
1668  (uintmax_t)getuid(), (uintmax_t)getgid(), GetErrorStr());
1669  }
1670 
1671  chmod(vbuff, (mode_t) 0755);
1672  }
1673  else
1674  {
1675 #ifndef __MINGW32__
1676  if (statbuf.st_mode & 022)
1677  {
1678  Log(LOG_LEVEL_ERR, "UNTRUSTED: State directory %s (mode %jo) was not private, world and/or group writeable!", statedir,
1679  (uintmax_t)(statbuf.st_mode & 0777));
1680  }
1681 #endif /* !__MINGW32__ */
1682  }
1683 
1684  Log(LOG_LEVEL_VERBOSE, "Checking integrity of the module directory");
1685 
1686  snprintf(vbuff, CF_BUFSIZE, "%s%cmodules", workdir, FILE_SEPARATOR);
1687 
1688  if (stat(vbuff, &statbuf) == -1)
1689  {
1690  snprintf(vbuff, CF_BUFSIZE, "%s%cmodules%c.", workdir, FILE_SEPARATOR, FILE_SEPARATOR);
1691  MakeParentDirectory(vbuff, false);
1692 
1693  if (chown(vbuff, getuid(), getgid()) == -1)
1694  {
1695  Log(LOG_LEVEL_ERR, "Unable to set owner on '%s' to '%ju.%ju'. (chown: %s)", vbuff,
1696  (uintmax_t)getuid(), (uintmax_t)getgid(), GetErrorStr());
1697  }
1698 
1699  chmod(vbuff, (mode_t) 0700);
1700  }
1701  else
1702  {
1703 #ifndef __MINGW32__
1704  if (statbuf.st_mode & 022)
1705  {
1706  Log(LOG_LEVEL_ERR, "UNTRUSTED: Module directory %s (mode %jo) was not private!", vbuff,
1707  (uintmax_t)(statbuf.st_mode & 0777));
1708  }
1709 #endif /* !__MINGW32__ */
1710  }
1711 
1712  Log(LOG_LEVEL_VERBOSE, "Checking integrity of the PKI directory");
1713 
1714  snprintf(vbuff, CF_BUFSIZE, "%s%cppkeys", workdir, FILE_SEPARATOR);
1715 
1716  if (stat(vbuff, &statbuf) == -1)
1717  {
1718  snprintf(vbuff, CF_BUFSIZE, "%s%cppkeys%c", workdir, FILE_SEPARATOR, FILE_SEPARATOR);
1719  MakeParentDirectory(vbuff, false);
1720 
1721  chmod(vbuff, (mode_t) 0700); /* Keys must be immutable to others */
1722  }
1723  else
1724  {
1725 #ifndef __MINGW32__
1726  if (statbuf.st_mode & 077)
1727  {
1728  FatalError(ctx, "UNTRUSTED: Private key directory %s%cppkeys (mode %jo) was not private!\n", workdir,
1729  FILE_SEPARATOR, (uintmax_t)(statbuf.st_mode & 0777));
1730  }
1731 #endif /* !__MINGW32__ */
1732  }
1733 }
1734 
1735 
1736 const char *GenericAgentResolveInputPath(const GenericAgentConfig *config, const char *input_file)
1737 {
1738  static char input_path[CF_BUFSIZE]; /* GLOBAL_R, no initialization needed */
1739 
1740  switch (FilePathGetType(input_file))
1741  {
1743  strlcpy(input_path, input_file, CF_BUFSIZE);
1744  break;
1745 
1748  snprintf(input_path, CF_BUFSIZE, "%s%c%s", config->input_dir, FILE_SEPARATOR, input_file);
1749  break;
1750  }
1751 
1752  return MapName(input_path);
1753 }
1754 
1756 {
1757  WriterWriteF(w, "%s\n", NameVersion());
1758 }
1759 
1760 /*******************************************************************/
1761 
1762 const char *Version(void)
1763 {
1764  return VERSION;
1765 }
1766 
1767 /*******************************************************************/
1768 
1769 const char *NameVersion(void)
1770 {
1771  return "CFEngine Core " VERSION;
1772 }
1773 
1774 /********************************************************************/
1775 
1776 static void CleanPidFile(void)
1777 {
1778  if (unlink(PIDFILE) != 0)
1779  {
1780  if (errno != ENOENT)
1781  {
1782  Log(LOG_LEVEL_ERR, "Unable to remove pid file '%s'. (unlink: %s)", PIDFILE, GetErrorStr());
1783  }
1784  }
1785 }
1786 
1787 /********************************************************************/
1788 
1789 static void RegisterPidCleanup(void)
1790 {
1792 }
1793 
1794 /********************************************************************/
1795 
1796 void WritePID(char *filename)
1797 {
1798  pthread_once(&pid_cleanup_once, RegisterPidCleanup);
1799 
1800  snprintf(PIDFILE, CF_BUFSIZE - 1, "%s%c%s", GetPidDir(), FILE_SEPARATOR, filename);
1801 
1803  if (fp == NULL)
1804  {
1805  Log(LOG_LEVEL_INFO, "Could not write to PID file '%s'. (fopen: %s)", filename, GetErrorStr());
1806  return;
1807  }
1808 
1809  fprintf(fp, "%ju\n", (uintmax_t)getpid());
1810 
1811  fclose(fp);
1812 }
1813 
1814 bool GenericAgentConfigParseArguments(GenericAgentConfig *config, int argc, char **argv)
1815 {
1816  if (argc == 0)
1817  {
1818  return true;
1819  }
1820 
1821  if (argc > 1)
1822  {
1823  return false;
1824  }
1825 
1826  GenericAgentConfigSetInputFile(config, NULL, argv[0]);
1827  MINUSF = true;
1828  return true;
1829 }
1830 
1831 bool GenericAgentConfigParseWarningOptions(GenericAgentConfig *config, const char *warning_options)
1832 {
1833  if (strlen(warning_options) == 0)
1834  {
1835  return false;
1836  }
1837 
1838  if (strcmp("error", warning_options) == 0)
1839  {
1841  return true;
1842  }
1843 
1844  const char *options_start = warning_options;
1845  bool warnings_as_errors = false;
1846 
1847  if (StringStartsWith(warning_options, "error="))
1848  {
1849  options_start = warning_options + strlen("error=");
1850  warnings_as_errors = true;
1851  }
1852 
1853  StringSet *warnings_set = StringSetFromString(options_start, ',');
1854  StringSetIterator it = StringSetIteratorInit(warnings_set);
1855  const char *warning_str = NULL;
1856  while ((warning_str = StringSetIteratorNext(&it)))
1857  {
1858  int warning = ParserWarningFromString(warning_str);
1859  if (warning == -1)
1860  {
1861  Log(LOG_LEVEL_ERR, "Unrecognized warning '%s'", warning_str);
1862  StringSetDestroy(warnings_set);
1863  return false;
1864  }
1865 
1866  if (warnings_as_errors)
1867  {
1868  config->agent_specific.common.parser_warnings_error |= warning;
1869  }
1870  else
1871  {
1872  config->agent_specific.common.parser_warnings |= warning;
1873  }
1874  }
1875 
1876  StringSetDestroy(warnings_set);
1877  return true;
1878 }
1879 
1880 bool GenericAgentConfigParseColor(GenericAgentConfig *config, const char *mode)
1881 {
1882  if (!mode || strcmp("auto", mode) == 0)
1883  {
1884  config->color = config->tty_interactive;
1885  return true;
1886  }
1887  else if (strcmp("always", mode) == 0)
1888  {
1889  config->color = true;
1890  return true;
1891  }
1892  else if (strcmp("never", mode) == 0)
1893  {
1894  config->color = false;
1895  return true;
1896  }
1897  else
1898  {
1899  Log(LOG_LEVEL_ERR, "Unrecognized color mode '%s'", mode);
1900  return false;
1901  }
1902 }
1903 
1905 {
1906  return isatty(0) || isatty(1) || isatty(2);
1907 }
1908 
1910 {
1911  GenericAgentConfig *config = xmalloc(sizeof(GenericAgentConfig));
1912 
1913  LoggingSetAgentType(CF_AGENTTYPES[agent_type]);
1914  config->agent_type = agent_type;
1915  config->tty_interactive = tty_interactive;
1916 
1917  const char *color_env = getenv("CFENGINE_COLOR");
1918  config->color = (color_env && strcmp(color_env, "1") == 0);
1919 
1920  config->bundlesequence = NULL;
1921 
1922  config->original_input_file = NULL;
1923  config->input_file = NULL;
1924  config->input_dir = NULL;
1925 
1926  config->check_not_writable_by_others = agent_type != AGENT_TYPE_COMMON;
1927  config->check_runnable = agent_type != AGENT_TYPE_COMMON;
1928  config->ignore_missing_bundles = false;
1929  config->ignore_missing_inputs = false;
1930 
1931  config->heap_soft = NULL;
1932  config->heap_negated = NULL;
1933  config->ignore_locks = false;
1934 
1936 
1941 
1942  /* By default we trust the network when bootstrapping. */
1944 
1945  /* By default we run promises.cf as the last step of boostrapping */
1947 
1948  /* Log classes */
1949  config->agent_specific.agent.report_class_log = false;
1950 
1951  switch (agent_type)
1952  {
1953  case AGENT_TYPE_COMMON:
1954  config->agent_specific.common.eval_functions = true;
1958  /* Bitfields of warnings to be recorded, or treated as errors. */
1961  break;
1962 
1963  case AGENT_TYPE_AGENT:
1966  break;
1967 
1968  default:
1969  break;
1970  }
1971 
1972  return config;
1973 }
1974 
1976 {
1977  if (config)
1978  {
1979  RlistDestroy(config->bundlesequence);
1980  StringSetDestroy(config->heap_soft);
1981  StringSetDestroy(config->heap_negated);
1982  free(config->original_input_file);
1983  free(config->input_file);
1984  free(config->input_dir);
1989  free(config);
1990  }
1991 }
1992 
1994 {
1995  if (config->heap_soft)
1996  {
1998  const char *context = NULL;
1999  while ((context = StringSetIteratorNext(&it)))
2000  {
2001  Class *cls = EvalContextClassGet(ctx, NULL, context);
2002  if (cls && !cls->is_soft)
2003  {
2004  FatalError(ctx, "You cannot use -D to define a reserved class");
2005  }
2006 
2007  EvalContextClassPutSoft(ctx, context, CONTEXT_SCOPE_NAMESPACE, "source=environment");
2008  }
2009  }
2010 
2011  switch (LogGetGlobalLevel())
2012  {
2013  case LOG_LEVEL_DEBUG:
2014  EvalContextClassPutHard(ctx, "debug_mode", "cfe_internal,source=agent");
2015  EvalContextClassPutHard(ctx, "opt_debug", "cfe_internal,source=agent");
2016  // intentional fall
2017  case LOG_LEVEL_VERBOSE:
2018  EvalContextClassPutHard(ctx, "verbose_mode", "cfe_internal,source=agent");
2019  // intentional fall
2020  case LOG_LEVEL_INFO:
2021  EvalContextClassPutHard(ctx, "inform_mode", "cfe_internal,source=agent");
2022  break;
2023  default:
2024  break;
2025  }
2026 
2027  if (config->color)
2028  {
2029  LoggingSetColor(config->color);
2030  }
2031 
2032  switch (config->agent_type)
2033  {
2034  case AGENT_TYPE_COMMON:
2036  if (config->agent_specific.common.eval_functions)
2038  break;
2039 
2040  default:
2041  break;
2042  }
2043 
2045 
2046  if (DONTDO)
2047  {
2048  EvalContextClassPutHard(ctx, "opt_dry_run", "cfe_internal,source=environment");
2049  }
2050 }
2051 
2052 bool CheckAndGenerateFailsafe(const char *inputdir, const char *input_file)
2053 {
2054  char failsafe_path[CF_BUFSIZE];
2055 
2056  if (strlen(inputdir) + strlen(input_file) > sizeof(failsafe_path) - 2)
2057  {
2059  "Unable to generate path for %s/%s file. Path too long.",
2060  inputdir, input_file);
2061  /* We could create dynamically allocated buffer able to hold the
2062  whole content of the path but this should be unlikely that we
2063  will end up here. */
2064  return false;
2065  }
2066  snprintf(failsafe_path, CF_BUFSIZE - 1, "%s/%s", inputdir, input_file);
2067  MapName(failsafe_path);
2068 
2069  if (access(failsafe_path, R_OK) != 0)
2070  {
2071  return WriteBuiltinFailsafePolicyToPath(failsafe_path);
2072  }
2073  return true;
2074 }
2075 
2076 void GenericAgentConfigSetInputFile(GenericAgentConfig *config, const char *inputdir, const char *input_file)
2077 {
2078  free(config->original_input_file);
2079  free(config->input_file);
2080  free(config->input_dir);
2081 
2082  config->original_input_file = xstrdup(input_file);
2083 
2084  if (inputdir && FilePathGetType(input_file) == FILE_PATH_TYPE_NON_ANCHORED)
2085  {
2086  config->input_file = StringFormat("%s%c%s", inputdir, FILE_SEPARATOR, input_file);
2087  }
2088  else
2089  {
2090  config->input_file = xstrdup(input_file);
2091  }
2092 
2093  config->input_dir = xstrdup(config->input_file);
2094  if (!ChopLastNode(config->input_dir))
2095  {
2096  free(config->input_dir);
2097  config->input_dir = xstrdup(".");
2098  }
2099 }
2100 
2102 {
2103  RlistDestroy(config->bundlesequence);
2104  config->bundlesequence = RlistCopy(bundlesequence);
2105 }
2106 
2108 {
2109  const char *tls_ciphers =
2111  const char *tls_min_version =
2113 
2114  return cfnet_init(tls_min_version, tls_ciphers);
2115 }
2116 
2118 {
2119  signal(SIGINT, HandleSignalsForAgent);
2120  signal(SIGTERM, HandleSignalsForAgent);
2121  signal(SIGBUS, HandleSignalsForAgent);
2122  signal(SIGHUP, SIG_IGN);
2123  signal(SIGPIPE, SIG_IGN);
2124  signal(SIGUSR1, HandleSignalsForAgent);
2125  signal(SIGUSR2, HandleSignalsForAgent);
2126 }
2127 
2128 void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp)
2129 {
2130  assert(regexp != NULL);
2131 
2133  Class *cls = NULL;
2134 
2135  Seq *seq = SeqNew(1000, free);
2136 
2137  pcre *rx = CompileRegex(regexp);
2138 
2139  if (rx == NULL)
2140  {
2141  Log(LOG_LEVEL_ERR, "Sorry, we could not compile regular expression %s", regexp);
2142  return;
2143  }
2144 
2145  while ((cls = ClassTableIteratorNext(iter)))
2146  {
2147  char *class_name = ClassRefToString(cls->ns, cls->name);
2148 
2149  if (!RegexPartialMatch(rx, class_name))
2150  {
2151  free(class_name);
2152  continue;
2153  }
2154 
2155  StringSet *tagset = EvalContextClassTags(ctx, cls->ns, cls->name);
2156  Buffer *tagbuf = StringSetToBuffer(tagset, ',');
2157 
2158  char *line;
2159  xasprintf(&line, "%-60s %-40s", class_name, BufferData(tagbuf));
2160  SeqAppend(seq, line);
2161 
2162  BufferDestroy(tagbuf);
2163  free(class_name);
2164  }
2165 
2166  pcre_free(rx);
2167 
2168  SeqSort(seq, (SeqItemComparator)strcmp, NULL);
2169 
2170  printf("%-60s %-40s\n", "Class name", "Meta tags");
2171 
2172  for (size_t i = 0; i < SeqLength(seq); i++)
2173  {
2174  const char *context = SeqAt(seq, i);
2175  printf("%s\n", context);
2176  }
2177 
2178  SeqDestroy(seq);
2179 
2181 }
2182 
2183 void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp)
2184 {
2185  assert(regexp != NULL);
2186 
2188  Variable *v = NULL;
2189 
2190  Seq *seq = SeqNew(2000, free);
2191 
2192  pcre *rx = CompileRegex(regexp);
2193 
2194  if (rx == NULL)
2195  {
2196  Log(LOG_LEVEL_ERR, "Sorry, we could not compile regular expression %s", regexp);
2197  return;
2198  }
2199 
2200  while ((v = VariableTableIteratorNext(iter)))
2201  {
2202  char *varname = VarRefToString(v->ref, true);
2203 
2204  if (!RegexPartialMatch(rx, varname))
2205  {
2206  free(varname);
2207  continue;
2208  }
2209 
2210  Writer *w = StringWriter();
2211 
2212  switch (DataTypeToRvalType(v->type))
2213  {
2214  case RVAL_TYPE_CONTAINER:
2216  break;
2217 
2218  default:
2219  RvalWrite(w, v->rval);
2220  }
2221 
2222  const char *var_value;
2224  {
2225  var_value = StringWriterData(w);
2226  }
2227  else
2228  {
2229  var_value = "<non-printable>";
2230  }
2231 
2232 
2233  StringSet *tagset = EvalContextVariableTags(ctx, v->ref);
2234  Buffer *tagbuf = StringSetToBuffer(tagset, ',');
2235 
2236  char *line;
2237  xasprintf(&line, "%-40s %-60s %-40s", varname, var_value, BufferData(tagbuf));
2238 
2239  SeqAppend(seq, line);
2240 
2241  BufferDestroy(tagbuf);
2242  WriterClose(w);
2243  free(varname);
2244  }
2245 
2246  pcre_free(rx);
2247 
2248  SeqSort(seq, (SeqItemComparator)strcmp, NULL);
2249 
2250  printf("%-40s %-60s %-40s\n", "Variable name", "Variable value", "Meta tags");
2251 
2252  for (size_t i = 0; i < SeqLength(seq); i++)
2253  {
2254  const char *variable = SeqAt(seq, i);
2255  printf("%s\n", variable);
2256  }
2257 
2258  SeqDestroy(seq);
2260 }
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
void FatalError(const EvalContext *ctx, char *s,...)
Definition: audit.c:94
void UpdateLastPolicyUpdateTime(EvalContext *ctx)
Updates sys.last_policy_update variable from $(sys.masterdir)/cf_promises_validated.
Definition: bootstrap.c:167
void EvalContextSetPolicyServer(EvalContext *ctx, const char *new_policy_server)
Sets both internal C variables as well as policy sys variables.
Definition: bootstrap.c:94
char * CreateBootstrapIDFile(const char *workdir)
Definition: bootstrap.c:360
bool WriteBuiltinFailsafePolicyToPath(const char *filename)
Exposed for testing. Use WriteBuiltinFailsafePolicy.
Definition: bootstrap.c:263
bool MasterfileExists(const char *masterdir)
Definition: bootstrap.c:325
bool WriteBuiltinFailsafePolicy(const char *inputdir)
Write the builtin failsafe policy to the default location.
Definition: bootstrap.c:251
bool RemoveAllExistingPolicyInInputs(const char *inputs_path)
Removes all files in $(sys.inputdir)
Definition: bootstrap.c:295
char * ReadBootstrapIDFile(const char *workdir)
Definition: bootstrap.c:385
bool WriteAmPolicyHubFile(bool am_policy_hub)
Definition: bootstrap.c:211
void EvalContextSetBootstrapID(EvalContext *ctx, char *bootstrap_id)
Definition: bootstrap.c:423
bool GetAmPolicyHub(void)
Definition: bootstrap.c:191
void BufferDestroy(Buffer *buffer)
Destroys a buffer and frees the memory associated with it.
Definition: buffer.c:72
const char * BufferData(const Buffer *buffer)
Provides a pointer to the internal data.
Definition: buffer.c:470
ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, Nova_TrackExecution, ARG_UNUSED const char *, input_file)
#define ARG_UNUSED
Definition: cf-net.c:47
#define EXEC_SUFFIX
Definition: cf3.defs.h:282
@ COMMON_CONTROL_TLS_CIPHERS
Definition: cf3.defs.h:434
@ COMMON_CONTROL_TLS_MIN_VERSION
Definition: cf3.defs.h:435
@ RVAL_TYPE_CONTAINER
Definition: cf3.defs.h:609
AgentType
Definition: cf3.defs.h:400
@ AGENT_TYPE_MONITOR
Definition: cf3.defs.h:404
@ AGENT_TYPE_KEYGEN
Definition: cf3.defs.h:407
@ AGENT_TYPE_EXECUTOR
Definition: cf3.defs.h:405
@ AGENT_TYPE_SERVER
Definition: cf3.defs.h:403
@ AGENT_TYPE_COMMON
Definition: cf3.defs.h:401
@ AGENT_TYPE_AGENT
Definition: cf3.defs.h:402
@ CF_DATA_TYPE_STRING_LIST
Definition: cf3.defs.h:372
@ CF_DATA_TYPE_STRING
Definition: cf3.defs.h:369
@ CF_DATA_TYPE_CONTAINER
Definition: cf3.defs.h:384
@ CONTEXT_SCOPE_NAMESPACE
Definition: cf3.defs.h:946
bool DONTDO
Definition: cf3globals.c:55
HashMethod CF_DEFAULT_DIGEST
Definition: cf3globals.c:88
bool MINUSF
Definition: cf3globals.c:150
const char *const CF_AGENTTYPES[]
Definition: constants.c:65
struct utsname VSYSNAME
Definition: cf3globals.c:38
AgentType THIS_AGENT_TYPE
Definition: cf3globals.c:43
int CF_DEFAULT_DIGEST_LEN
Definition: cf3globals.c:89
void free(void *)
char * ClassRefToString(const char *ns, const char *name)
Definition: class.c:319
void ClassTableIteratorDestroy(ClassTableIterator *iter)
Definition: class.c:286
Class * ClassTableIteratorNext(ClassTableIterator *iter)
Definition: class.c:248
void RegisterCleanupFunction(CleanupFn fn)
Definition: cleanup.c:63
void DoCleanupAndExit(int ret)
Definition: cleanup.c:57
bool cfnet_init(const char *tls_min_version, const char *ciphers)
Definition: client_code.c:57
void cfnet_shut()
Definition: client_code.c:63
void DetermineCfenginePort()
Definition: client_code.c:80
bool LoadSecretKeys(const char *const priv_key_path, const char *const pub_key_path, RSA **priv_key, RSA **pub_key)
Definition: crypto.c:170
void CryptoInitialize()
Definition: crypto.c:71
void PolicyHubUpdateKeys(const char *policy_server)
Definition: crypto.c:276
void CryptoDeInitialize()
Definition: crypto.c:86
#define CF_PERMS_DEFAULT
Definition: definitions.h:58
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_EXPANDSIZE
Definition: definitions.h:51
#define CF_MAXVARSIZE
Definition: definitions.h:36
#define ENTERPRISE_VOID_FUNC_2ARG_DEFINE_STUB(__ret, __func, __t1, __p1, __t2, __p2)
void CheckAndSetHAState(const char *workdir, EvalContext *ctx)
void EvalContextSetEntryPoint(EvalContext *const ctx, const char *const entry_point)
StringSet * ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, const char *regex, const Rlist *tags, bool first_only)
JsonElement * JsonExpandElement(EvalContext *ctx, const JsonElement *source)
StringSet * EvalContextVariableTags(const EvalContext *ctx, const VarRef *ref)
const void * EvalContextVariableControlCommonGet(const EvalContext *ctx, CommonControl lval)
ClassTableIterator * EvalContextClassTableIteratorNewGlobal(const EvalContext *ctx, const char *ns, bool is_hard, bool is_soft)
void EvalContextSetLaunchDirectory(EvalContext *ctx, const char *path)
bool EvalContextClassPutHard(EvalContext *ctx, const char *name, const char *tags)
void EvalContextDestroy(EvalContext *ctx)
void EvalContextSetIgnoreLocks(EvalContext *ctx, bool ignore)
void EvalContextHeapPersistentLoadAll(EvalContext *ctx)
Definition: eval_context.c:731
StringSet * EvalContextClassTags(const EvalContext *ctx, const char *ns, const char *name)
void EvalContextSetEvalOption(EvalContext *ctx, EvalContextOption option, bool value)
bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const char *lval, const void *value, DataType type, const char *tags)
Class * EvalContextClassGet(const EvalContext *ctx, const char *ns, const char *name)
bool EvalContextClassPutSoft(EvalContext *ctx, const char *name, ContextScope scope, const char *tags)
VariableTableIterator * EvalContextVariableTableIteratorNew(const EvalContext *ctx, const char *ns, const char *scope, const char *lval)
static bool IsDefinedClass(const EvalContext *ctx, const char *context)
Definition: eval_context.h:213
@ EVAL_OPTION_EVAL_FUNCTIONS
Definition: eval_context.h:108
@ EVAL_OPTION_FULL
Definition: eval_context.h:111
bool ShellCommandReturnsZero(const char *command, ShellType shell)
Definition: unix.c:190
char * ExpandScalar(const EvalContext *ctx, const char *ns, const char *scope, const char *string, Buffer *out)
Definition: expand.c:516
FILE * safe_fopen_create_perms(const char *const path, const char *const mode, const mode_t create_perms)
Definition: file_lib.c:832
bool FileCanOpen(const char *path, const char *modes)
Definition: file_lib.c:46
FILE * safe_fopen(const char *const path, const char *const mode)
Definition: file_lib.c:812
char * MapName(char *s)
Definition: file_lib.c:441
#define FILE_SEPARATOR
Definition: file_lib.h:102
bool HashDirectoryTree(const char *path, const char **extensions_filter, EVP_MD_CTX *crypto_context)
Definition: files_lib.c:534
bool MakeParentDirectory(const char *parentandchild, bool force)
Definition: files_lib.c:133
void CreateEmptyFile(char *name)
Definition: files_lib.c:641
bool ChopLastNode(char *str)
Definition: files_names.c:422
char * CanonifyName(const char *str)
Definition: files_names.c:483
bool IsFileOutsideDefaultRepository(const char *f)
Definition: files_names.c:722
FilePathType FilePathGetType(const char *file_path)
Definition: files_names.c:706
char * GetAbsolutePath(const char *path)
Definition: files_names.c:642
bool IsNewerFileTree(const char *dir, time_t reftime)
Definition: files_names.c:41
@ FILE_PATH_TYPE_RELATIVE
Definition: files_names.h:33
@ FILE_PATH_TYPE_NON_ANCHORED
Definition: files_names.h:34
@ FILE_PATH_TYPE_ABSOLUTE
Definition: files_names.h:32
static JsonElement * ReadJsonFile(const char *filename, LogLevel log_level)
const char * Version(void)
bool GenericAgentConfigParseWarningOptions(GenericAgentConfig *config, const char *warning_options)
static bool MissingInputFile(const char *input_file)
static bool GeneratePolicyReleaseIDFromGit(char *release_id_out, size_t out_size, const char *policy_dir)
void GenericAgentConfigSetInputFile(GenericAgentConfig *config, const char *inputdir, const char *input_file)
void SetFacility(const char *retval)
bool GenericAgentArePromisesValid(const GenericAgentConfig *config)
bool GenericAgentIsPolicyReloadNeeded(const GenericAgentConfig *config)
GenericAgentConfig * GenericAgentConfigNewDefault(AgentType agent_type, bool tty_interactive)
static char CF_PROGRAM_NAME[256]
Definition: generic_agent.c:81
static JsonElement * ReadPolicyValidatedFile(const char *filename)
static JsonElement * ReadPolicyValidatedFileFromMasterfiles(const GenericAgentConfig *config, const char *maybe_dirname)
static bool WritePolicyValidatedFile(const GenericAgentConfig *config, const char *filename)
Writes a file with a contained timestamp to mark a policy file as validated.
bool GenericAgentPostLoadInit(const EvalContext *ctx)
static char PIDFILE[4096]
Definition: generic_agent.c:78
Policy * SelectAndLoadPolicy(GenericAgentConfig *config, EvalContext *ctx, bool validate_policy, bool write_validated_file)
static bool WriteReleaseIdFile(const char *filename, const char *dirname)
Writes a file with a contained release ID based on git SHA, or file checksum if git SHA is not availa...
static void GetPromisesValidatedFile(char *filename, size_t max_size, const GenericAgentConfig *config, const char *maybe_dirname)
Gets the promises_validated file name depending on context and options.
static void CleanPidFile(void)
bool GenericAgentCheckPolicy(GenericAgentConfig *config, bool force_validation, bool write_validated_file)
void GenericAgentConfigSetBundleSequence(GenericAgentConfig *config, const Rlist *bundlesequence)
static char * ReadReleaseIdFromReleaseIdFileMasterfiles(const char *maybe_dirname)
void SetupSignalsForAgent(void)
static int ParseFacility(const char *name)
void GenericAgentSetDefaultDigest(HashMethod *digest, int *digest_len)
void WritePID(char *filename)
static bool GeneratePolicyReleaseID(char *release_id_out, size_t out_size, const char *policy_dir)
const char * NameVersion(void)
static bool LoadAugmentsData(EvalContext *ctx, const char *filename, const JsonElement *augment)
void GetReleaseIdFile(const char *base_path, char *filename, size_t max_size)
Gets the release_id file name in the given base_path.
const char * GenericAgentResolveInputPath(const GenericAgentConfig *config, const char *input_file)
static void CheckWorkingDirectories(EvalContext *ctx)
static bool CheckContextClassmatch(EvalContext *ctx, const char *class_str)
time_t ReadTimestampFromPolicyValidatedFile(const GenericAgentConfig *config, const char *maybe_dirname)
static bool LoadAugmentsFiles(EvalContext *ctx, const char *filename)
static JsonElement * ReadReleaseIdFileFromMasterfiles(const char *maybe_dirname)
char * ReadChecksumFromPolicyValidatedMasterfiles(const GenericAgentConfig *config, const char *maybe_dirname)
static void GetAutotagDir(char *dirname, size_t max_size, const char *maybe_dirname)
Gets the promises_validated file name depending on context and options.
static void RegisterPidCleanup(void)
static bool GeneratePolicyReleaseIDFromTree(char *release_id_out, size_t out_size, const char *policy_dir)
static void AddPolicyEntryVariables(EvalContext *ctx, const GenericAgentConfig *config)
void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp)
Seq * ControlBodyConstraints(const Policy *policy, AgentType agent)
void CloseLog(void)
static bool IsPolicyPrecheckNeeded(GenericAgentConfig *config, bool force_validation)
static void SanitizeEnvironment()
void GenericAgentConfigDestroy(GenericAgentConfig *config)
void LoadAugments(EvalContext *ctx, GenericAgentConfig *config)
void GenericAgentFinalize(EvalContext *ctx, GenericAgentConfig *config)
bool GenericAgentTagReleaseDirectory(const GenericAgentConfig *config, const char *dirname, bool write_validated, bool write_release)
Writes the policy validation file and release ID to a directory.
bool CheckAndGenerateFailsafe(const char *inputdir, const char *input_file)
void GenericAgentDiscoverContext(EvalContext *ctx, GenericAgentConfig *config, const char *program_name)
void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp)
static void OpenLog(int facility)
void GenericAgentInitialize(EvalContext *ctx, GenericAgentConfig *config)
void MarkAsPolicyServer(EvalContext *ctx)
void GenericAgentAddEditionClasses(EvalContext *ctx)
bool GenericAgentConfigParseArguments(GenericAgentConfig *config, int argc, char **argv)
bool GetTTYInteractive(void)
bool GenericAgentConfigParseColor(GenericAgentConfig *config, const char *mode)
void GenericAgentConfigApply(EvalContext *ctx, const GenericAgentConfig *config)
void GenericAgentWriteVersion(Writer *w)
static pthread_once_t pid_cleanup_once
Definition: generic_agent.c:76
#define GENERIC_AGENT_CHECKSUM_METHOD
Definition: generic_agent.h:34
#define GENERIC_AGENT_CHECKSUM_SIZE
Definition: generic_agent.h:33
@ GENERIC_AGENT_CONFIG_COMMON_POLICY_OUTPUT_FORMAT_NONE
Definition: generic_agent.h:38
int errno
#define NULL
Definition: getopt1.c:56
char * getenv(char *name)
const EVP_MD * HashDigestFromId(HashMethod type)
Returns pointer to an openssl digest struct.
Definition: hash.c:383
char * HashPrintSafe(char *dst, size_t dst_size, const unsigned char *digest, HashMethod type, bool use_prefix)
Definition: hash.c:612
HashMethod
Definition: hash_method.h:36
@ HASH_METHOD_MD5
Definition: hash_method.h:37
@ CF_MD5_LEN
Definition: hash_method.h:50
void JsonWrite(Writer *const writer, const JsonElement *const element, const size_t indent_level)
Pretty-print a JsonElement recursively into a Writer. If it's a JsonObject, its children will be sort...
Definition: json.c:1701
const char * JsonIteratorNextKey(JsonIterator *const iter)
Definition: json.c:557
JsonElement * JsonObjectCreate(const size_t initialCapacity)
Create a new JSON object.
Definition: json.c:880
void JsonDestroy(JsonElement *const element)
Destroy a JSON element.
Definition: json.c:386
JsonElementType JsonGetElementType(const JsonElement *const element)
Definition: json.c:667
void JsonObjectAppendInteger(JsonElement *const object, const char *const key, const int value)
Append an integer field to an object.
Definition: json.c:1062
JsonIterator JsonIteratorInit(const JsonElement *const container)
Definition: json.c:549
JsonElement * JsonObjectGet(const JsonElement *const object, const char *const key)
Definition: json.c:1266
JsonParseError JsonParseFile(const char *const path, const size_t size_max, JsonElement **const json_out)
Convenience function to parse JSON from a file.
Definition: json.c:2727
bool JsonArrayContainsOnlyPrimitives(JsonElement *const array)
Check if an array contains only primitives.
Definition: json.c:1406
JsonContainerType JsonGetContainerType(const JsonElement *const container)
Definition: json.c:685
void JsonObjectAppendString(JsonElement *const object, const char *const key, const char *const value)
Append a string field to an object.
Definition: json.c:1055
JsonElement * JsonIteratorNextValueByType(JsonIterator *const iter, const JsonElementType type, const bool skip_null)
Definition: json.c:583
void JsonWriteCompact(Writer *const w, const JsonElement *const element)
Definition: json.c:1832
char * JsonPrimitiveToString(const JsonElement *const primitive)
Definition: json.c:709
const char * JsonPrimitiveGetAsString(const JsonElement *const primitive)
Definition: json.c:701
long JsonPrimitiveGetAsInteger(const JsonElement *const primitive)
Definition: json.c:750
const char * JsonParseErrorToString(const JsonParseError error)
Definition: json.c:1905
JsonParseError
Definition: json.h:83
@ JSON_PARSE_OK
Definition: json.h:84
@ JSON_ELEMENT_TYPE_PRIMITIVE
Definition: json.h:53
@ JSON_ELEMENT_TYPE_CONTAINER
Definition: json.h:52
@ JSON_CONTAINER_TYPE_ARRAY
Definition: json.h:59
@ JSON_CONTAINER_TYPE_OBJECT
Definition: json.h:58
const char * GetInputDir(void)
Definition: known_dirs.c:182
const char * GetLogDir(void)
Definition: known_dirs.c:146
const char * GetPidDir(void)
Definition: known_dirs.c:153
const char * GetStateDir(void)
Definition: known_dirs.c:186
const char * GetBinDir(void)
Definition: known_dirs.c:121
const char * GetMasterDir(void)
Definition: known_dirs.c:184
const char * GetWorkDir(void)
Definition: known_dirs.c:114
void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
EVP_MD_CTX * EVP_MD_CTX_new(void)
void LoadSystemConstants(EvalContext *ctx)
Definition: constants.c:30
Policy * LoadPolicy(EvalContext *ctx, GenericAgentConfig *config)
Definition: loading.c:495
LogLevel
Definition: log.h:30
void LoggingSetAgentType(const char *type)
Definition: logging.c:83
void LoggingSetColor(bool enabled)
Definition: logging.c:586
char VPREFIX[1024]
Definition: logging.c:33
LogLevel LogGetGlobalLevel(void)
Definition: logging.c:581
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_NOTICE
Definition: logging.h:44
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_WARNING
Definition: logging.h:43
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
void Banner(const char *s)
Definition: ornaments.c:219
int ParserWarningFromString(const char *warning_str)
Definition: parser.c:157
#define PARSER_WARNING_ALL
Definition: parser.h:33
int chown(const char *path, uid_t owner, gid_t group)
uid_t getuid(void)
gid_t getgid(void)
int uname(struct utsname *buf)
int chmod(const char *path, mode_t mode)
#define MAX_FILENAME
Definition: platform.h:51
#define PATH_MAX
Definition: platform.h:176
bool PolicyServerWriteFile(const char *workdir, const char *new_policy_server)
Write new_policy_server to the policy_server.dat file.
char * PolicyServerReadFile(const char *workdir)
Reads the policy_server.dat file.
bool PolicyServerLookUpFile(const char *workdir, char **ipaddr, char **port)
Reads and parses the policy_server.dat file.
Access to Policy Server IP Address, hostname and port number.
@ CF_PROTOCOL_UNDEFINED
#define OpenNetwork()
Definition: prototypes3.h:101
pcre * CompileRegex(const char *regex)
Definition: regex.c:37
bool RegexPartialMatch(const pcre *rx, const char *teststring)
Definition: regex.c:278
JsonElement * RvalContainerValue(Rval rval)
Definition: rlist.c:165
char * RlistScalarValue(const Rlist *rlist)
Definition: rlist.c:83
void RvalWrite(Writer *writer, Rval rval)
Definition: rlist.c:1386
Rlist * RlistFromContainer(const JsonElement *container)
Definition: rlist.c:1691
void RlistDestroy(Rlist *rl)
Definition: rlist.c:501
RvalType DataTypeToRvalType(DataType datatype)
Definition: rlist.c:44
Rlist * RlistCopy(const Rlist *rp)
Definition: rlist.c:494
const char * SpecialScopeToString(SpecialScope scope)
Definition: scope.c:42
@ SPECIAL_SCOPE_SYS
Definition: scope.h:38
@ SPECIAL_SCOPE_DEF
Definition: scope.h:41
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 SeqSort(Seq *seq, SeqItemComparator Compare, void *user_data)
Sort a Sequence according to the given item comparator function.
Definition: sequence.c:279
void SeqDestroy(Seq *seq)
Destroy an existing Sequence.
Definition: sequence.c:60
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
int(* SeqItemComparator)(const void *, const void *, void *user_data)
Function to compare two items in a Sequence.
Definition: sequence.h:100
StringSetIterator StringSetIteratorInit(StringSet *set)
Definition: set.c:34
StringSet * StringSetFromString(const char *str, char delimiter)
Definition: set.c:179
size_t StringSetSize(const StringSet *set)
Definition: set.c:34
Buffer * StringSetToBuffer(StringSet *set, const char delimiter)
Definition: set.c:117
void StringSetDestroy(StringSet *set)
Definition: set.c:34
char * StringSetIteratorNext(StringSetIterator *iter)
Definition: set.c:34
void setlinebuf(FILE *stream)
Definition: setlinebuf.c:47
void HandleSignalsForAgent(int signum)
Definition: signals.c:145
#define ERANGE
Definition: snprintf.c:453
bool StringEndsWith(const char *str, const char *suffix)
Check if a string ends with the given suffix.
Definition: string_lib.c:1330
bool StringStartsWith(const char *str, const char *prefix)
Check if a string starts with the given prefix.
Definition: string_lib.c:1335
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
char * StringCanonify(char *dst, const char *src)
Definition: string_lib.c:1430
bool StringIsPrintable(const char *s)
Definition: string_lib.c:441
char * StringFormat(const char *fmt,...)
Format string like sprintf and return formatted string allocated on heap as a return value.
Definition: string_lib.c:51
size_t strlcat(char *dst, const char *src, size_t siz)
Definition: strlcat.c:36
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
char * strstr(const char *haystack, const char *needle)
Definition: strstr.c:35
Definition: policy.h:85
char * type
Definition: policy.h:88
Seq * conlist
Definition: policy.h:93
char * name
Definition: policy.h:89
Definition: buffer.h:50
Definition: class.h:31
char * ns
Definition: class.h:32
char * name
Definition: class.h:33
bool is_soft
Definition: class.h:36
unsigned int parser_warnings
Definition: generic_agent.h:77
StringSet * heap_soft
Definition: generic_agent.h:59
char * show_evaluated_variables
Definition: generic_agent.h:92
char * original_input_file
Definition: generic_agent.h:51
bool check_not_writable_by_others
Definition: generic_agent.h:56
AgentType agent_type
Definition: generic_agent.h:47
enum generic_agent_config_common_policy_output_format policy_output_format
Definition: generic_agent.h:76
struct GenericAgentConfig::@14::@15 common
struct GenericAgentConfig::@14 agent_specific
ProtocolVersion protocol_version
Definition: generic_agent.h:66
struct GenericAgentConfig::@14::@16 agent
StringSet * heap_negated
Definition: generic_agent.h:60
struct GenericAgentConfig::@14::@17 daemon
char * show_evaluated_classes
Definition: generic_agent.h:91
unsigned int parser_warnings_error
Definition: generic_agent.h:78
Definition: policy.h:53
char * release_id
Definition: policy.h:54
Seq * bodies
Definition: policy.h:57
Definition: rlist.h:35
Rlist * next
Definition: rlist.h:37
Sequence data-structure.
Definition: sequence.h:50
Definition: set.h:138
VarRef * ref
Definition: variable.h:33
DataType type
Definition: variable.h:35
Rval rval
Definition: variable.h:34
Definition: writer.c:45
void DetectEnvironment(EvalContext *ctx)
Definition: sysinfo.c:3332
void SetSyslogFacility(int facility)
Definition: syslog_client.c:44
void UpdateTimeClasses(EvalContext *ctx, time_t t)
Definition: time_classes.c:133
time_t SetReferenceTime(void)
Definition: timeout.c:55
int unsetenv(const char *name)
char * VarRefToString(const VarRef *ref, bool qualified)
Variable * VariableTableIteratorNext(VariableTableIterator *iter)
Definition: variable.c:283
void VariableTableIteratorDestroy(VariableTableIterator *iter)
Definition: variable.c:336
size_t WriterWrite(Writer *writer, const char *str)
Definition: writer.c:193
Writer * FileWriter(FILE *file)
Definition: writer.c:56
const char * StringWriterData(const Writer *writer)
Definition: writer.c:229
void WriterClose(Writer *writer)
Definition: writer.c:242
size_t WriterWriteF(Writer *writer, const char *fmt,...)
Definition: writer.c:144
Writer * StringWriter(void)
Definition: writer.c:67