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