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