4ddcfa8effc697b211abbc0867d929729a0f185c
[freeradius.git] / src / modules / rlm_policy / evaluate.c
1 /*
2  * evaluate.c           Evaluate a policy language
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2004  Alan DeKok <aland@ox.org>
21  * Copyright 2006  The FreeRADIUS server project
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include "rlm_policy.h"
28
29 #ifdef HAVE_REGEX_H
30 #include <regex.h>
31 #endif
32
33 #define debug_evaluate if (0) printf
34
35 /*
36  *      Print stuff we've parsed
37  */
38 static void policy_print(const policy_item_t *item, int indent)
39 {
40         if (!item) {
41                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
42                 fprintf(fr_log_fp, "[NULL]\n");
43                 return;
44         }
45
46         while (item) {
47                 switch (item->type) {
48                 case POLICY_TYPE_BAD:
49                         if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
50                         fprintf(fr_log_fp, "[BAD STATEMENT]");
51                         break;
52
53                 case POLICY_TYPE_PRINT:
54                         if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
55                         {
56                                 const policy_print_t *this;
57
58                                 this = (const policy_print_t *) item;
59
60                                 if (this->rhs_type == POLICY_LEX_BARE_WORD) {
61                                         fprintf(fr_log_fp, "print %s\n", this->rhs);
62                                 } else {
63                                         fprintf(fr_log_fp, "print \"%s\"\n", this->rhs);
64                                 }
65                         }
66                         break;
67
68                 case POLICY_TYPE_ASSIGNMENT:
69                         {
70                                 const policy_assignment_t *assign;
71
72                                 assign = (const policy_assignment_t *) item;
73                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
74
75                                 fprintf(fr_log_fp, "\t%s %s ", assign->lhs,
76                                        fr_int2str(rlm_policy_tokens,
77                                                     assign->assign, "?"));
78                                 if (assign->rhs_type == POLICY_LEX_BARE_WORD) {
79                                         fprintf(fr_log_fp, "%s\n", assign->rhs);
80                                 } else {
81                                         /*
82                                          *      FIXME: escape "
83                                          */
84                                         fprintf(fr_log_fp, "\"%s\"\n", assign->rhs);
85                                 }
86                         }
87                         break;
88
89                 case POLICY_TYPE_CONDITIONAL: /* no indentation here */
90                         {
91                                 const policy_condition_t *condition;
92
93                                 condition = (const policy_condition_t *) item;
94
95                                 fprintf(fr_log_fp, "(");
96
97                                 if (condition->sense) {
98                                         fprintf(fr_log_fp, "!");
99                                 }
100
101                                 /*
102                                  *      Nested conditions.
103                                  */
104                                 if (condition->compare == POLICY_LEX_L_BRACKET) {
105                                         policy_print(condition->child, indent);
106                                         fprintf(fr_log_fp, ")");
107                                         break;
108                                 }
109
110                                 if (condition->compare == POLICY_LEX_L_NOT) {
111                                         fprintf(fr_log_fp, "!");
112                                         policy_print(condition->child, indent);
113                                         fprintf(fr_log_fp, ")");
114                                         break;
115                                 }
116
117                                 if (condition->compare == POLICY_LEX_CMP_TRUE) {
118                                         fprintf(fr_log_fp, "%s)", condition->lhs);
119                                         break;
120                                 }
121
122                                 if (condition->lhs_type == POLICY_LEX_FUNCTION) {
123                                         fprintf(fr_log_fp, "%s()", condition->lhs);
124                                 } else {
125                                         /*
126                                          *      FIXME: escape ",
127                                          *      and move all of this logic
128                                          *      to a function.
129                                          */
130                                         fprintf(fr_log_fp, "\"%s\"", condition->lhs);
131                                 }
132
133                                 /*
134                                  *      We always print this condition.
135                                  */
136                                 fprintf(fr_log_fp, " %s ", fr_int2str(rlm_policy_tokens,
137                                                             condition->compare,
138                                                             "?"));
139                                 if (condition->rhs_type == POLICY_LEX_BARE_WORD) {
140                                         fprintf(fr_log_fp, "%s", condition->rhs);
141                                 } else {
142                                         /*
143                                          *      FIXME: escape ",
144                                          *      and move all of this logic
145                                          *      to a function.
146                                          */
147                                         fprintf(fr_log_fp, "\"%s\"", condition->rhs);
148                                 }
149                                 fprintf(fr_log_fp, ")");
150
151                                 if ((condition->child_condition != POLICY_LEX_BAD) &&
152                                     (condition->child_condition != POLICY_LEX_BARE_WORD)) {
153                                         fprintf(fr_log_fp, " %s ", fr_int2str(rlm_policy_tokens, condition->child_condition, "?"));
154                                         policy_print(condition->child, indent);
155                                 }
156                         }
157                         break;
158
159                 case POLICY_TYPE_IF:
160                         {
161                                 const policy_if_t *statement;
162
163                                 statement = (const policy_if_t *) item;
164
165                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
166                                 fprintf(fr_log_fp, "if ");
167                                 policy_print(statement->condition, indent);
168                                 fprintf(fr_log_fp, " {\n");
169                                 policy_print(statement->if_true, indent + 1);
170                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
171                                 if (statement->if_false) {
172                                         fprintf(fr_log_fp, "} else ");
173                                         if (statement->if_false->type == POLICY_TYPE_ASSIGNMENT) {
174                                                 fprintf(fr_log_fp, " { ");
175                                                 policy_print(statement->if_false, indent + 1);
176                                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
177                                                 fprintf(fr_log_fp, " }");
178                                         } else {
179                                                 policy_print(statement->if_false, indent + 1);
180                                         }
181                                 } else {
182                                         fprintf(fr_log_fp, "}\n");
183                                 }
184                         }
185                         break;
186
187                 case POLICY_TYPE_ATTRIBUTE_LIST:
188                         {
189                                 const policy_attributes_t *this;
190
191                                 this = (const policy_attributes_t *) item;
192
193                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
194                                 fprintf(fr_log_fp, "%s %s {\n",
195                                        fr_int2str(policy_reserved_words,
196                                                     this->where, "?"),
197                                        fr_int2str(rlm_policy_tokens,
198                                                     this->how, "?"));
199                                 policy_print(this->attributes, indent + 1);
200                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
201                                 fprintf(fr_log_fp, "}\n");
202                         }
203                         break;
204
205                 case POLICY_TYPE_NAMED_POLICY:
206                         {
207                                 const policy_named_t *this;
208
209                                 this = (const policy_named_t *) item;
210                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
211                                 fprintf(fr_log_fp, "policy %s {\n", this->name);
212                                 policy_print(this->policy, indent + 1);
213                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
214                                 fprintf(fr_log_fp, "}\n");
215                         }
216                         break;
217
218                 case POLICY_TYPE_CALL:
219                         {
220                                 const policy_call_t *this;
221
222                                 this = (const policy_call_t *) item;
223                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
224                                 fprintf(fr_log_fp, "call %s\n", this->name);
225                         }
226                         break;
227
228                 case POLICY_TYPE_RETURN:
229                         {
230                                 const policy_return_t *this;
231
232                                 this = (const policy_return_t *) item;
233                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
234                                 fprintf(fr_log_fp, "return %s\n",
235                                        fr_int2str(policy_return_codes,
236                                                     this->rcode, "???"));
237                         }
238                         break;
239
240                 case POLICY_TYPE_MODULE:
241                         {
242                                 const policy_module_t *this;
243
244                                 this = (const policy_module_t *) item;
245                                 if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
246                                 fprintf(fr_log_fp, "module %s <stuff>\n",
247                                        fr_int2str(policy_component_names,
248                                                     this->component, "???"));
249                         }
250                         break;
251
252                 default:
253                         if (indent) fprintf(fr_log_fp, "%*s", indent, " ");
254                         fprintf(fr_log_fp, "[HUH?]\n");
255                         break;
256
257                 }
258
259                 item = item->next;
260         }
261 }
262
263
264 void rlm_policy_print(const policy_item_t *item)
265 {
266         if (!fr_log_fp) return;
267
268         fprintf(fr_log_fp, "# rlm_policy \n");
269         policy_print(item, 0);
270 }
271
272 /*
273  *      Internal stack of things to do.  This lets us have function
274  *      calls...
275  *
276  *      Yes, we should learn lex, yacc, etc.
277  */
278 #define POLICY_MAX_STACK 16
279 typedef struct policy_state_t {
280         rlm_policy_t    *inst;
281         REQUEST         *request; /* so it's not passed on the C stack */
282         int             rcode;  /* for functions, etc. */
283         int             component; /* for calling other modules */
284         int             depth;
285         const policy_item_t *stack[POLICY_MAX_STACK];
286 } policy_state_t;
287
288
289 static int policy_evaluate_name(policy_state_t *state, const char *name);
290
291 /*
292  *      Push an item onto the state.
293  */
294 static int policy_stack_push(policy_state_t *state, const policy_item_t *item)
295 {
296         rad_assert(state->depth >= 0);
297
298         /*
299          *      Asked to push nothing.  Don't push it.
300          */
301         if (!item) return 1;
302
303         /*
304          *      State is full.  Die.
305          */
306         if (state->depth >= POLICY_MAX_STACK) {
307                 return 0;
308         }
309
310         /*
311          *      Walk back up the stack, looking for previous ocurrances
312          *      of this name.  If found, we have infinite recursion,
313          *      which we stop dead in the water!
314          *
315          *      This isn't strictly necessary right now, as we look up
316          *      policies by name when they're first referenced.  This
317          *      means that ALL references are backwards (to the start
318          *      of the file), which means that there are no circular
319          *      references.
320          */
321         if (item->type == POLICY_TYPE_NAMED_POLICY) {
322                 int i;
323
324                 for (i = 0; i < state->depth; i++) {
325                         /*
326                          *      Check for circular references, by seeing
327                          *      if the function is already on the stack.
328                          *
329                          *      Hmmm... do we want to do this for any type?
330                          */
331                         if (state->stack[i] == item) {
332                                 debug_evaluate("Circular call to policy %s\n",
333                                                ((const policy_named_t *) item)->name);
334                                 return 0;
335                         }
336                 }
337         }
338
339         debug_evaluate("push %d %p\n", state->depth, item);
340
341         state->stack[state->depth] = item;
342         state->depth++;         /* points to unused entry */
343
344         return 1;
345 }
346
347
348 /*
349  *      Pop an item from the state.
350  */
351 static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem)
352 {
353         rad_assert(pitem != NULL);
354         rad_assert(state->depth >= 0);
355
356  redo:
357         if (state->depth == 0) {
358                 *pitem = NULL;
359                 return 0;
360         }
361
362         *pitem = state->stack[state->depth - 1];
363
364         /*
365          *      Named policies are on the stack for catching recursion.
366          */
367         if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {
368                 state->depth--;
369                 goto redo;
370         }
371
372         /*
373          *      Process the whole item list.
374          */
375         if ((*pitem)->next) {
376                 state->stack[state->depth - 1] = (*pitem)->next;
377                 debug_evaluate("pop/push %d %p\n", state->depth - 1, *pitem);
378         } else {
379                 state->depth--;         /* points to unused entry */
380                 debug_evaluate("pop %d %p\n", state->depth, *pitem);
381         }
382
383         return 1;
384 }
385
386
387 /*
388  *      Evaluate a print statement
389  */
390 static int evaluate_print(policy_state_t *state, const policy_item_t *item)
391 {
392         const policy_print_t *this;
393
394         if (!fr_log_fp) return 1;
395
396         this = (const policy_print_t *) item;
397
398         if (this->rhs_type == POLICY_LEX_BARE_WORD) {
399                 fprintf(fr_log_fp, "%s\n", this->rhs);
400         } else {
401                 char buffer[1024];
402
403                 radius_xlat(buffer, sizeof(buffer), this->rhs,
404                             state->request, NULL);
405                 fprintf(fr_log_fp, "%s", buffer);
406                 if (!strchr(buffer, '\n')) fprintf(fr_log_fp, "\n");
407         }
408
409         /*
410          *      Doesn't change state->rcode
411          */
412
413         return 1;
414 }
415
416 /*
417  *      Return a VALUE_PAIR, given an attribute name.
418  *
419  *      FIXME: Have it return the N'th one, too, like
420  *      doc/variables.txt?
421  *
422  *      The amount of duplicated code is getting annoying...
423  */
424 static VALUE_PAIR *find_vp(REQUEST *request, const char *name)
425 {
426         const char *p;
427         const DICT_ATTR *dattr;
428         VALUE_PAIR *vps;
429
430         p = name;
431         vps = request->packet->vps;;
432
433         /*
434          *      FIXME: use names from reserved word list?
435          */
436         if (strncasecmp(name, "request:", 8) == 0) {
437                 p += 8;
438         } else if (strncasecmp(name, "reply:", 6) == 0) {
439                 p += 6;
440                 vps = request->reply->vps;
441         } else if (strncasecmp(name, "proxy-request:", 14) == 0) {
442                 p += 14;
443                 if (request->proxy) {
444                         vps = request->proxy->vps;
445                 }
446         } else if (strncasecmp(name, "proxy-reply:", 12) == 0) {
447                 p += 12;
448                 if (request->proxy_reply) {
449                         vps = request->proxy_reply->vps;
450                 }
451         } else if (strncasecmp(name, "control:", 8) == 0) {
452                 p += 8;
453                 vps = request->config_items;
454         } /* else it must be a bare attribute name */
455
456         if (!vps) {
457                 return NULL;
458         }
459
460         dattr = dict_attrbyname(p);
461         if (!dattr) {
462                 fprintf(stderr, "No such attribute %s\n", p);
463                 return NULL;    /* no such attribute */
464         }
465
466         return pairfind(vps, dattr->attr, dattr->vendor);
467 }
468
469
470 /*
471  *      Evaluate an assignment
472  *
473  *      Not really used much...
474  */
475 static int evaluate_assignment(UNUSED policy_state_t *state, const policy_item_t *item)
476 {
477         const policy_assignment_t *this;
478 #if 0
479         const DICT_ATTR *dattr;
480 #endif
481
482         this = (const policy_assignment_t *) item;
483
484         rad_assert(this->lhs != NULL);
485         rad_assert(this->rhs != NULL);
486
487 #if 0
488         dattr = dict_attrbyname(this->lhs);
489         if (!dattr) {
490                 fprintf(stderr, "HUH?\n");
491                 return 0;
492         }
493 #endif
494
495         return 1;
496 }
497
498
499 /*
500  *      Evaluate a condition
501  */
502 static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
503 {
504         int rcode;
505         const policy_condition_t *this;
506         VALUE_PAIR *vp = NULL;
507         const char *data = NULL;
508         int compare;
509 #ifdef HAVE_REGEX_H
510         regex_t reg;
511 #endif
512         char buffer[256];
513         char lhs_buffer[2048];
514
515         this = (const policy_condition_t *) item;
516
517  redo:
518         /*
519          *      FIXME: Don't always do this...
520          */
521         if (this->compare != POLICY_LEX_L_BRACKET) {
522                 if (this->lhs_type == POLICY_LEX_FUNCTION) {
523                         /*
524                          *      We can't call evaluate_call here,
525                          *      because that just pushes stuff onto
526                          *      the stack, and we want to actually
527                          *      evaluate all of it...
528                          */
529                         rcode = policy_evaluate_name(state, this->lhs);
530                         data = fr_int2str(policy_return_codes, rcode, "???");
531                         strlcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
532                 } else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
533                         if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
534                                         state->request, NULL) > 0) {
535                                 data = lhs_buffer;
536                         }
537                 }
538         }
539
540         switch (this->compare) {
541         case POLICY_LEX_L_BRACKET: /* nested brackets are a special case */
542                 rcode = evaluate_condition(state, this->child);
543                 break;
544
545         case POLICY_LEX_L_NOT:
546                 rcode = evaluate_condition(state, this->child);
547                 rcode = (rcode == FALSE); /* reverse sense of test */
548                 break;
549
550         case POLICY_LEX_CMP_FALSE: /* non-existence */
551                 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
552                         vp = find_vp(state->request, this->lhs);
553                         rcode = (vp == NULL);
554                 } else {
555                         rcode = (data == NULL);
556                 }
557                 break;
558
559         case POLICY_LEX_CMP_TRUE: /* existence */
560                 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
561                         vp = find_vp(state->request, this->lhs);
562                         rcode = (vp != NULL);
563                 } else {
564                         rcode = (data != NULL);
565                 }
566                 break;
567
568         default:                /* process other comparisons */
569                 if ((this->compare != POLICY_LEX_CMP_EQUALS) &&
570 #ifdef HAVE_REGEX_H
571                     (this->compare != POLICY_LEX_RX_EQUALS) &&
572                     (this->compare != POLICY_LEX_RX_NOT_EQUALS) &&
573 #endif
574                     (this->compare != POLICY_LEX_LT) &&
575                     (this->compare != POLICY_LEX_GT) &&
576                     (this->compare != POLICY_LEX_LE) &&
577                     (this->compare != POLICY_LEX_GE) &&
578                     (this->compare != POLICY_LEX_CMP_NOT_EQUALS)) {
579                         fprintf(stderr, "%d: bad comparison\n",
580                                 this->item.lineno);
581                         return FALSE;
582                 }
583
584                 if (this->lhs_type == POLICY_LEX_BARE_WORD) {
585                         VALUE_PAIR *myvp;
586
587                         vp = find_vp(state->request, this->lhs);
588
589                         /*
590                          *      A op B is FALSE if A doesn't
591                          *      exist.
592                          */
593                         if (!vp) {
594                                 rcode = FALSE;
595                                 break;
596                         }
597
598                         /*
599                          *      FIXME: Move sanity checks to
600                          *      post-parse code, so we don't do
601                          *      it on every packet.
602                          */
603                         vp_prints_value(buffer, sizeof(buffer), vp, 0);
604                         myvp = pairmake(vp->name, this->rhs, T_OP_EQ);
605                         if (!myvp) return FALSE; /* memory failure */
606                         data = buffer;
607
608                         /*
609                          *      FIXME: What to do about comparisons
610                          *      where vp doesn't exist?  Right now,
611                          *      "simplepaircmp" returns -1, which is
612                          *      probably a bad idea.  it should
613                          *      instead take an operator, a pointer to
614                          *      the comparison result, and return
615                          *      "true/false" for "comparions
616                          *      succeeded/failed", which are different
617                          *      error codes than "comparison is less
618                          *      than, equal to, or greater than zero".
619                          */
620                         compare = radius_callback_compare(state->request,
621                                                           vp, myvp, NULL, NULL);
622                         pairfree(&myvp);
623
624                 } else {
625                         /*
626                          *      FIXME: Do something for RHS type?
627                          */
628                         fr_printf_log("CMP %s %s\n", lhs_buffer, this->rhs);
629                         compare = strcmp(lhs_buffer, this->rhs);
630                 }
631
632                 debug_evaluate("CONDITION COMPARE %d\n", compare);
633
634                 switch (this->compare) {
635                 case POLICY_LEX_CMP_EQUALS:
636                         rcode = (compare == 0);
637                         break;
638
639                 case POLICY_LEX_CMP_NOT_EQUALS:
640                         rcode = (compare != 0);
641                         break;
642
643                 case POLICY_LEX_LT:
644                         rcode = (compare < 0);
645                         break;
646
647                 case POLICY_LEX_GT:
648                         rcode = (compare > 0);
649                         break;
650
651                 case POLICY_LEX_LE:
652                         rcode =(compare <= 0);
653                         break;
654
655                 case POLICY_LEX_GE:
656                         rcode = (compare >= 0);
657                         break;
658
659 #ifdef HAVE_REGEX_H
660                 case POLICY_LEX_RX_EQUALS:
661                 { /* FIXME: copied from src/main/valuepair.c */
662                         int i;
663                         regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
664
665                         /*
666                          *      Include substring matches.
667                          */
668                         if (regcomp(&reg, this->rhs,
669                                     REG_EXTENDED) != 0) {
670                                 /* FIXME: print error */
671                                 return FALSE;
672                         }
673                         rad_assert(data != NULL);
674                         rcode = regexec(&reg, data,
675                                         REQUEST_MAX_REGEX + 1,
676                                         rxmatch, 0);
677                         rcode = (rcode == 0);
678                         regfree(&reg);
679
680                         /*
681                          *      Add %{0}, %{1}, etc.
682                          */
683                         for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
684                                 char *p;
685                                 char rxbuffer[256];
686
687                                 /*
688                                  *      Didn't match: delete old
689                                  *      match, if it existed.
690                                  */
691                                 if (!rcode ||
692                                     (rxmatch[i].rm_so == -1)) {
693                                         p = request_data_get(state->request, state->request,
694                                                              REQUEST_DATA_REGEX | i);
695                                         if (p) {
696                                                 free(p);
697                                                 continue;
698                                         }
699
700                                         /*
701                                          *      No previous match
702                                          *      to delete, stop.
703                                          */
704                                         break;
705                                 }
706
707                                 /*
708                                  *      Copy substring into buffer.
709                                  */
710                                 memcpy(rxbuffer,
711                                        data + rxmatch[i].rm_so,
712                                        rxmatch[i].rm_eo - rxmatch[i].rm_so);
713                                 rxbuffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
714
715                                 /*
716                                  *      Copy substring, and add it to
717                                  *      the request.
718                                  *
719                                  *      Note that we don't check
720                                  *      for out of memory, which is
721                                  *      the only error we can get...
722                                  */
723                                 p = strdup(rxbuffer);
724                                 request_data_add(state->request,
725                                                  state->request,
726                                                  REQUEST_DATA_REGEX | i,
727                                                  p, free);
728                         }
729
730                 }
731                 break;
732
733                 case POLICY_LEX_RX_NOT_EQUALS:
734                         regcomp(&reg, this->rhs, REG_EXTENDED|REG_NOSUB);
735                         rad_assert(data != NULL);
736                         rcode = regexec(&reg, data,
737                                         0, NULL, 0);
738                         rcode = (rcode != 0);
739                         regfree(&reg);
740                                 break;
741 #endif /* HAVE_REGEX_H */
742                 default:
743                         rcode = FALSE;
744                         break;
745                 } /* switch over comparison operators */
746                 break;          /* default from first switch over compare */
747         }
748
749         if (this->sense) rcode = (rcode == FALSE); /* reverse sense of test */
750
751         /*
752          *      No trailing &&, ||
753          */
754         switch (this->child_condition) {
755         default:
756                 return rcode;
757
758         case POLICY_LEX_L_AND:
759                 if (!rcode) return rcode; /* FALSE && x == FALSE */
760                 break;
761
762         case POLICY_LEX_L_OR:
763                 if (rcode) return rcode; /* TRUE && x == TRUE */
764                 break;
765         }
766
767         /*
768          *      Tail recursion.
769          */
770         this = (const policy_condition_t *) this->child;
771         goto redo;
772
773         return 1;               /* should never reach here */
774 }
775
776
777 /*
778  *      Evaluate an 'if' statement
779  */
780 static int evaluate_if(policy_state_t *state, const policy_item_t *item)
781 {
782         int rcode;
783         const policy_if_t *this;
784
785         this = (const policy_if_t *) item;
786
787         /*
788          *      evaluate_condition calls itself recursively.
789          *      We should probably allocate a new state, instead.
790          */
791         rcode = evaluate_condition(state, this->condition);
792         debug_evaluate("IF condition returned %s\n",
793                rcode ? "true" : "false");
794         if (rcode) {
795                 rcode = policy_stack_push(state, this->if_true);
796                 if (!rcode) return rcode;
797         } else if (this->if_false) {
798                 rcode = policy_stack_push(state, this->if_false);
799                 if (!rcode) return rcode;
800         }
801
802         /*
803          *      'if' can fail, if the block it's processing fails.
804          */
805         return 1;;
806 }
807
808
809 /*
810  *      Make a VALUE_PAIR from a policy_assignment_t*
811  *
812  *      The assignment operator has to be '='.
813  */
814 static VALUE_PAIR *assign2vp(REQUEST *request,
815                              const policy_assignment_t *assign)
816 {
817         VALUE_PAIR *vp;
818         FR_TOKEN operator = T_OP_EQ;
819         const char *value = assign->rhs;
820         char buffer[2048];
821
822         if ((assign->rhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) &&
823             (strchr(assign->rhs, '%') != NULL)) {
824                 radius_xlat(buffer, sizeof(buffer), assign->rhs,
825                             request, NULL);
826                 value = buffer;
827         }
828
829         /*
830          *      This is crappy.. fix it.
831          */
832         switch (assign->assign) {
833         case POLICY_LEX_ASSIGN:
834                 operator = T_OP_EQ;
835                 break;
836
837         case POLICY_LEX_SET_EQUALS:
838                 operator = T_OP_SET;
839                 break;
840
841         case POLICY_LEX_PLUS_EQUALS:
842                 operator = T_OP_ADD;
843                 break;
844
845         default:
846                 fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n",
847                         fr_int2str(rlm_policy_tokens,
848                                      assign->assign, "?"),
849                         assign->item.lineno);
850                 return NULL;
851         }
852
853         vp = pairmake(assign->lhs, value, operator);
854         if (!vp) {
855                 fprintf(stderr, "Failed creating pair: %s %s\n", value, fr_strerror());
856         }
857
858         return vp;
859 }
860
861
862 /*
863  *      Evaluate a 'packet .= {attrs}' statement
864  */
865 static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
866 {
867         const policy_attributes_t *this;
868         VALUE_PAIR **vps = NULL;
869         VALUE_PAIR *vp, *head, **tail;
870         const policy_item_t *attr;
871         policy_lex_t this_how;
872
873         this = (const policy_attributes_t *) item;
874
875         switch (this->where) {
876         case POLICY_RESERVED_CONTROL:
877                 vps = &(state->request->config_items);
878                 break;
879
880         case POLICY_RESERVED_REQUEST:
881                 vps = &(state->request->packet->vps);
882                 break;
883
884         case POLICY_RESERVED_REPLY:
885                 vps = &(state->request->reply->vps);
886                 break;
887
888         case POLICY_RESERVED_PROXY_REQUEST:
889                 if (!state->request->proxy) return 0; /* FIXME: print error */
890                 vps = &(state->request->proxy->vps);
891                 break;
892
893         case POLICY_RESERVED_PROXY_REPLY:
894                 if (!state->request->proxy_reply) return 0; /* FIXME: print error */
895                 vps = &(state->request->proxy_reply->vps);
896                 break;
897
898         default:
899                 return 0;
900         }
901
902         head = NULL;
903         tail = &head;
904
905         for (attr = this->attributes; attr != NULL; attr = attr->next) {
906                 if (attr->type != POLICY_TYPE_ASSIGNMENT) {
907                         fprintf(stderr, "bad assignment in attribute list at line %d\n", attr->lineno);
908                         pairfree(&head);
909                         return 0;
910                 }
911
912                 vp = assign2vp(state->request, (const policy_assignment_t *) attr);
913                 if (!vp) {
914                         fprintf(stderr, "Failed to allocate VP\n");
915                         pairfree(&head);
916                         return 0;
917                 }
918                 *tail = vp;
919                 tail = &(vp->next);
920         }
921
922         this_how = this->how;
923  retry_how:
924         switch (this_how) {
925         case POLICY_LEX_SET_EQUALS: /* dangerous: removes all previous things! */
926                 pairfree(vps);
927                 *vps = head;
928                 break;
929
930         case POLICY_LEX_AFTER_TAIL_ASSIGN:
931                 pairmove(vps, &head);
932                 pairfree(&head);
933                 break;
934
935         case POLICY_LEX_ASSIGN: /* 'union' */
936                 pairmove(vps, &head);
937                 pairfree(&head);
938                 break;
939
940         case POLICY_LEX_BEFORE_HEAD_ASSIGN:
941                 pairmove(&head, vps);
942                 pairfree(vps);
943                 *vps = head;
944                 break;
945
946         case POLICY_LEX_AFTER_TAIL_EQUALS:
947         case POLICY_LEX_CONCAT_EQUALS:
948                 pairadd(vps, head);
949                 break;
950
951         case POLICY_LEX_BEFORE_HEAD_EQUALS:
952                 pairadd(&head, *vps);
953                 *vps = head;
954                 break;
955
956         case POLICY_LEX_BEFORE_WHERE_EQUALS:
957         case POLICY_LEX_AFTER_WHERE_EQUALS:
958         case POLICY_LEX_BEFORE_WHERE_ASSIGN:
959         case POLICY_LEX_AFTER_WHERE_ASSIGN:
960                 /* find location*/
961                 {
962                         VALUE_PAIR *vpprev = NULL, *vpnext = NULL, *lvp;
963
964                         for(lvp = *vps; lvp; vpprev = lvp, lvp = lvp->next) {
965                                 vpnext = lvp->next;
966                                 lvp->next = NULL;
967                                 if (evaluate_condition(state, this->where_loc))
968                                         break;
969                                 lvp->next = vpnext;
970                         }
971
972                         if (lvp) { 
973                                 switch(this_how) {
974                                 case POLICY_LEX_BEFORE_WHERE_EQUALS:
975                                 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
976                                         if (vpprev) {
977                                                 lvp->next = vpnext;
978                                                 vpnext = lvp;
979                                                 vpprev->next = NULL;
980                                                 lvp = vpprev;
981                                         }
982                                 default: /* always reached */
983                                         break;
984                                 }
985
986                                 switch(this_how) {
987                                 case POLICY_LEX_BEFORE_WHERE_EQUALS:
988                                         if (vpprev) 
989                                                 pairadd(&lvp, head);
990                                         else
991                                                 *vps = lvp = head;
992                                         break;
993                                 case POLICY_LEX_AFTER_WHERE_EQUALS:
994                                         pairadd(&lvp, head);
995                                         break;
996                                 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
997                                         if (vpprev) {
998                                                 pairmove(&lvp, &head);
999                                                 pairfree(&head);
1000                                         }
1001                                         else
1002                                                 *vps = lvp = head;
1003                                         break;
1004                                 case POLICY_LEX_AFTER_WHERE_ASSIGN:
1005                                         pairmove(&lvp, &head);
1006                                         pairfree(&head);
1007                                         break;
1008                                 default:/*never reached*/
1009                                         break;
1010                                 }       
1011                                 for( ; lvp && lvp->next; lvp = lvp->next);
1012                                 if (lvp)
1013                                         lvp->next = vpnext;
1014                                 break;
1015                         }
1016
1017                         switch(this_how) {
1018                                 case POLICY_LEX_BEFORE_WHERE_EQUALS:
1019                                         this_how = POLICY_LEX_BEFORE_HEAD_EQUALS;
1020                                         break;
1021                                 case POLICY_LEX_AFTER_WHERE_EQUALS:
1022                                         this_how = POLICY_LEX_AFTER_TAIL_EQUALS;
1023                                         break;
1024                                 case POLICY_LEX_BEFORE_WHERE_ASSIGN:
1025                                         this_how = POLICY_LEX_BEFORE_HEAD_ASSIGN;
1026                                         break;
1027                                 case POLICY_LEX_AFTER_WHERE_ASSIGN:
1028                                         this_how = POLICY_LEX_AFTER_TAIL_ASSIGN;
1029                                         break;
1030                                 default: /*never reached*/
1031                                         break;
1032                         }
1033                         goto retry_how; 
1034                 }
1035                 /* FALL-THROUGH */
1036
1037         default:
1038                 fprintf(stderr, "HUH?\n");
1039                 pairfree(&head);
1040                 return 0;
1041         }
1042
1043         state->rcode = RLM_MODULE_UPDATED; /* we did stuff */
1044
1045         return 1;
1046 }
1047
1048
1049 /*
1050  *      Evaluate a reference call to a module.
1051  */
1052 static int evaluate_call(policy_state_t *state, const policy_item_t *item)
1053 {
1054         int rcode;
1055         const policy_call_t *this;
1056         const policy_named_t *policy;
1057
1058         this = (const policy_call_t *) item;
1059
1060         policy = rlm_policy_find(state->inst->policies, this->name);
1061         if (!policy) return 0;  /* not found... */
1062
1063         DEBUG2("rlm_policy: Evaluating policy %s", this->name);
1064
1065         rad_assert(policy->policy->type != POLICY_TYPE_BAD);
1066         rad_assert(policy->policy->type < POLICY_TYPE_NUM_TYPES);
1067
1068         /*
1069          *      Push the name of the function onto the stack,
1070          *      so that we can catch recursive calls.
1071          *
1072          *      The "pop" function will skip over it when it sees it.
1073          */
1074         rcode = policy_stack_push(state, (const policy_item_t *) policy);
1075         if (!rcode) {
1076                 return rcode;
1077         }
1078
1079         /*
1080          *      Push it onto the stack.  Other code will take care of
1081          *      calling it.
1082          */
1083         rcode = policy_stack_push(state, policy->policy);
1084         if (!rcode) {
1085                 return rcode;
1086         }
1087
1088         return 1;
1089 }
1090
1091
1092 /*
1093  *      Evaluate a return statement
1094  */
1095 static int evaluate_return(policy_state_t *state, const policy_item_t *item)
1096 {
1097         const policy_return_t *this;
1098
1099         this = (const policy_return_t *) item;
1100         state->rcode = this->rcode;
1101
1102         return 1;               /* we succeeded */
1103 }
1104
1105
1106 /*
1107  *      Evaluate a module statement
1108  */
1109 static int evaluate_module(policy_state_t *state, const policy_item_t *item)
1110 {
1111         const policy_module_t *this;
1112
1113         this = (const policy_module_t *) item;
1114
1115         /*
1116          *      Just to be paranoid.  Maybe we want to loosen this
1117          *      restriction in the future?
1118          */
1119         if (this->component != state->component) {
1120                 DEBUG2("rlm_policy: Cannot mix & match components");
1121                 return 0;
1122         }
1123
1124         DEBUG2("rlm_policy: begin nested call");
1125         state->rcode = modcall(this->component, this->mc, state->request);
1126         DEBUG2("rlm_policy: end nested call");
1127
1128         return 1;               /* we succeeded */
1129 }
1130
1131
1132 /*
1133  *      State machine stuff.
1134  */
1135 typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);
1136
1137
1138 /*
1139  *      MUST be kept in sync with policy_type_t
1140  */
1141 static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = {
1142         NULL,                   /* POLICY_TYPE_BAD */
1143         evaluate_if,
1144         evaluate_condition,
1145         evaluate_assignment,
1146         evaluate_attr_list,
1147         evaluate_print,
1148         NULL,                   /* define a named policy.. */
1149         evaluate_call,
1150         evaluate_return,
1151         evaluate_module
1152 };
1153
1154
1155 /*
1156  *      Evaluate a policy, keyed by name.
1157  */
1158 static int policy_evaluate_name(policy_state_t *state, const char *name)
1159 {
1160         int rcode;
1161         const policy_item_t *this;
1162         policy_named_t mypolicy, *policy;
1163
1164         mypolicy.name = name;
1165         policy = rbtree_finddata(state->inst->policies, &mypolicy);
1166         if (!policy) return RLM_MODULE_FAIL;
1167
1168         DEBUG2("rlm_policy: Evaluating policy %s", name);
1169
1170         rad_assert(policy->item.type != POLICY_TYPE_BAD);
1171         rad_assert(policy->item.type < POLICY_TYPE_NUM_TYPES);
1172
1173         rcode = policy_stack_push(state, policy->policy);
1174         if (!rcode) {
1175                 return RLM_MODULE_FAIL;
1176         }
1177
1178         /*
1179          *      FIXME: Look for magic keywords like "return",
1180          *      where the packet gets accepted/rejected/whatever
1181          */
1182         while (policy_stack_pop(state, &this)) {
1183                 rad_assert(this != NULL);
1184                 rad_assert(this->type != POLICY_TYPE_BAD);
1185                 rad_assert(this->type < POLICY_TYPE_NUM_TYPES);
1186
1187                 debug_evaluate("Evaluating at line %d\n",
1188                                this->lineno);
1189                 rcode = (*evaluate_functions[this->type])(state,
1190                                                           this);
1191                 if (!rcode) {
1192                         return RLM_MODULE_FAIL;
1193                 }
1194         } /* loop until the stack is empty */
1195
1196         return state->rcode;
1197 }
1198
1199
1200 /*
1201  *      Evaluate, which is pretty close to print, but we look at what
1202  *      we're printing.
1203  */
1204 int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name)
1205 {
1206         int rcode;
1207         policy_state_t *state;
1208
1209         state = rad_malloc(sizeof(*state));
1210         memset(state, 0, sizeof(*state));
1211         state->request = request;
1212         state->inst = inst;
1213         state->rcode = RLM_MODULE_OK;
1214         state->component = fr_str2int(policy_component_names, name,
1215                                         RLM_COMPONENT_COUNT);
1216
1217         rcode = policy_evaluate_name(state, name);
1218
1219         free(state);
1220
1221         return rcode;           /* evaluated OK. */
1222 }