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