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)  

server_transform.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 <server_transform.h>
26 
27 #include <server.h>
28 
29 #include <misc_lib.h>
30 #include <eval_context.h>
31 #include <files_names.h>
32 #include <mod_common.h>
33 #include <mod_access.h>
34 #include <item_lib.h>
35 #include <conversion.h>
36 #include <ornaments.h>
37 #include <expand.h>
38 #include <scope.h>
39 #include <vars.h>
40 #include <attributes.h>
41 #include <communication.h>
42 #include <string_lib.h>
43 #include <rlist.h>
45 #include <syslog_client.h>
46 #include <verify_classes.h>
47 #include <verify_vars.h>
48 #include <generic_agent.h> /* HashControls */
49 #include <file_lib.h> /* IsDirReal */
50 #include <matching.h> /* IsRegex */
51 #include <net.h>
52 #include <client_code.h>
53 #include <cfnet.h>
54 
55 #include "server_common.h" /* PreprocessRequestPath */
56 #include "server_access.h"
57 #include "strlist.h"
58 #include <cleanup.h>
59 
60 
61 static PromiseResult KeepServerPromise(EvalContext *ctx, const Promise *pp, void *param);
62 static void InstallServerAuthPath(const char *path, Auth **list, Auth **listtail);
63 static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp);
64 static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy);
65 static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config);
66 static void KeepBundlesAccessPromise(EvalContext *ctx, const Promise *pp);
67 static Auth *GetAuthPath(const char *path, Auth *list);
68 
69 
70 extern int COLLECT_INTERVAL;
71 extern int COLLECT_WINDOW;
72 extern bool SERVER_LISTEN;
73 
74 
75 /*******************************************************************/
76 /* GLOBAL VARIABLES */
77 /*******************************************************************/
78 
79 extern int CFD_MAXPROCESSES;
80 extern int NO_FORK;
81 extern bool DENYBADCLOCKS;
82 extern int MAXTRIES;
83 extern bool LOGENCRYPT;
84 
85 /*******************************************************************/
86 
87 static void KeepFileAccessPromise(const EvalContext *ctx, const Promise *pp);
88 static void KeepLiteralAccessPromise(EvalContext *ctx, const Promise *pp, const char *type);
89 static void KeepQueryAccessPromise(EvalContext *ctx, const Promise *pp);
90 
91 /*******************************************************************/
92 /* Level */
93 /*******************************************************************/
94 
95 
96 void Summarize()
97 {
98  Auth *ptr;
99  Item *ip, *ipr;
100 
101  Log(LOG_LEVEL_VERBOSE, " === BEGIN summary of access promises === ");
102 
104  "Host IPs allowed connection access (allowconnects):");
105  for (ip = SERVER_ACCESS.nonattackerlist; ip != NULL; ip = ip->next)
106  {
107  Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
108  }
109 
111  "Host IPs denied connection access (denyconnects):");
112  for (ip = SERVER_ACCESS.attackerlist; ip != NULL; ip = ip->next)
113  {
114  Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
115  }
116 
118  "Host IPs allowed multiple connection access (allowallconnects):");
119  for (ip = SERVER_ACCESS.multiconnlist; ip != NULL; ip = ip->next)
120  {
121  Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
122  }
123 
125  "Host IPs whose keys we shall establish trust to (trustkeysfrom):");
126  for (ip = SERVER_ACCESS.trustkeylist; ip != NULL; ip = ip->next)
127  {
128  Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
129  }
130 
132  "Host IPs allowed legacy connections (allowlegacyconnects):");
133  for (ip = SERVER_ACCESS.allowlegacyconnects; ip != NULL; ip = ip->next)
134  {
135  Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
136  }
137 
139  "Users from whom we accept cf-runagent connections (allowusers):");
140  for (ip = SERVER_ACCESS.allowuserlist; ip != NULL; ip = ip->next)
141  {
142  Log(LOG_LEVEL_VERBOSE, "\tUSER: %s", ip->name);
143  }
144 
145  Log(LOG_LEVEL_VERBOSE, "Access control lists:");
146  acl_Summarise(paths_acl, "Path");
147  acl_Summarise(classes_acl, "Class");
148  acl_Summarise(vars_acl, "Variable");
149  acl_Summarise(literals_acl, "Literal");
150  acl_Summarise(query_acl, "Query");
151  acl_Summarise(roles_acl, "Role");
152  acl_Summarise(bundles_acl, "Bundle");
153 
155  "Access control lists for the classic network protocol:");
156 
157  for (ptr = SERVER_ACCESS.admit; ptr != NULL; ptr = ptr->next)
158  {
159  /* Don't report empty entries. */
160  if (ptr->maproot != NULL || ptr->accesslist != NULL)
161  {
162  Log(LOG_LEVEL_VERBOSE, "\tPath: %s", ptr->path);
163  }
164 
165  for (ipr = ptr->maproot; ipr != NULL; ipr = ipr->next)
166  {
167  Log(LOG_LEVEL_VERBOSE, "\t\tmaproot user: %s,", ipr->name);
168  }
169 
170  for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
171  {
172  Log(LOG_LEVEL_VERBOSE, "\t\tadmit: %s", ip->name);
173  }
174  }
175 
176  for (ptr = SERVER_ACCESS.deny; ptr != NULL; ptr = ptr->next)
177  {
178  /* Don't report empty entries. */
179  if (ptr->accesslist != NULL)
180  {
181  Log(LOG_LEVEL_VERBOSE, "\tPath: %s", ptr->path);
182  }
183 
184  for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
185  {
186  Log(LOG_LEVEL_VERBOSE, "\t\tdeny: %s", ip->name);
187  }
188  }
189 
190  for (ptr = SERVER_ACCESS.varadmit; ptr != NULL; ptr = ptr->next)
191  {
192  Log(LOG_LEVEL_VERBOSE, "Object: %s", ptr->path);
193 
194  for (ipr = ptr->maproot; ipr != NULL; ipr = ipr->next)
195  {
196  Log(LOG_LEVEL_VERBOSE, "%s,", ipr->name);
197  }
198  for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
199  {
200  Log(LOG_LEVEL_VERBOSE, "Admit '%s' root=", ip->name);
201  }
202  }
203 
204  for (ptr = SERVER_ACCESS.vardeny; ptr != NULL; ptr = ptr->next)
205  {
206  Log(LOG_LEVEL_VERBOSE, "Object %s", ptr->path);
207 
208  for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
209  {
210  Log(LOG_LEVEL_VERBOSE, "Deny '%s'", ip->name);
211  }
212  }
213 
214  Log(LOG_LEVEL_VERBOSE, " === END summary of access promises === ");
215 }
216 
217 void KeepPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
218 {
219  if (paths_acl != NULL || classes_acl != NULL || vars_acl != NULL ||
220  literals_acl != NULL || query_acl != NULL || bundles_acl != NULL ||
222  {
223  UnexpectedError("ACLs are not NULL - we are probably leaking memory!");
224  }
225 
226  paths_acl = calloc(1, sizeof(*paths_acl));
227  classes_acl = calloc(1, sizeof(*classes_acl));
228  vars_acl = calloc(1, sizeof(*vars_acl));
229  literals_acl = calloc(1, sizeof(*literals_acl));
230  query_acl = calloc(1, sizeof(*query_acl));
231  bundles_acl = calloc(1, sizeof(*bundles_acl));
232  roles_acl = calloc(1, sizeof(*roles_acl));
234 
235  if (paths_acl == NULL || classes_acl == NULL || vars_acl == NULL ||
236  literals_acl == NULL || query_acl == NULL || bundles_acl == NULL ||
238  {
239  Log(LOG_LEVEL_CRIT, "calloc: %s", GetErrorStr());
240  DoCleanupAndExit(255);
241  }
242 
243  KeepControlPromises(ctx, policy, config);
244  KeepPromiseBundles(ctx, policy);
245 }
246 
247 /*******************************************************************/
248 
249 static bool SetMaxOpenFiles(int n)
250 #ifdef HAVE_SYS_RESOURCE_H
251 {
252  const struct rlimit lim = {
253  .rlim_cur = n,
254  .rlim_max = n,
255  };
256  int ret = setrlimit(RLIMIT_NOFILE, &lim);
257  if (ret == -1)
258  {
259  Log(LOG_LEVEL_INFO, "Failed setting max open files limit"
260  " (setrlimit(NOFILE, %d): %s)", n, GetErrorStr());
262  "Please ensure that 'nofile' ulimit is at least 5x maxconnections");
263  return false;
264  }
265  else
266  {
267  Log(LOG_LEVEL_VERBOSE, "Setting max open files rlimit to %d", n);
268  return true;
269  }
270 }
271 #else /* MinGW */
272 {
274  "Platform does not support setrlimit(NOFILE), max open files not set");
275  return false;
276 }
277 #endif /* HAVE_SYS_RESOURCE_H */
278 
279 static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
280 {
281  CFD_MAXPROCESSES = 30;
282  MAXTRIES = 5;
283  DENYBADCLOCKS = true;
284  CFRUNCOMMAND[0] = '\0';
285  SetChecksumUpdatesDefault(ctx, true);
286 
287  /* Keep promised agent behaviour - control bodies */
288 
289  Banner("Server control promises..");
290 
291  PolicyResolve(ctx, policy, config);
292 
293  /* Now expand */
294 
295  Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_SERVER);
296 
297 #define IsControlBody(e) (strcmp(cp->lval, CFS_CONTROLBODY[e].lval) == 0)
298 
299  if (constraints)
300  {
301  for (size_t i = 0; i < SeqLength(constraints); i++)
302  {
303  Constraint *cp = SeqAt(constraints, i);
304 
305  if (!IsDefinedClass(ctx, cp->classes))
306  {
307  continue;
308  }
309 
310  VarRef *ref = VarRefParseFromScope(cp->lval, "control_server");
311  const void *value = EvalContextVariableGet(ctx, ref, NULL);
312  VarRefDestroy(ref);
313 
315  {
316  SetFacility(value);
317  }
319  {
322  "Setting denybadclocks to '%s'",
323  DENYBADCLOCKS ? "true" : "false");
324  }
326  {
327  LOGENCRYPT = BooleanFromString(value);
329  "Setting logencrypt to '%s'",
330  LOGENCRYPT ? "true" : "false");
331  }
333  {
335  Log(LOG_LEVEL_VERBOSE, "Setting logconns to %d", SERVER_ACCESS.logconns);
336  }
338  {
339  CFD_MAXPROCESSES = (int) IntFromString(value);
340 
341  /* Ease apoptosis limits. */
343 
344  /* The handling of max_readers in LMDB is not ideal, but
345  * here is how it is right now: We know that both cf-serverd and
346  * cf-hub will access the lastseen database. Worst case every
347  * single thread and process will do it at the same time, and
348  * this has in fact been observed. So we add the maximum of
349  * those two values together to provide a safe ceiling. In
350  * addition, cf-agent can access the database occasionally as
351  * well, so add a few extra for that too. */
353  "Setting maxconnections to %d", CFD_MAXPROCESSES);
356 
357  /* Set RLIMIT_NOFILE to be enough for all threads. */
359  }
361  {
362  COLLECT_INTERVAL = (int) 60 * IntFromString(value);
364  "Setting call_collect_interval to %d (seconds)",
366  }
368  {
371  "Setting server listen to '%s' ",
372  SERVER_LISTEN ? "true" : "false");
373  }
375  {
376  COLLECT_WINDOW = (int) IntFromString(value);
378  "Setting collect_window to %d (seconds)",
380  }
382  {
383  if (strlen(value) >= sizeof(CFRUNCOMMAND))
384  {
386  "cfruncommand too long (>%zu), leaving empty",
387  sizeof(CFRUNCOMMAND));
388  }
389  else
390  {
391  memcpy(CFRUNCOMMAND, value, strlen(value) + 1);
392  Log(LOG_LEVEL_VERBOSE, "Setting cfruncommand to: %s",
393  CFRUNCOMMAND);
394  }
395  }
397  {
398  Log(LOG_LEVEL_VERBOSE, "Setting allowing connections from ...");
399 
400  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
401  {
403  {
405  }
406  }
407  }
409  {
410  Log(LOG_LEVEL_VERBOSE, "Setting denying connections from ...");
411 
412  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
413  {
415  {
417  }
418  }
419  }
421  {
422  /* Skip. */
423  }
425  {
426  Log(LOG_LEVEL_VERBOSE, "Setting allowing multiple connections from ...");
427 
428  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
429  {
431  {
433  }
434  }
435  }
437  {
438  Log(LOG_LEVEL_VERBOSE, "SET Allowing users ...");
439 
440  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
441  {
443  {
445  }
446  }
447  }
449  {
450  Log(LOG_LEVEL_VERBOSE, "Setting 'trustkeysfrom' ...");
451 
452  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
453  {
455  {
457  }
458  }
459  }
461  {
462  Log(LOG_LEVEL_VERBOSE, "Setting 'allowlegacyconnects' ...");
463 
464  for (const Rlist *rp = value; rp != NULL; rp = rp->next)
465  {
467  {
469  }
470  }
471  }
473  {
474  bool ret = SetCfenginePort(value);
475  assert(ret);
476  if (ret == false)
477  {
478  Log(LOG_LEVEL_VERBOSE, "Could not set port number, continuing (See errors above)");
479  }
480  }
482  {
483  SetBindInterface(value);
484  }
486  {
487  assert(SERVER_ACCESS.allowciphers == NULL); /* no leak */
489  Log(LOG_LEVEL_VERBOSE, "Setting allowciphers to: %s",
491  }
493  {
494  assert(SERVER_ACCESS.allowtlsversion == NULL); /* no leak */
496  Log(LOG_LEVEL_VERBOSE, "Setting allowtlsversion to: %s",
498  }
499  }
500 
501 #undef IsControlBody
502 
503  }
504 
506  if (value)
507  {
508  /* Don't resolve syslog_host now, better do it per log request. */
509  if (!SetSyslogHost(value))
510  {
511  Log(LOG_LEVEL_ERR, "Failed to set syslog_host, '%s' too long", (const char *)value);
512  }
513  else
514  {
515  Log(LOG_LEVEL_VERBOSE, "Setting syslog_host to '%s'", (const char *)value);
516  }
517  }
518 
520  if (value)
521  {
523  }
524 
526  if (value)
527  {
528  FIPS_MODE = BooleanFromString(value);
529  Log(LOG_LEVEL_VERBOSE, "Setting FIPS mode to to '%s'", FIPS_MODE ? "true" : "false");
530  }
531 
533  if (value)
534  {
535  LASTSEENEXPIREAFTER = IntFromString(value) * 60;
536  }
537 
539  if (value)
540  {
541  double bval;
542  if (DoubleFromString(value, &bval))
543  {
544  bwlimit_kbytes = (uint32_t) ( bval / 1000.0);
545  Log(LOG_LEVEL_VERBOSE, "Setting rate limit to %d kBytes/sec", bwlimit_kbytes);
546  }
547  }
548 
549 }
550 
551 /*********************************************************************/
552 
553 /* Sequence in which server promise types should be evaluated */
554 static const char *const SERVER_TYPESEQUENCE[] =
555 {
556  "meta",
557  "vars",
558  "classes",
559  "roles",
560  "access",
561  NULL
562 };
563 
564 static const char *const COMMON_TYPESEQUENCE[] =
565 {
566  "meta",
567  "vars",
568  "classes",
569  "reports",
570  NULL
571 };
572 
573 /* Check if promise is NOT belonging to default server types
574  * (see SERVER_TYPESEQUENCE)*/
575 static bool IsPromiseTypeNotInTypeSequence(const char *promise_type,
576  const char * const *seq)
577 {
578  for (int type = 0; seq[type] != NULL; type++)
579  {
580  if (strcmp(promise_type, seq[type]) == 0)
581  {
582  return false;
583  }
584  }
585  return true;
586 }
587 
588 static void EvaluateBundle(EvalContext *ctx, const Bundle *bp, const char * const *seq)
589 {
590  EvalContextStackPushBundleFrame(ctx, bp, NULL, false);
591 
592  for (int type = 0; seq[type] != NULL; type++)
593  {
594  const PromiseType *sp = BundleGetPromiseType((Bundle *)bp, seq[type]);
595 
596  /* Some promise types might not be there. */
597  if (!sp || SeqLength(sp->promises) == 0)
598  {
599  Log(LOG_LEVEL_DEBUG, "No promise type %s in bundle %s",
600  seq[type], bp->name);
601  continue;
602  }
603 
605  for (size_t ppi = 0; ppi < SeqLength(sp->promises); ppi++)
606  {
607  Promise *pp = SeqAt(sp->promises, ppi);
609  }
611  }
612 
613  /* Check if we are having some other promise types which we
614  * should evaluate. THIS IS ONLY FOR BACKWARD COMPATIBILITY! */
615  for (size_t j = 0; j < SeqLength(bp->promise_types); j++)
616  {
617  PromiseType *sp = SeqAt(bp->promise_types, j);
618 
619  /* Skipping evaluation of promise as this was evaluated in
620  * loop above. */
621  if (!IsPromiseTypeNotInTypeSequence(sp->name, seq))
622  {
623  Log(LOG_LEVEL_DEBUG, "Skipping subsequent evaluation of "
624  "promise type %s in bundle %s", sp->name, bp->name);
625  continue;
626  }
627 
628  Log(LOG_LEVEL_WARNING, "Trying to evaluate unsupported/obsolete "
629  "promise type %s in %s bundle %s", sp->name, bp->type, bp->name);
630 
632  for (size_t ppi = 0; ppi < SeqLength(sp->promises); ppi++)
633  {
634  Promise *pp = SeqAt(sp->promises, ppi);
636  }
638 
639  }
640 
642 }
643 
644 static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy)
645 {
646  /* Dial up the generic promise expansion with a callback */
647 
649 
650  for (size_t i = 0; i < SeqLength(policy->bundles); i++)
651  {
652  Bundle *bp = SeqAt(policy->bundles, i);
653  bool server_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_SERVER]) == 0;
654  bool common_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_COMMON]) == 0;
655 
656  if (server_bundle || common_bundle)
657  {
658  if (RlistLen(bp->args) > 0)
659  {
661  "Cannot implicitly evaluate bundle '%s %s', as this bundle takes arguments.",
662  bp->type, bp->name);
663  continue;
664  }
665  }
666 
667  if (server_bundle)
668  {
670  }
671 
672  else if (common_bundle)
673  {
675  }
676  }
677 }
678 
679 static PromiseResult KeepServerPromise(EvalContext *ctx, const Promise *pp, ARG_UNUSED void *param)
680 {
681  assert(!param);
682  PromiseBanner(ctx, pp);
683 
684  if (strcmp(pp->parent_promise_type->name, "vars") == 0)
685  {
686  return VerifyVarPromise(ctx, pp, NULL);
687  }
688 
689  if (strcmp(pp->parent_promise_type->name, "classes") == 0)
690  {
691  return VerifyClassPromise(ctx, pp, NULL);
692  }
693 
694  /* Warn if promise locking was used with a promise that doesn't support it.
695  * That applies to both of the below promise types while 'vars' and
696  * 'classes' handle this on their own. */
697  int ifelapsed = PromiseGetConstraintAsInt(ctx, "ifelapsed", pp);
698  if (ifelapsed != CF_NOINT)
699  {
701  "ifelapsed attribute specified in action body for %s promise '%s',"
702  " but %s promises do not support promise locking",
705  }
706  int expireafter = PromiseGetConstraintAsInt(ctx, "expireafter", pp);
707  if (expireafter != CF_NOINT)
708  {
710  "expireafter attribute specified in action body for %s promise '%s',"
711  " but %s promises do not support promise locking",
714  }
715 
716  if (strcmp(pp->parent_promise_type->name, "access") == 0)
717  {
718  const char *resource_type =
719  PromiseGetConstraintAsRval(pp, "resource_type", RVAL_TYPE_SCALAR);
720 
721  /* Default resource_type in access_rules is "path" */
722  if (resource_type == NULL ||
723  strcmp(resource_type, "path") == 0)
724  {
725  KeepFileAccessPromise(ctx, pp);
726  return PROMISE_RESULT_NOOP;
727  }
728  else if (strcmp(resource_type, "literal") == 0)
729  {
730  KeepLiteralAccessPromise(ctx, pp, "literal");
731  return PROMISE_RESULT_NOOP;
732  }
733  else if (strcmp(resource_type, "variable") == 0)
734  {
735  KeepLiteralAccessPromise(ctx, pp, "variable");
736  return PROMISE_RESULT_NOOP;
737  }
738  else if (strcmp(resource_type, "query") == 0)
739  {
740  KeepQueryAccessPromise(ctx, pp);
742  return PROMISE_RESULT_NOOP;
743  }
744  else if (strcmp(resource_type, "context") == 0)
745  {
746  KeepLiteralAccessPromise(ctx, pp, "context");
747  return PROMISE_RESULT_NOOP;
748  }
749  else if (strcmp(resource_type, "bundle") == 0)
750  {
751  KeepBundlesAccessPromise(ctx, pp);
752  return PROMISE_RESULT_NOOP;
753  }
754  }
755  else if (strcmp(pp->parent_promise_type->name, "roles") == 0)
756  {
757  KeepServerRolePromise(ctx, pp);
758  return PROMISE_RESULT_NOOP;
759  }
760 
761  return PROMISE_RESULT_NOOP;
762 }
763 
764 /*********************************************************************/
765 
767 {
772 };
773 
774 /* Check if the given string is an IP subnet, a hostname, a key, or none of
775  * the above. */
776 static enum admit_type AdmitType(const char *s)
777 {
778  if (strncmp(s, "SHA=", strlen("SHA=")) == 0 ||
779  strncmp(s, "MD5=", strlen("MD5=")) == 0)
780  {
781  return ADMIT_TYPE_KEY;
782  }
783  /* IPv4 or IPv6 subnet mask or regex. */
784  /* TODO change this to "0123456789abcdef.:/", no regex allowed. */
785  else if (s[strspn(s, "0123456789abcdef.:/[-]*()\\")] == '\0')
786  {
787  return ADMIT_TYPE_IP;
788  }
789  else
790  {
791  return ADMIT_TYPE_HOSTNAME;
792  }
793 }
794 
795 /**
796  * Map old-style regex-or-hostname #host to new-style host-or-domain
797  * and append it to #sl.
798  *
799  * Old-style ACLs could include regexes to be matched against host
800  * names; but new-style ones only support sub-domain matching. If the
801  * old-style host regex looks like ".*\.sub\.domain\.tld" we can take
802  * it in as ".sub.domain.tld"; otherwise, we can only really map exact
803  * match hostnames. However, we know some old policy (including our
804  * own masterfiles) had cases of .*sub.domain.tld and it's possible
805  * that someone might include a new-style .sub.domain.tld by mistake
806  * in an (old-style) accept list; so cope with these cases, too.
807  *
808  * @param sl The string-list to which to add entries.
809  * @param host The name-or-regex to add to the ACL.
810  * @return An index at which an entry was added to the list (there may
811  * be another), or -1 if nothing added.
812  */
813 static size_t StrList_AppendRegexHostname(StrList **sl, const char *host)
814 {
815  if (IsRegex(host))
816  {
817  if (host[strcspn(host, "({[|+?]})")] != '\0')
818  {
819  return -1; /* Not a regex we can sensibly massage; discard. */
820  }
821  bool skip[2] = { false, false }; /* { domain, host } passes below */
822  const char *name = host;
823  if (name[0] == '^') /* Was always implicit; but read as hint to intent. */
824  {
825  /* Default to skipping domain-form if anchored explicitly: */
826  skip[0] = true; /* Over-ridden below if followed by .* of course. */
827  name++;
828  }
829  if (StringStartsWith(name, ".*"))
830  {
831  skip[0] = false; /* Domain-form should match */
832  name += 2;
833  }
834  if (StringStartsWith(name, "\\."))
835  {
836  /* Skip host-form, as the regex definitely wants something
837  * before the given name. */
838  skip[1] = true;
839  name += 2;
840  }
841  if (strchr(name, '*') != NULL)
842  {
843  /* Can't handle a * later than the preamble. */
844  return (size_t) -1;
845  }
846 
847  if (name > host ||
848  strchr(host, '\\') != NULL)
849  {
850  /* 2: leading '.' and final '\0' */
851  char copy[2 + strlen(name)], *c = copy;
852  c++[0] = '.'; /* For domain-form; and copy+1 gives host-form. */
853  /* Now copy the rest of the name, de-regex-ifying as we go: */
854  for (const char *p = name; p[0] != '\0'; p++)
855  {
856  if (p[0] == '\\')
857  {
858  p++;
859  if (p[0] != '.')
860  {
861  /* Regex includes a non-dot escape */
862  return (size_t) -1;
863  }
864  }
865 #if 0
866  else if (p[0] == '.')
867  {
868  /* In principle, this is a special character; but
869  * it may just be an unescaped dot, so let it be. */
870  }
871 #endif
872  c++[0] = p[0];
873  }
874  assert(c < copy + sizeof(copy));
875  c[0] = '\0';
876 
877  /* Now, for host then domain, add entry if suitable */
878  int pass = 2;
879  size_t ret = -1;
880  while (pass > 0)
881  {
882  pass--;
883  if (!skip[pass]) /* pass 0 is domain, pass 1 is host */
884  {
885  ret = StrList_Append(sl, copy + pass);
886  }
887  }
888  return ret;
889  }
890 
891  /* IsRegex() is true but we treat it just as a name! */
892  }
893  /* Just a simple host name. */
894 
895  return StrList_Append(sl, host);
896 }
897 
898 bool NEED_REVERSE_LOOKUP = false;
899 
900 static void TurnOnReverseLookups()
901 {
902  if (!NEED_REVERSE_LOOKUP)
903  {
905  "Found hostname admit/deny in access_rules, "
906  "turning on reverse DNS lookups for every connection");
907  NEED_REVERSE_LOOKUP = true;
908  }
909 
910 }
911 
912 static size_t racl_SmartAppend(struct admitdeny_acl *ad, const char *entry)
913 {
914  size_t ret;
915 
916  switch (AdmitType(entry))
917  {
918 
919  case ADMIT_TYPE_IP:
920  /* TODO convert IP string to binary representation. */
921  ret = StrList_Append(&ad->ips, entry);
922  break;
923 
924  case ADMIT_TYPE_KEY:
925  ret = StrList_Append(&ad->keys, entry);
926  break;
927 
928  case ADMIT_TYPE_HOSTNAME:
929  ret = StrList_AppendRegexHostname(&ad->hostnames, entry);
930 
931  /* If any hostname rule got added,
932  * turn on reverse DNS lookup in the new protocol. */
933  if (ret != (size_t) -1)
934  {
936  }
937 
938  break;
939 
940  default:
942  "Access rule 'admit: %s' is not IP, hostname or key, ignoring",
943  entry);
944  ret = (size_t) -1;
945  }
946 
947  return ret;
948 }
949 
950 /* Package hostname as regex, if needed.
951  *
952  * @param old The old Auth structure to which to add.
953  * @param host The new acl_hostnames entry to add to it.
954  */
955 static void NewHostToOldACL(Auth *old, const char *host)
956 {
957  if (host[0] == '.') /* Domain - transform to regex: */
958  {
959  int extra = 2; /* For leading ".*" */
960  const char *dot = host;
961 
962  do
963  {
964  do
965  {
966  dot++; /* Step over prior dot. */
967  } while (dot[0] == '.'); /* Treat many dots as one. */
968  extra++; /* For a backslash before the dot */
969  dot = strchr(dot, '.');
970  } while (dot);
971 
972  char regex[strlen(host) + extra], *dst = regex;
973  dst++[0] = '.';
974  dst++[0] = '*';
975 
976  dot = host;
977  do
978  {
979  /* Insert literal dot. */
980  assert(dot[0] == '.');
981  dst++[0] = '\\';
982  dst++[0] = '.';
983 
984  do /* Step over prior dot(s), as before. */
985  {
986  dot++;
987  } while (dot[0] == '.');
988 
989  /* Identify next fragment: */
990  const char *d = strchr(dot, '.');
991  size_t len = d ? d - dot : strlen(dot);
992 
993  /* Copy fragment: */
994  memcpy(dst, dot, len);
995  dst += len;
996 
997  /* Advance: */
998  dot = d;
999  } while (dot);
1000 
1001  /* Terminate: */
1002  assert(dst < regex + sizeof(regex));
1003  dst[0] = '\0';
1004 
1005  /* Add to list: */
1006  PrependItem(&(old->accesslist), regex, NULL);
1007  }
1008  else
1009  {
1010  /* Simple host-name; just add it: */
1011  PrependItem(&(old->accesslist), host, NULL);
1012  }
1013 }
1014 
1015 /**
1016  * Add access rules to the given ACL #acl according to the constraints in the
1017  * particular access promise.
1018  *
1019  * For legacy reasons (non-TLS connections), build also the #ap (access Auth)
1020  * and #dp (deny Auth), if they are not NULL.
1021  */
1023  const Promise *pp,
1024  struct resource_acl *racl,
1025  Auth *ap, Auth *dp)
1026 {
1027  for (size_t i = 0; i < SeqLength(pp->conlist); i++)
1028  {
1029  const Constraint *cp = SeqAt(pp->conlist, i);
1030  size_t ret = -2;
1031 
1032  if (!IsDefinedClass(ctx, cp->classes))
1033  {
1034  continue;
1035  }
1036 
1037  switch (cp->rval.type)
1038  {
1039 #define IsAccessBody(e) (strcmp(cp->lval, CF_REMACCESS_BODIES[e].lval) == 0)
1040 
1041  case RVAL_TYPE_SCALAR:
1042 
1043  if (ap != NULL &&
1045  {
1046  ap->encrypt = BooleanFromString(cp->rval.item);
1047  }
1049  {
1050  const char *shortcut = cp->rval.item;
1051 
1052  if (strchr(shortcut, FILE_SEPARATOR) != NULL)
1053  {
1055  "slashes are forbidden in ACL shortcut: %s",
1056  shortcut);
1057  }
1058  else if (StringMapHasKey(SERVER_ACCESS.path_shortcuts, shortcut))
1059  {
1061  "Already existing shortcut for path '%s' was replaced",
1062  pp->promiser);
1063  }
1064  else
1065  {
1067  xstrdup(shortcut), xstrdup(pp->promiser));
1068 
1069  Log(LOG_LEVEL_DEBUG, "Added shortcut '%s' for path: %s",
1070  shortcut, pp->promiser);
1071  }
1072  }
1073  break;
1074 
1075  case RVAL_TYPE_LIST:
1076 
1077  for (const Rlist *rp = (const Rlist *) cp->rval.item;
1078  rp != NULL; rp = rp->next)
1079  {
1080  /* TODO keys, ips, hostnames are valid such strings. */
1081 
1083  {
1084  ret = StrList_Append(&racl->admit.ips, RlistScalarValue(rp));
1085  if (ap != NULL)
1086  {
1088  }
1089  }
1091  {
1092  ret = StrList_Append(&racl->deny.ips, RlistScalarValue(rp));
1093  if (dp != NULL)
1094  {
1096  }
1097  }
1099  {
1100  ret = StrList_Append(&racl->admit.hostnames, RlistScalarValue(rp));
1101  /* If any hostname rule got added,
1102  * turn on reverse DNS lookup in the new protocol. */
1103  if (ret != (size_t) -1)
1104  {
1106  }
1107  if (ap != NULL)
1108  {
1110  }
1111  }
1113  {
1114  ret = StrList_Append(&racl->deny.hostnames, RlistScalarValue(rp));
1115  /* If any hostname rule got added,
1116  * turn on reverse DNS lookup in the new protocol. */
1117  if (ret != (size_t) -1)
1118  {
1120  }
1121  if (dp != NULL)
1122  {
1124  }
1125  }
1127  {
1128  ret = StrList_Append(&racl->admit.keys, RlistScalarValue(rp));
1129  }
1131  {
1132  ret = StrList_Append(&racl->deny.keys, RlistScalarValue(rp));
1133  }
1134  /* Legacy stuff */
1136  {
1137  ret = racl_SmartAppend(&racl->admit, RlistScalarValue(rp));
1138  if (ap != NULL)
1139  {
1141  }
1142  }
1143  else if (IsAccessBody(REMOTE_ACCESS_DENY))
1144  {
1145  ret = racl_SmartAppend(&racl->deny, RlistScalarValue(rp));
1146  if (dp != NULL)
1147  {
1149  }
1150  }
1151  else if (ap != NULL && IsAccessBody(REMOTE_ACCESS_MAPROOT))
1152  {
1153  PrependItem(&(ap->maproot), RlistScalarValue(rp), NULL);
1154  }
1155  }
1156 
1157  if (ret == (size_t) -1)
1158  {
1159  /* Should never happen, besides when allocation fails. */
1160  Log(LOG_LEVEL_CRIT, "StrList_Append: %s", GetErrorStr());
1161  DoCleanupAndExit(255);
1162  }
1163 
1164  break;
1165 
1166  default:
1167  UnexpectedError("Unknown constraint type!");
1168  break;
1169 
1170 #undef IsAccessBody
1171  }
1172  }
1173 
1174  StrList_Finalise(&racl->admit.ips);
1175  StrList_Sort(racl->admit.ips, string_Compare);
1176 
1177  StrList_Finalise(&racl->admit.hostnames);
1178  StrList_Sort(racl->admit.hostnames, string_CompareFromEnd);
1179 
1180  StrList_Finalise(&racl->admit.keys);
1181  StrList_Sort(racl->admit.keys, string_Compare);
1182 
1183  StrList_Finalise(&racl->deny.ips);
1184  StrList_Sort(racl->deny.ips, string_Compare);
1185 
1186  StrList_Finalise(&racl->deny.hostnames);
1187  StrList_Sort(racl->deny.hostnames, string_CompareFromEnd);
1188 
1189  StrList_Finalise(&racl->deny.keys);
1190  StrList_Sort(racl->deny.keys, string_Compare);
1191 }
1192 
1193 /* It is allowed to have duplicate handles (paths or class names or variables
1194  * etc) in bundle server access_rules in policy files, but the lists here
1195  * should have unique entries. This, we make sure here. */
1196 static Auth *GetOrCreateAuth(const char *handle, Auth **authchain, Auth **authchain_tail)
1197 {
1198  Auth *a = GetAuthPath(handle, *authchain);
1199 
1200  if (!a)
1201  {
1202  InstallServerAuthPath(handle, authchain, authchain_tail);
1203  a = GetAuthPath(handle, *authchain);
1204  }
1205 
1206  return a;
1207 }
1208 
1209 static void KeepFileAccessPromise(const EvalContext *ctx, const Promise *pp)
1210 {
1211  char path[PATH_MAX];
1212  size_t path_len = strlen(pp->promiser);
1213  if (path_len > sizeof(path) - 1)
1214  {
1215  goto err_too_long;
1216  }
1217  memcpy(path, pp->promiser, path_len + 1);
1218 
1219  /* Resolve symlinks and canonicalise access_rules path. */
1220  size_t ret2 = PreprocessRequestPath(path, sizeof(path));
1221 
1222  if (ret2 == (size_t) -1)
1223  {
1224  if (errno != ENOENT) /* something went wrong */
1225  {
1227  "Failed to canonicalize path '%s' in access_rules, ignoring!",
1228  pp->promiser);
1229  return;
1230  }
1231  else /* file does not exist, it doesn't matter */
1232  {
1234  "Path does not exist, it's added as-is in access rules: %s",
1235  path);
1237  "WARNING: this means that (not) having a trailing slash defines if it's (not) a directory!");
1238  /* Legacy: convert trailing "/." to "/" */
1239  if (path_len >= 2 &&
1240  path[path_len - 1] == '.' &&
1241  path[path_len - 2] == '/')
1242  {
1243  path[path_len - 1] = '\0';
1244  path_len--;
1245  }
1246  }
1247  }
1248  else /* file exists, path canonicalised */
1249  {
1250  /* If it's a directory append trailing '/' */
1251  path_len = ret2;
1252  bool is_dir = IsDirReal(path);
1253  if (is_dir && path[path_len - 1] != FILE_SEPARATOR)
1254  {
1255  if (path_len + 2 > sizeof(path))
1256  {
1257  goto err_too_long;
1258  }
1259  PathAppendTrailingSlash(path, path_len);
1260  path_len++;
1261  }
1262  }
1263 
1264  size_t pos = acl_SortedInsert(&paths_acl, path);
1265  if (pos == (size_t) -1)
1266  {
1267  /* Should never happen, besides when allocation fails. */
1268  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1269  DoCleanupAndExit(255);
1270  }
1271 
1272  /* Legacy code */
1273  if (path_len != 1)
1274  {
1275  DeleteSlash(path);
1276  }
1279 
1281  ap, dp);
1282  return;
1283 
1284  err_too_long:
1286  "Path '%s' in access_rules is too long (%zu > %d), ignoring!",
1287  pp->promiser, strlen(pp->promiser), PATH_MAX);
1288  return;
1289 }
1290 
1291 /*********************************************************************/
1292 
1293 void KeepLiteralAccessPromise(EvalContext *ctx, const Promise *pp, const char *type)
1294 {
1295  Auth *ap, *dp;
1296  const char *handle = PromiseGetHandle(pp);
1297 
1298  if (handle == NULL && strcmp(type, "literal") == 0)
1299  {
1300  Log(LOG_LEVEL_ERR, "Access to literal server data requires you to define a promise handle for reference");
1301  return;
1302  }
1303 
1304  if (strcmp(type, "literal") == 0)
1305  {
1306  Log(LOG_LEVEL_VERBOSE,"Looking at literal access promise '%s', type '%s'", pp->promiser, type);
1307 
1310 
1311  RegisterLiteralServerData(ctx, handle, pp);
1312  ap->literal = true;
1313 
1314 
1315  size_t pos = acl_SortedInsert(&literals_acl, handle);
1316  if (pos == (size_t) -1)
1317  {
1318  /* Should never happen, besides when allocation fails. */
1319  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1320  DoCleanupAndExit(255);
1321  }
1322 
1324  ap, dp);
1325  }
1326  else
1327  {
1328  Log(LOG_LEVEL_VERBOSE,"Looking at context/var access promise '%s', type '%s'", pp->promiser, type);
1329 
1332 
1333  if (strcmp(type, "context") == 0)
1334  {
1335  ap->classpattern = true;
1336 
1337  size_t pos = acl_SortedInsert(&classes_acl, pp->promiser);
1338  if (pos == (size_t) -1)
1339  {
1340  /* Should never happen, besides when allocation fails. */
1341  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1342  DoCleanupAndExit(255);
1343  }
1344 
1346  ap, dp);
1347  }
1348  else if (strcmp(type, "variable") == 0)
1349  {
1350  ap->variable = true;
1351 
1352  size_t pos = acl_SortedInsert(&vars_acl, pp->promiser);
1353  if (pos == (size_t) -1)
1354  {
1355  /* Should never happen, besides when allocation fails. */
1356  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1357  DoCleanupAndExit(255);
1358  }
1359 
1361  ap, dp);
1362  }
1363  }
1364 }
1365 
1366 /*********************************************************************/
1367 
1368 static void KeepQueryAccessPromise(EvalContext *ctx, const Promise *pp)
1369 {
1372 
1373  RegisterLiteralServerData(ctx, pp->promiser, pp);
1374  ap->literal = true;
1375 
1376  size_t pos = acl_SortedInsert(&query_acl, pp->promiser);
1377  if (pos == (size_t) -1)
1378  {
1379  /* Should never happen, besides when allocation fails. */
1380  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1381  DoCleanupAndExit(255);
1382  }
1383 
1385  ap, dp);
1386 }
1387 
1388 static void KeepBundlesAccessPromise(EvalContext *ctx, const Promise *pp)
1389 {
1390  size_t pos = acl_SortedInsert(&bundles_acl, pp->promiser);
1391  if (pos == (size_t) -1)
1392  {
1393  /* Should never happen, besides when allocation fails. */
1394  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1395  DoCleanupAndExit(255);
1396  }
1397 
1398  /* Last params are NULL because we don't have
1399  * old-school Auth type ACLs here. */
1401  NULL, NULL);
1402 }
1403 /*********************************************************************/
1404 
1405 /**
1406  * The "roles" access promise is for remote class activation by means of
1407  * cf-runagent -D:
1408  *
1409  * pp->promiser is a regex to match classes.
1410  * pp->conlist is an slist of usernames.
1411  */
1412 static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp)
1413 {
1414  size_t pos = acl_SortedInsert(&roles_acl, pp->promiser);
1415  if (pos == (size_t) -1)
1416  {
1417  /* Should never happen, besides when allocation fails. */
1418  Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
1419  DoCleanupAndExit(255);
1420  }
1421 
1422  size_t i = SeqLength(pp->conlist);
1423  while (i > 0)
1424  {
1425  i--;
1426  Constraint *cp = SeqAt(pp->conlist, i);
1427  char const * const authorizer =
1429 
1430  if (strcmp(cp->lval, authorizer) == 0)
1431  {
1432  if (cp->rval.type != RVAL_TYPE_LIST)
1433  {
1435  "Right-hand side of authorize promise for '%s' should be a list",
1436  pp->promiser);
1437  }
1438  else if (IsDefinedClass(ctx, cp->classes))
1439  {
1440  for (const Rlist *rp = cp->rval.item; rp != NULL; rp = rp->next)
1441  {
1442  /* The "roles" access promise currently only supports
1443  * listing usernames to admit access to, nothing more. */
1444  struct resource_acl *racl = &roles_acl->acls[pos];
1445  size_t zret = StrList_Append(&racl->admit.usernames,
1446  RlistScalarValue(rp));
1447  if (zret == (size_t) -1)
1448  {
1449  /* Should never happen, besides when allocation fails. */
1450  Log(LOG_LEVEL_CRIT, "StrList_Append: %s", GetErrorStr());
1451  DoCleanupAndExit(255);
1452  }
1453  }
1454  }
1455  }
1456  else if (strcmp(cp->lval, "comment") != 0 &&
1457  strcmp(cp->lval, "handle") != 0 &&
1458  /* Are there other known list constraints ? if not, skip this: */
1459  cp->rval.type != RVAL_TYPE_LIST)
1460  {
1462  "Unrecognised promise '%s' for %s",
1463  cp->lval, pp->promiser);
1464  }
1465  }
1466 }
1467 
1468 static void InstallServerAuthPath(const char *path, Auth **list, Auth **listtail)
1469 {
1470  Auth **nextp = *listtail ? &((*listtail)->next) : list;
1471  assert(*nextp == NULL);
1472  *listtail = *nextp = xcalloc(1, sizeof(Auth));
1473  (*nextp)->path = xstrdup(path);
1474 
1475 #ifdef __MINGW32__
1476  for (char *p = (*nextp)->path; *p != '\0'; p++)
1477  {
1478  *p = ToLower(*p);
1479  }
1480 #endif /* __MINGW32__ */
1481 }
1482 
1483 static Auth *GetAuthPath(const char *path, Auth *list)
1484 {
1485  size_t path_len = strlen(path);
1486  char unslashed_path[path_len + 1];
1487  memcpy(unslashed_path, path, path_len + 1);
1488 
1489 #ifdef __MINGW32__
1490  ToLowerStrInplace(unslashed_path);
1491 #endif
1492 
1493  if (path_len != 1)
1494  {
1495  DeleteSlash(unslashed_path);
1496  }
1497 
1498  for (Auth *ap = list; ap != NULL; ap = ap->next)
1499  {
1500  if (strcmp(ap->path, unslashed_path) == 0)
1501  {
1502  return ap;
1503  }
1504  }
1505 
1506  return NULL;
1507 }
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
#define ARG_UNUSED
Definition: cf-net.c:47
void KeepReportDataSelectAccessPromise(const Promise *pp)
void CleanReportBookFilterSet()
void RegisterLiteralServerData(EvalContext *ctx, const char *handle, const Promise *pp)
@ COMMON_CONTROL_FIPS_MODE
Definition: cf3.defs.h:430
@ COMMON_CONTROL_SYSLOG_HOST
Definition: cf3.defs.h:428
@ COMMON_CONTROL_BWLIMIT
Definition: cf3.defs.h:431
@ COMMON_CONTROL_LASTSEEN_EXPIRE_AFTER
Definition: cf3.defs.h:422
@ COMMON_CONTROL_SYSLOG_PORT
Definition: cf3.defs.h:429
@ RVAL_TYPE_LIST
Definition: cf3.defs.h:607
@ RVAL_TYPE_SCALAR
Definition: cf3.defs.h:606
PromiseResult
Definition: cf3.defs.h:122
@ PROMISE_RESULT_NOOP
Definition: cf3.defs.h:124
@ AGENT_TYPE_SERVER
Definition: cf3.defs.h:403
@ AGENT_TYPE_COMMON
Definition: cf3.defs.h:401
#define CF_NOINT
Definition: cf3.defs.h:339
long LASTSEENEXPIREAFTER
Definition: cf3globals.c:49
bool FIPS_MODE
Definition: cf3globals.c:36
const char *const CF_AGENTTYPES[]
Definition: constants.c:65
void SetBindInterface(const char *ip)
Definition: net.c:40
void DoCleanupAndExit(int ret)
Definition: cleanup.c:57
bool SetCfenginePort(const char *port_str)
Definition: client_code.c:107
bool DoubleFromString(const char *s, double *value_out)
Definition: conversion.c:521
long IntFromString(const char *s)
Definition: conversion.c:390
bool BooleanFromString(const char *s)
Definition: conversion.c:354
void DBSetMaximumConcurrentTransactions(int max_txn)
Definition: dbm_api.c:365
size_t EnterpriseGetMaxCfHubProcesses()
void EvalContextStackPushPromiseTypeFrame(EvalContext *ctx, const PromiseType *owner)
const void * EvalContextVariableControlCommonGet(const EvalContext *ctx, CommonControl lval)
void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, const Rlist *args, bool inherits_previous)
const void * EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, DataType *type_out)
void EvalContextStackPopFrame(EvalContext *ctx)
void SetChecksumUpdatesDefault(EvalContext *ctx, bool enabled)
static bool IsDefinedClass(const EvalContext *ctx, const char *context)
Definition: eval_context.h:213
void PolicyResolve(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
Definition: expand.c:1065
PromiseResult ExpandPromise(EvalContext *ctx, const Promise *pp, PromiseActuator *act_on_promise, void *param)
Definition: expand.c:257
bool IsDirReal(const char *path)
Definition: file_lib.c:314
#define FILE_SEPARATOR
Definition: file_lib.h:102
void DeleteSlash(char *str)
Definition: files_names.c:320
void SetFacility(const char *retval)
Seq * ControlBodyConstraints(const Policy *policy, AgentType agent)
int errno
#define NULL
Definition: getopt1.c:56
bool IsItemIn(const Item *list, const char *item)
Definition: item_lib.c:226
Item * PrependItem(Item **liststart, const char *itemstring, const char *classes)
Definition: item_lib.c:372
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_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_WARNING
Definition: logging.h:43
@ LOG_LEVEL_CRIT
Definition: logging.h:41
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
bool StringMapHasKey(const StringMap *map, const char *key)
Definition: map.c:359
bool StringMapInsert(const StringMap *map, char *key, char *value)
Definition: map.c:359
StringMap * StringMapNew(void)
Definition: map.c:359
bool IsRegex(const char *str)
Definition: matching.c:96
#define UnexpectedError(...)
Definition: misc_lib.h:38
const ConstraintSyntax CF_REMROLE_BODIES[REMOTE_ROLE_NONE+1]
Definition: mod_access.c:97
@ REMOTE_ACCESS_IFENCRYPTED
Definition: mod_access.h:41
@ REMOTE_ACCESS_ADMITHOSTNAMES
Definition: mod_access.h:36
@ REMOTE_ACCESS_ADMITKEYS
Definition: mod_access.h:38
@ REMOTE_ACCESS_DENYKEYS
Definition: mod_access.h:39
@ REMOTE_ACCESS_ADMIT
Definition: mod_access.h:32
@ REMOTE_ACCESS_DENYIPS
Definition: mod_access.h:35
@ REMOTE_ACCESS_DENYHOSTNAMES
Definition: mod_access.h:37
@ REMOTE_ACCESS_MAPROOT
Definition: mod_access.h:40
@ REMOTE_ACCESS_DENY
Definition: mod_access.h:33
@ REMOTE_ACCESS_ADMITIPS
Definition: mod_access.h:34
@ REMOTE_ACCESS_SHORTCUT
Definition: mod_access.h:44
@ REMOTE_ROLE_AUTHORIZE
Definition: mod_access.h:50
@ SERVER_CONTROL_LOG_ALL_CONNECTIONS
Definition: mod_common.h:46
@ SERVER_CONTROL_DENY_BAD_CLOCKS
Definition: mod_common.h:41
@ SERVER_CONTROL_ALLOW_ALL_CONNECTS
Definition: mod_common.h:33
@ SERVER_CONTROL_SERVER_FACILITY
Definition: mod_common.h:50
@ SERVER_CONTROL_LISTEN
Definition: mod_common.h:53
@ SERVER_CONTROL_ALLOW_USERS
Definition: mod_common.h:35
@ SERVER_CONTROL_TRUST_KEYS_FROM
Definition: mod_common.h:52
@ SERVER_CONTROL_DENY_CONNECTS
Definition: mod_common.h:42
@ SERVER_CONTROL_SKIP_VERIFY
Definition: mod_common.h:51
@ SERVER_CONTROL_CALL_COLLECT_WINDOW
Definition: mod_common.h:40
@ SERVER_CONTROL_ALLOW_CONNECTS
Definition: mod_common.h:34
@ SERVER_CONTROL_ALLOWCIPHERS
Definition: mod_common.h:54
@ SERVER_CONTROL_MAX_CONNECTIONS
Definition: mod_common.h:48
@ SERVER_CONTROL_PORT_NUMBER
Definition: mod_common.h:49
@ SERVER_CONTROL_ALLOWLEGACYCONNECTS
Definition: mod_common.h:55
@ SERVER_CONTROL_CALL_COLLECT_INTERVAL
Definition: mod_common.h:39
@ SERVER_CONTROL_LOG_ENCRYPTED_TRANSFERS
Definition: mod_common.h:47
@ SERVER_CONTROL_BIND_TO_INTERFACE
Definition: mod_common.h:37
@ SERVER_CONTROL_ALLOWTLSVERSION
Definition: mod_common.h:56
@ SERVER_CONTROL_CFRUNCOMMAND
Definition: mod_common.h:38
uint32_t bwlimit_kbytes
Definition: net.c:302
void PromiseBanner(EvalContext *ctx, const Promise *pp)
Definition: ornaments.c:127
void Banner(const char *s)
Definition: ornaments.c:219
#define PATH_MAX
Definition: platform.h:176
const char * PromiseGetHandle(const Promise *pp)
Return handle of the promise.
Definition: policy.c:2713
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
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
const PromiseType * BundleGetPromiseType(const Bundle *bp, const char *name)
Definition: policy.c:1600
char * RlistScalarValue(const Rlist *rlist)
Definition: rlist.c:83
int RlistLen(const Rlist *start)
Definition: rlist.c:672
size_t SeqLength(const Seq *seq)
Length of the sequence.
Definition: sequence.c:354
static void * SeqAt(const Seq *seq, int i)
Definition: sequence.h:57
char CFRUNCOMMAND[1024]
Definition: server.c:81
ServerAccess SERVER_ACCESS
Definition: server.c:79
struct acl * classes_acl
Definition: server_access.c:40
void acl_Summarise(const struct acl *acl, const char *title)
size_t acl_SortedInsert(struct acl **a, const char *handle)
struct acl * paths_acl
Definition: server_access.c:39
struct acl * roles_acl
Definition: server_access.c:45
struct acl * query_acl
Definition: server_access.c:43
struct acl * literals_acl
Definition: server_access.c:42
struct acl * bundles_acl
Definition: server_access.c:44
struct acl * vars_acl
Definition: server_access.c:41
bool PathAppendTrailingSlash(char *s, size_t s_len)
size_t PreprocessRequestPath(char *reqpath, size_t reqpath_size)
static void KeepBundlesAccessPromise(EvalContext *ctx, const Promise *pp)
int MAXTRIES
Definition: server.c:73
static void KeepQueryAccessPromise(EvalContext *ctx, const Promise *pp)
static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp)
int COLLECT_WINDOW
Definition: server.c:76
static Auth * GetOrCreateAuth(const char *handle, Auth **authchain, Auth **authchain_tail)
bool DENYBADCLOCKS
Definition: server.c:72
void Summarize()
static size_t racl_SmartAppend(struct admitdeny_acl *ad, const char *entry)
static void AccessPromise_AddAccessConstraints(const EvalContext *ctx, const Promise *pp, struct resource_acl *racl, Auth *ap, Auth *dp)
int CFD_MAXPROCESSES
Definition: server.c:71
static PromiseResult KeepServerPromise(EvalContext *ctx, const Promise *pp, void *param)
static enum admit_type AdmitType(const char *s)
bool NEED_REVERSE_LOOKUP
static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy)
static void InstallServerAuthPath(const char *path, Auth **list, Auth **listtail)
static bool SetMaxOpenFiles(int n)
static void NewHostToOldACL(Auth *old, const char *host)
bool LOGENCRYPT
Definition: server.c:74
static void KeepLiteralAccessPromise(EvalContext *ctx, const Promise *pp, const char *type)
#define IsControlBody(e)
static Auth * GetAuthPath(const char *path, Auth *list)
bool SERVER_LISTEN
Definition: server.c:77
int COLLECT_INTERVAL
Definition: server.c:75
static const char *const COMMON_TYPESEQUENCE[]
static size_t StrList_AppendRegexHostname(StrList **sl, const char *host)
static void KeepFileAccessPromise(const EvalContext *ctx, const Promise *pp)
static bool IsPromiseTypeNotInTypeSequence(const char *promise_type, const char *const *seq)
static const char *const SERVER_TYPESEQUENCE[]
static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
static void EvaluateBundle(EvalContext *ctx, const Bundle *bp, const char *const *seq)
void KeepPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
admit_type
@ ADMIT_TYPE_OTHER
@ ADMIT_TYPE_KEY
@ ADMIT_TYPE_HOSTNAME
@ ADMIT_TYPE_IP
#define IsAccessBody(e)
int NO_FORK
Definition: env_monitor.c:94
static void TurnOnReverseLookups()
bool StringStartsWith(const char *str, const char *prefix)
Check if a string starts with the given prefix.
Definition: string_lib.c:1335
char ToLower(char ch)
Definition: string_lib.c:119
void ToLowerStrInplace(char *str)
Definition: string_lib.c:162
int string_CompareFromEnd(const struct string **sp1, const struct string **sp2)
Definition: strlist.c:130
size_t StrList_Append(StrList **sl, const char *s)
Definition: strlist.c:298
int string_Compare(const struct string **sp1, const struct string **sp2)
Definition: strlist.c:83
void StrList_Sort(StrList *sl, StringComparatorF comparator)
Definition: strlist.c:383
void StrList_Finalise(StrList **sl)
Definition: strlist.c:324
Definition: server.h:44
Auth * next
Definition: server.h:54
Item * accesslist
Definition: server.h:50
int variable
Definition: server.h:48
int literal
Definition: server.h:46
int classpattern
Definition: server.h:47
Item * maproot
Definition: server.h:51
int encrypt
Definition: server.h:52
char * path
Definition: server.h:45
Definition: policy.h:70
char * name
Definition: policy.h:74
char * type
Definition: policy.h:73
Seq * promise_types
Definition: policy.h:78
Rlist * args
Definition: policy.h:76
const char * lval
Definition: cf3.defs.h:656
Rval rval
Definition: policy.h:133
char * classes
Definition: policy.h:135
char * lval
Definition: policy.h:132
Definition: item_lib.h:33
Item * next
Definition: item_lib.h:38
char * name
Definition: item_lib.h:34
Definition: policy.h:53
Seq * bundles
Definition: policy.h:56
Seq * promises
Definition: policy.h:104
char * name
Definition: policy.h:103
PromiseType * parent_promise_type
Definition: policy.h:111
Seq * conlist
Definition: policy.h:117
char * promiser
Definition: policy.h:115
Definition: rlist.h:35
RvalType type
Definition: cf3.defs.h:616
void * item
Definition: cf3.defs.h:615
Sequence data-structure.
Definition: sequence.h:50
Item * multiconnlist
Definition: server.h:65
Item * trustkeylist
Definition: server.h:66
int logconns
Definition: server.h:83
Auth * deny
Definition: server.h:74
Item * allowuserlist
Definition: server.h:64
Auth * varadmit
Definition: server.h:78
StringMap * path_shortcuts
Definition: server.h:87
Auth * denytail
Definition: server.h:75
Auth * admittail
Definition: server.h:73
Auth * varadmittail
Definition: server.h:79
char * allowciphers
Definition: server.h:68
Item * nonattackerlist
Definition: server.h:62
Auth * vardeny
Definition: server.h:80
Auth * vardenytail
Definition: server.h:81
Item * allowlegacyconnects
Definition: server.h:67
Item * attackerlist
Definition: server.h:63
char * allowtlsversion
Definition: server.h:69
Auth * admit
Definition: server.h:72
struct acl::resource_acl acls[]
StrList * hostnames
Definition: server_access.h:47
StrList * keys
Definition: server_access.h:48
StrList * ips
Definition: server_access.h:46
void SetSyslogPort(uint16_t port)
Definition: syslog_client.c:62
bool SetSyslogHost(const char *host)
Definition: syslog_client.c:49
VarRef * VarRefParseFromScope(const char *var_ref_string, const char *scope)
void VarRefDestroy(VarRef *ref)
PromiseResult VerifyClassPromise(EvalContext *ctx, const Promise *pp, void *param)
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, void *param)
Definition: verify_vars.c:109