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