1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
|
/*
Copyright 2024 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_EVAL_CONTEXT_H
#define CFENGINE_EVAL_CONTEXT_H
#include <platform.h>
#include <writer.h>
#include <set.h>
#include <sequence.h>
#include <var_expressions.h>
#include <logic_expressions.h>
#include <scope.h>
#include <variable.h>
#include <class.h>
#include <iteration.h>
#include <rb-tree.h>
#include <ring_buffer.h>
#include <generic_agent.h>
typedef enum
{
STACK_FRAME_TYPE_BUNDLE,
STACK_FRAME_TYPE_BODY,
STACK_FRAME_TYPE_BUNDLE_SECTION,
STACK_FRAME_TYPE_PROMISE,
STACK_FRAME_TYPE_PROMISE_ITERATION,
STACK_FRAME_TYPE_MAX
} StackFrameType;
typedef struct
{
const Bundle *owner;
ClassTable *classes;
VariableTable *vars;
} StackFrameBundle;
typedef struct
{
const Body *owner;
VariableTable *vars;
} StackFrameBody;
typedef struct
{
const Promise *owner;
VariableTable *vars;
} StackFramePromise;
typedef struct
{
const BundleSection *owner;
} StackFrameBundleSection;
typedef struct
{
Promise *owner;
const PromiseIterator *iter_ctx;
size_t index;
RingBuffer *log_messages;
} StackFramePromiseIteration;
typedef struct
{
StackFrameType type;
bool inherits_previous; // whether or not this frame inherits context from the previous frame
union
{
StackFrameBundle bundle;
StackFrameBody body;
StackFrameBundleSection bundle_section;
StackFramePromise promise;
StackFramePromiseIteration promise_iteration;
} data;
char *path;
} StackFrame;
typedef enum
{
EVAL_OPTION_NONE = 0,
EVAL_OPTION_EVAL_FUNCTIONS = 1 << 0,
EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS = 1 << 1,
EVAL_OPTION_FULL = 0xFFFFFFFF
} EvalContextOption;
EvalContext *EvalContextNew(void);
void EvalContextDestroy(EvalContext *ctx);
void EvalContextSetConfig(EvalContext *ctx, const GenericAgentConfig *config);
const GenericAgentConfig *EvalContextGetConfig(EvalContext *ctx);
Rlist *EvalContextGetRestrictKeys(const EvalContext *ctx);
void EvalContextSetRestrictKeys(EvalContext *ctx, const Rlist *restrict_keys);
void EvalContextHeapAddAbort(EvalContext *ctx, const char *context, const char *activated_on_context);
void EvalContextHeapAddAbortCurrentBundle(EvalContext *ctx, const char *context, const char *activated_on_context);
void EvalContextHeapPersistentSave(EvalContext *ctx, const char *name, unsigned int ttl_minutes, PersistentClassPolicy policy, const char *tags);
void EvalContextHeapPersistentRemove(const char *context);
void EvalContextHeapPersistentLoadAll(EvalContext *ctx);
/**
* Sets negated classes (persistent classes that should not be defined).
*
* @note Takes ownership of #negated_classes
*/
void EvalContextSetNegatedClasses(EvalContext *ctx, StringSet *negated_classes);
bool EvalContextClassPutSoft(EvalContext *ctx, const char *name, ContextScope scope, const char *tags);
bool EvalContextClassPutSoftTagsSet(EvalContext *ctx, const char *name, ContextScope scope, StringSet *tags);
bool EvalContextClassPutSoftTagsSetWithComment(EvalContext *ctx, const char *name, ContextScope scope,
StringSet *tags, const char *comment);
bool EvalContextClassPutSoftNS(EvalContext *ctx, const char *ns, const char *name,
ContextScope scope, const char *tags);
bool EvalContextClassPutSoftNSTagsSet(EvalContext *ctx, const char *ns, const char *name,
ContextScope scope, StringSet *tags);
bool EvalContextClassPutSoftNSTagsSetWithComment(EvalContext *ctx, const char *ns, const char *name,
ContextScope scope, StringSet *tags, const char *comment);
bool EvalContextClassPutHard(EvalContext *ctx, const char *name, const char *tags);
Class *EvalContextClassGet(const EvalContext *ctx, const char *ns, const char *name);
Class *EvalContextClassMatch(const EvalContext *ctx, const char *regex);
bool EvalContextClassRemove(EvalContext *ctx, const char *ns, const char *name);
StringSet *EvalContextClassTags(const EvalContext *ctx, const char *ns, const char *name);
ClassTableIterator *EvalContextClassTableIteratorNewGlobal(const EvalContext *ctx, const char *ns, bool is_hard, bool is_soft);
ClassTableIterator *EvalContextClassTableIteratorNewLocal(const EvalContext *ctx);
// Class Logging
const StringSet *EvalContextAllClassesGet(const EvalContext *ctx);
void EvalContextAllClassesLoggingEnable(EvalContext *ctx, bool enable);
void EvalContextPushBundleName(const EvalContext *ctx, const char *bundle_name);
const StringSet *EvalContextGetBundleNames(const EvalContext *ctx);
void EvalContextPushRemoteVarPromise(EvalContext *ctx, const char *bundle_name, const Promise *pp);
const Seq *EvalContextGetRemoteVarPromises(const EvalContext *ctx, const char *bundle_name);
void EvalContextClear(EvalContext *ctx);
Rlist *EvalContextGetPromiseCallerMethods(EvalContext *ctx);
void EvalContextStackPushBundleFrame(EvalContext *ctx, const Bundle *owner, const Rlist *args, bool inherits_previous);
void EvalContextStackPushBodyFrame(EvalContext *ctx, const Promise *caller, const Body *body, const Rlist *args);
void EvalContextStackPushBundleSectionFrame(EvalContext *ctx, const BundleSection *owner);
void EvalContextStackPushPromiseFrame(EvalContext *ctx, const Promise *owner);
Promise *EvalContextStackPushPromiseIterationFrame(EvalContext *ctx, const PromiseIterator *iter_ctx);
void EvalContextStackPopFrame(EvalContext *ctx);
const char *EvalContextStackToString(EvalContext *ctx);
void EvalContextSetBundleArgs(EvalContext *ctx, const Rlist *args);
void EvalContextSetPass(EvalContext *ctx, int pass);
Rlist *EvalContextGetBundleArgs(EvalContext *ctx);
int EvalContextGetPass(EvalContext *ctx);
char *EvalContextStackPath(const EvalContext *ctx);
StringSet *EvalContextStackPromisees(const EvalContext *ctx);
const Promise *EvalContextStackCurrentPromise(const EvalContext *ctx);
const Bundle *EvalContextStackCurrentBundle(const EvalContext *ctx);
const RingBuffer *EvalContextStackCurrentMessages(const EvalContext *ctx);
Rlist *EvalContextGetPromiseCallerMethods(EvalContext *ctx);
JsonElement *EvalContextGetPromiseCallers(EvalContext *ctx);
bool EvalContextVariablePut(EvalContext *ctx, const VarRef *ref, const void *value, DataType type, const char *tags);
bool EvalContextVariablePutTagsSet(EvalContext *ctx, const VarRef *ref, const void *value, DataType type, StringSet *tags);
bool EvalContextVariablePutTagsSetWithComment(EvalContext *ctx,
const VarRef *ref, const void *value,
DataType type, StringSet *tags,
const char *comment);
bool EvalContextVariablePutSpecial(EvalContext *ctx, SpecialScope scope, const char *lval, const void *value, DataType type, const char *tags);
bool EvalContextVariablePutSpecialTagsSet(EvalContext *ctx, SpecialScope scope, const char *lval,
const void *value, DataType type, StringSet *tags);
bool EvalContextVariablePutSpecialTagsSetWithComment(EvalContext *ctx, SpecialScope scope,
const char *lval, const void *value,
DataType type, StringSet *tags,
const char *comment);
const void *EvalContextVariableGetSpecial(const EvalContext *ctx, const SpecialScope scope, const char *varname, DataType *type_out);
const char *EvalContextVariableGetSpecialString(const EvalContext *ctx, const SpecialScope scope, const char *varname);
const void *EvalContextVariableGet(const EvalContext *ctx, const VarRef *ref, DataType *type_out);
const Promise *EvalContextVariablePromiseGet(const EvalContext *ctx, const VarRef *ref);
bool EvalContextVariableRemoveSpecial(const EvalContext *ctx, SpecialScope scope, const char *lval);
bool EvalContextVariableRemove(const EvalContext *ctx, const VarRef *ref);
StringSet *EvalContextVariableTags(const EvalContext *ctx, const VarRef *ref);
bool EvalContextVariableClearMatch(EvalContext *ctx);
VariableTableIterator *EvalContextVariableTableIteratorNew(const EvalContext *ctx, const char *ns, const char *scope, const char *lval);
VariableTableIterator *EvalContextVariableTableFromRefIteratorNew(const EvalContext *ctx, const VarRef *ref);
bool EvalContextPromiseLockCacheContains(const EvalContext *ctx, const char *key);
void EvalContextPromiseLockCachePut(EvalContext *ctx, const char *key);
void EvalContextPromiseLockCacheRemove(EvalContext *ctx, const char *key);
bool EvalContextFunctionCacheGet(const EvalContext *ctx, const FnCall *fp, const Rlist *args, Rval *rval_out);
void EvalContextFunctionCachePut(EvalContext *ctx, const FnCall *fp, const Rlist *args, const Rval *rval);
const void *EvalContextVariableControlCommonGet(const EvalContext *ctx, CommonControl lval);
/**
* @brief Find a bundle for a bundle call, given a callee reference (in the form of ns:bundle), and a type of bundle.
* This is requires EvalContext because the callee reference may be unqualified.
* Hopefully this should go away in the future if we make a more generalized API to simply call a bundle,
* but we have a few special rules around edit_line and so on.
*/
const Bundle *EvalContextResolveBundleExpression(const EvalContext *ctx, const Policy *policy,
const char *callee_reference, const char *callee_type);
const Body *EvalContextFindFirstMatchingBody(const Policy *policy, const char *type,
const char *namespace, const char *name);
/**
@brief Returns a Sequence of const Body* elements, first the body and then its parents
Uses `inherit_from` to figure out the parents.
*/
Seq *EvalContextResolveBodyExpression(const EvalContext *ctx, const Policy *policy,
const char *callee_reference, const char *callee_type);
/* - Parsing/evaluating expressions - */
void ValidateClassSyntax(const char *str);
ExpressionValue CheckClassExpression(const EvalContext *ctx, const char *context);
static inline bool IsDefinedClass(const EvalContext *ctx, const char *context)
{
return (CheckClassExpression(ctx, context) == EXPRESSION_VALUE_TRUE);
}
StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, const char* regex, const Rlist *tags, bool first_only);
StringSet *ClassesMatchingGlobal(const EvalContext *ctx, const char* regex, const Rlist *tags, bool first_only);
StringSet *ClassesMatchingLocal(const EvalContext *ctx, const char* regex, const Rlist *tags, bool first_only);
bool EvalProcessResult(const char *process_result, StringSet *proc_attr);
bool EvalFileResult(const char *file_result, StringSet *leaf_attr);
/**
* @brief Evaluates a class expression based on a set of defined classes.
* @param expr Class expression (E.g. "GMT_Monday|GMT_Wednesday").
* @param token_set Set of defined classes.
* @return True if the class expression evaluates to true, otherwise false.
*/
bool EvalWithTokenFromList(const char *expr, StringSet *token_set);
/* Various global options */
void SetChecksumUpdatesDefault(EvalContext *ctx, bool enabled);
bool GetChecksumUpdatesDefault(const EvalContext *ctx);
/* IP addresses */
Item *EvalContextGetIpAddresses(const EvalContext *ctx);
void EvalContextAddIpAddress(EvalContext *ctx, const char *address, const char *iface);
void EvalContextDeleteIpAddresses(EvalContext *ctx);
/* - Rest - */
void EvalContextSetEvalOption(EvalContext *ctx, EvalContextOption option, bool value);
bool EvalContextGetEvalOption(EvalContext *ctx, EvalContextOption option);
bool EvalContextIsIgnoringLocks(const EvalContext *ctx);
void EvalContextSetIgnoreLocks(EvalContext *ctx, bool ignore);
void EvalContextSetLaunchDirectory(EvalContext *ctx, const char *path);
void EvalContextSetEntryPoint(EvalContext* ctx, const char *entry_point);
const char *EvalContextGetEntryPoint(EvalContext* ctx);
bool BundleAbort(EvalContext *ctx);
bool EvalAborted(const EvalContext *ctx);
void NotifyDependantPromises(EvalContext *ctx, const Promise *pp, PromiseResult result);
bool MissingDependencies(EvalContext *ctx, const Promise *pp);
/**
* Record promise status (result).
*
* This function should be called once for every promise to record its
* status/result. It logs the given message (#fmt and varargs) with the given
* #level based on the logging specifications in the 'action' body and
* increments the counters of actuated promises and promises
* kept/repaired/failed/...
*
* If #fmt is NULL or an empty string, nothing is logged. #level should be
* #LOG_LEVEL_NOTHING in such cases.
*/
void cfPS(EvalContext *ctx, LogLevel level, PromiseResult status, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(6, 7);
/**
* Log change done by the agent when evaluating policy and set the outcome
* classes.
*
* Unlike cfPS(), this function is expected to be called multiple times for the
* same promise. It's not recording a promise status, but rather one out of
* multiple changes done by the given promise.
*/
void RecordChange(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
void RecordNoChange(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
void RecordFailure(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
void RecordWarning(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
void RecordDenial(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
void RecordInterruption(EvalContext *ctx, const Promise *pp, const Attributes *attr, const char *fmt, ...) FUNC_ATTR_PRINTF(4, 5);
/**
* Check if the given promise is allowed to make changes in the current agent
* run and if not, log the fact and update #result accordingly.
*
* The #change_desc_fmt argument and the ones following it should format a
* message that describes the action, like "rename the file '/etc/issue'", the
* implementation of this function prepends and, potentially, appends text to
* the message to form a complete sentence.
*/
bool MakingChanges(EvalContext *ctx, const Promise *pp, const Attributes *attr,
PromiseResult *result, const char *change_desc_fmt, ...) FUNC_ATTR_PRINTF(5, 6);
/**
* Similar to MakingChanges() above, but checking if changes to internal
* structures are allowed. Audit modes should, for example, not make such
* changes, even though they make other changes (in a changes chroot).
*/
bool MakingInternalChanges(EvalContext *ctx, const Promise *pp, const Attributes *attr,
PromiseResult *result, const char *change_desc_fmt, ...) FUNC_ATTR_PRINTF(5, 6);
/**
* Whether to make changes in a chroot or not.
*/
static inline bool ChrootChanges()
{
return ((EVAL_MODE == EVAL_MODE_SIMULATE_DIFF) ||
(EVAL_MODE == EVAL_MODE_SIMULATE_MANIFEST) ||
(EVAL_MODE == EVAL_MODE_SIMULATE_MANIFEST_FULL));
}
/**
* Set the chroot for recording changes in files (in simulate mode(s)).
*
* @note This function should only be called once.
*/
void SetChangesChroot(const char *chroot);
/**
* Get the path for #orig_path under the changes chroot (where changes in simulate
* mode(s) are done). #orig_path is expected to be an absolute path.
*
* @note Returns a pointer to an internal buffer and the value is only valid
* until the function is called again.
* @warning not thread-safe
*/
const char *ToChangesChroot(const char *orig_path);
/**
* Possibly transform #path to the path where changes are to be made.
* @see ChrootChanges()
* @see ToChangesChroot()
*/
static inline const char *ToChangesPath(const char *path)
{
return (ChrootChanges() ? ToChangesChroot(path) : path);
}
/**
* Reverse operation for ToChangesChroot().
*
* @return A pointer to an offset of #orig_path where the non-chrooted path starts.
* @warning Doesn't work on Windows (because on Windows the operation is not as easy as just
* shifting the pointer by the offset).
*/
#ifndef __MINGW32__
const char *ToNormalRoot(const char *orig_path);
#else
const char *ToNormalRoot(const char *orig_path) __attribute__((error ("Not supported on Windows")));
#endif
PackagePromiseContext *GetPackageDefaultsFromCtx(const EvalContext *ctx);
bool EvalContextGetSelectEndMatchEof(const EvalContext *ctx);
void EvalContextSetSelectEndMatchEof(EvalContext *ctx, bool value);
void AddDefaultPackageModuleToContext(const EvalContext *ctx, char *name);
void AddDefaultInventoryToContext(const EvalContext *ctx, Rlist *inventory);
void AddPackageModuleToContext(const EvalContext *ctx, PackageModuleBody *pm);
PackageModuleBody *GetPackageModuleFromContext(const EvalContext *ctx, const char *name);
PackageModuleBody *GetDefaultPackageModuleFromContext(const EvalContext *ctx);
Rlist *GetDefaultInventoryFromContext(const EvalContext *ctx);
PackagePromiseContext *GetPackagePromiseContext(const EvalContext *ctx);
/* This function is temporarily exported. It needs to be made an detail of
* evaluator again, once variables promises are no longer specially handled */
void ClassAuditLog(EvalContext *ctx, const Promise *pp, const Attributes *attr, PromiseResult status);
/**
* Set classes based on the promise outcome/result.
*
* @note This function should only be called in special cases, ClassAuditLog()
* (which calls this function internally) should be called in most places.
*/
void SetPromiseOutcomeClasses(EvalContext *ctx, PromiseResult status, const DefineClasses *dc);
ENTERPRISE_VOID_FUNC_2ARG_DECLARE(void, TrackTotalCompliance, ARG_UNUSED PromiseResult, status, ARG_UNUSED const Promise *, pp);
ENTERPRISE_VOID_FUNC_3ARG_DECLARE(void, EvalContextLogPromiseIterationOutcome,
EvalContext *, ctx,
const Promise *, pp,
PromiseResult, result);
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, EvalContextSetupMissionPortalLogHook,
EvalContext *, ctx);
char *MissionPortalLogHook(LoggingPrivContext *pctx, LogLevel level, const char *message);
JsonElement* JsonExpandElement(EvalContext *ctx, const JsonElement *source);
void EvalContextSetDumpReports(EvalContext *ctx, bool dump_reports);
bool EvalContextGetDumpReports(EvalContext *ctx);
void EvalContextUpdateDumpReports(EvalContext *ctx);
#endif
|