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