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