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