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