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 #include <platform.h>
26 
27 #include <cf3.defs.h>
28 #include <stdbool.h>
29 #include <logic_expressions.h>
30 #include <misc_lib.h>
31 
32 #include <stdlib.h>
33 
34 /* <primary> */
35 
ParsePrimary(const char * expr,int start,int end)36 static ParseResult ParsePrimary(const char *expr, int start, int end)
37 {
38     if (start < end && expr[start] == '(')
39     {
40         ParseResult res = ParseExpression(expr, start + 1, end);
41 
42         if (res.result)
43         {
44             /* Check if there is a matching ')' at the end */
45             if (res.position < end && expr[res.position] == ')')
46             {
47                 return (ParseResult) {res.result, res.position + 1};
48             }
49             else
50             {
51                 /* Haven't found a matching bracket. Give up */
52                 FreeExpression(res.result);
53                 return (ParseResult) {NULL, res.position};
54             }
55         }
56         else
57         {
58             return res;
59         }
60     }
61     else
62     {
63         StringParseResult strres = ParseStringExpression(expr, start, end);
64 
65         if (strres.result)
66         {
67             Expression *res = xcalloc(1, sizeof(Expression));
68 
69             res->op = LOGICAL_OP_EVAL;
70             res->val.eval.name = strres.result;
71 
72             return (ParseResult) {res, strres.position};
73         }
74         else
75         {
76             return (ParseResult) {NULL, strres.position};
77         }
78     }
79 }
80 
81 /* <not-expr> */
82 
ParseNotExpression(const char * expr,int start,int end)83 static ParseResult ParseNotExpression(const char *expr, int start, int end)
84 {
85     if (start < end && expr[start] == '!')
86     {
87         ParseResult primres = ParsePrimary(expr, start + 1, end);
88 
89         if (primres.result)
90         {
91             Expression *res = xcalloc(1, sizeof(Expression));
92 
93             res->op = LOGICAL_OP_NOT;
94             res->val.not.arg = primres.result;
95 
96             return (ParseResult) {res, primres.position};
97         }
98         else
99         {
100             return primres;
101         }
102     }
103     else
104     {
105         return ParsePrimary(expr, start, end);
106     }
107 }
108 
109 /* <and-expr> */
110 
ParseAndExpression(const char * expr,int start,int end)111 static ParseResult ParseAndExpression(const char *expr, int start, int end)
112 {
113     ParseResult lhs, rhs;
114     Expression *res;
115 
116     lhs = ParseNotExpression(expr, start, end);
117 
118     if (!lhs.result)
119     {
120         return lhs;
121     }
122 
123     if (lhs.position == end || (expr[lhs.position] != '.' && expr[lhs.position] != '&'))
124     {
125         return lhs;
126     }
127 
128     rhs = ParseAndExpression(expr, lhs.position + 1, end);
129 
130     if (!rhs.result)
131     {
132         FreeExpression(lhs.result);
133         return rhs;
134     }
135 
136     res = xcalloc(1, sizeof(Expression));
137     res->op = LOGICAL_OP_AND;
138     res->val.andor.lhs = lhs.result;
139     res->val.andor.rhs = rhs.result;
140 
141     return (ParseResult) {res, rhs.position};
142 }
143 
144 /* <or-expr> */
145 
ParseExpression(const char * expr,int start,int end)146 ParseResult ParseExpression(const char *expr, int start, int end)
147 {
148     ParseResult lhs, rhs;
149     Expression *res;
150     int position;
151 
152     lhs = ParseAndExpression(expr, start, end);
153 
154     if (!lhs.result)
155     {
156         return lhs;
157     }
158 
159 /* End of left-hand side expression */
160     position = lhs.position;
161 
162     if (position == end || expr[position] != '|')
163     {
164         return lhs;
165     }
166 
167 /* Skip second '|' in 'lhs||rhs' */
168 
169     if (position + 1 < end && expr[position + 1] == '|')
170     {
171         position++;
172     }
173 
174     rhs = ParseExpression(expr, position + 1, end);
175 
176     if (!rhs.result)
177     {
178         FreeExpression(lhs.result);
179         return rhs;
180     }
181 
182     res = xcalloc(1, sizeof(Expression));
183     res->op = LOGICAL_OP_OR;
184     res->val.andor.lhs = lhs.result;
185     res->val.andor.rhs = rhs.result;
186 
187     return (ParseResult) {res, rhs.position};
188 }
189 
190 /* Evaluation */
191 
EvalExpression(const Expression * expr,NameEvaluator nameevalfn,VarRefEvaluator varrefevalfn,void * param)192 ExpressionValue EvalExpression(const Expression *expr,
193                                NameEvaluator nameevalfn, VarRefEvaluator varrefevalfn, void *param)
194 {
195     switch (expr->op)
196     {
197     case LOGICAL_OP_OR:
198     case LOGICAL_OP_AND:
199     {
200         ExpressionValue lhs = EXPRESSION_VALUE_ERROR, rhs = EXPRESSION_VALUE_ERROR;
201 
202         lhs = EvalExpression(expr->val.andor.lhs, nameevalfn, varrefevalfn, param);
203         if (lhs == EXPRESSION_VALUE_ERROR)
204         {
205             return EXPRESSION_VALUE_ERROR;
206         }
207 
208         rhs = EvalExpression(expr->val.andor.rhs, nameevalfn, varrefevalfn, param);
209 
210         if (rhs == EXPRESSION_VALUE_ERROR)
211         {
212             return EXPRESSION_VALUE_ERROR;
213         }
214 
215         if (expr->op == LOGICAL_OP_OR)
216         {
217             return ((ExpressionValue) (lhs || rhs));
218         }
219         else
220         {
221             return ((ExpressionValue) (lhs && rhs));
222         }
223     }
224 
225     case LOGICAL_OP_NOT:
226     {
227         ExpressionValue arg = EvalExpression(expr->val.not.arg,
228                                              nameevalfn,
229                                              varrefevalfn,
230                                              param);
231 
232         if (arg == EXPRESSION_VALUE_ERROR)
233         {
234             return EXPRESSION_VALUE_ERROR;
235         }
236         else
237         {
238             return !arg;
239         }
240     }
241 
242     case LOGICAL_OP_EVAL:
243     {
244         ExpressionValue ret = EXPRESSION_VALUE_ERROR;
245         char *name = EvalStringExpression(expr->val.eval.name,
246                                           varrefevalfn,
247                                           param);
248 
249         if (name == NULL)
250         {
251             return EXPRESSION_VALUE_ERROR;
252         }
253         else if (strcmp("true", name) == 0)
254         {
255             ret =  EXPRESSION_VALUE_TRUE;
256         }
257         else if (strcmp("false", name) == 0)
258         {
259             ret =  EXPRESSION_VALUE_FALSE;
260         }
261         else
262         {
263             ret = (*nameevalfn) (name, param);
264         }
265 
266         free(name);
267         return ret;
268     }
269 
270     default:
271         ProgrammingError("Unexpected class expression type is found: %d", expr->op);
272     }
273 }
274 
275 /* Freeing results */
276 
FreeExpression(Expression * e)277 void FreeExpression(Expression *e)
278 {
279     if (!e)
280     {
281         return;
282     }
283 
284     switch (e->op)
285     {
286     case LOGICAL_OP_OR:
287     case LOGICAL_OP_AND:
288         FreeExpression(e->val.andor.lhs);
289         FreeExpression(e->val.andor.rhs);
290         break;
291     case LOGICAL_OP_NOT:
292         FreeExpression(e->val.not.arg);
293         break;
294     case LOGICAL_OP_EVAL:
295         FreeStringExpression(e->val.eval.name);
296         break;
297     default:
298         ProgrammingError("Unknown logic expression type encountered in" "FreeExpression: %d", e->op);
299     }
300     free(e);
301 }
302