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