Added ability for functions to be in conditions. Not perfect yet,
authoraland <aland>
Tue, 8 Feb 2005 21:47:56 +0000 (21:47 +0000)
committeraland <aland>
Tue, 8 Feb 2005 21:47:56 +0000 (21:47 +0000)
but it works...

src/modules/rlm_policy/evaluate.c
src/modules/rlm_policy/parse.c
src/modules/rlm_policy/rlm_policy.h

index 672c8d9..0c35594 100644 (file)
@@ -124,25 +124,30 @@ static void policy_print(const policy_item_t *item, int indent)
                                        printf("\"%s\"", condition->lhs);
                                }
 
-                               /*
-                                *      We always print this condition.
-                                */
-                               printf(" %s ", lrad_int2str(rlm_policy_tokens,
-                                                           condition->compare,
-                                                           "?"));
-                               if (condition->rhs_type == POLICY_LEX_BARE_WORD) {
-                                       printf("%s", condition->rhs);
+                               if (condition->compare == POLICY_LEX_BARE_WORD) {
+                                       printf("()");
                                } else {
                                        /*
-                                        *      FIXME: escape ",
-                                        *      and move all of this logic
-                                        *      to a function.
+                                        *      We always print this condition.
                                         */
-                                       printf("\"%s\"", condition->rhs);
+                                       printf(" %s ", lrad_int2str(rlm_policy_tokens,
+                                                                   condition->compare,
+                                                                   "?"));
+                                       if (condition->rhs_type == POLICY_LEX_BARE_WORD) {
+                                               printf("%s", condition->rhs);
+                                       } else {
+                                               /*
+                                                *      FIXME: escape ",
+                                                *      and move all of this logic
+                                                *      to a function.
+                                                */
+                                               printf("\"%s\"", condition->rhs);
+                                       }
                                }
                                printf(")");
                                
-                               if (condition->child_condition != POLICY_LEX_BAD) {
+                               if ((condition->child_condition != POLICY_LEX_BAD) &&
+                                   (condition->child_condition != POLICY_LEX_BARE_WORD)) {
                                        printf(" %s ", lrad_int2str(rlm_policy_tokens, condition->child_condition, "?"));
                                        policy_print(condition->child, indent);
                                }
@@ -238,28 +243,22 @@ void rlm_policy_print(const policy_item_t *item)
 }
 
 /*
- *     Internal stack of things to do.
+ *     Internal stack of things to do.  This lets us have function
+ *     calls...
  *
- *     When a function is about to be pushed onto the stack, we walk
- *     backwards through the stack, and ensure that the function is
- *     not already there.  This prevents infinite recursion.
- *
- *     This means that we NEVER pop functions.  Rather, we push the
- *     function, and then immediately push it's first element.
- *
- *     When we've finished popping all of the elements, we pop the
- *     function, realize it's a function, ignore it, and pop one more
- *     entry.
+ *     Yes, we should learn lex, yacc, etc.
  */
 #define POLICY_MAX_STACK 16
 typedef struct policy_state_t {
        rlm_policy_t    *inst;
-       int             depth;
        REQUEST         *request; /* so it's not passed on the C stack */
+       int             depth;
        const policy_item_t *stack[POLICY_MAX_STACK];
 } policy_state_t;
 
 
+static int policy_evaluate_name(policy_state_t *state, const char *name);
+
 /*
  *     Push an item onto the state.
  */
@@ -325,6 +324,7 @@ static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem)
        rad_assert(pitem != NULL);
        rad_assert(state->depth >= 0);
 
+ redo:
        if (state->depth == 0) {
                *pitem = NULL;
                return 0;
@@ -333,6 +333,13 @@ static int policy_stack_pop(policy_state_t *state, const policy_item_t **pitem)
        *pitem = state->stack[state->depth - 1];
 
        /*
+        *      Named policies are on the stack for catching recursion.
+        */
+       if ((*pitem)->type == POLICY_TYPE_NAMED_POLICY) {
+               goto redo;
+       }
+
+       /*
         *      Process the whole item list.
         */
        if ((*pitem)->next) {
@@ -425,6 +432,8 @@ static VALUE_PAIR *find_vp(REQUEST *request, const char *name)
 
 /*
  *     Evaluate an assignment
+ *
+ *     Not really used much...
  */
 static int evaluate_assignment(policy_state_t *state, const policy_item_t *item)
 {
@@ -488,6 +497,18 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
                rcode = (rcode == FALSE); /* reverse sense of test */
                break;
 
+       case POLICY_LEX_BARE_WORD:
+               /*
+                *      We can't call evaluate_call here, because that just
+                *      pushes stuff onto the stack, and we want to actually
+                *      evaluate all of it...
+                *
+                *      Hmm.... why are these things different?
+                */
+               rcode = policy_evaluate_name(state,
+                                            ((const policy_named_t *) this->child)->name);
+               break;
+
        case POLICY_LEX_CMP_TRUE: /* existence */
                if (this->lhs_type == POLICY_LEX_BARE_WORD) {
                        vp = find_vp(state->request, this->lhs);
@@ -889,6 +910,11 @@ static int evaluate_call(policy_state_t *state, const policy_item_t *item)
        rad_assert(policy->policy->type != POLICY_TYPE_BAD);
        rad_assert(policy->policy->type < POLICY_TYPE_NUM_TYPES);
 
+       rcode = policy_stack_push(state, (const policy_item_t *) policy);
+       if (!rcode) {
+               return rcode;
+       }
+
        /*
         *      Push it onto the stack.  Other code will take care of
         *      calling it.
@@ -898,14 +924,6 @@ static int evaluate_call(policy_state_t *state, const policy_item_t *item)
                return rcode;
        }
 
-       /*
-        *      Function calls always succeed?
-        *
-        *      FIXME: Push the function name, etc. onto the stack,
-        *      so we can check for infinite recursion above, and
-        *      so we can also check for return codes from functions
-        *      we call...
-        */
        return 1;
 }
 
index b43d82f..1edf02d 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "rlm_policy.h"
 
+
 /*
  *     Explanations of what the lexical tokens are.
  */
@@ -381,6 +382,9 @@ typedef struct policy_lex_file_t {
 
 #define debug_tokens if (lexer->debug & POLICY_DEBUG_PRINT_TOKENS) printf
 
+static int parse_call(policy_lex_file_t *lexer, policy_item_t **tail,
+                     const char *name);
+
 /*
  *     Function to return a token saying what it read, and possibly
  *     a buffer of the quoted string or bare word.
@@ -660,6 +664,34 @@ static int parse_condition(policy_lex_file_t *lexer, policy_item_t **tail)
                break;
 
        case POLICY_LEX_BARE_WORD:
+               this->lhs_type = token;
+               token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
+               if (token == POLICY_LEX_L_BRACKET) {
+                       debug_tokens("[IF-CALL %s] ", lhs);
+
+                       /*
+                        *      Function call.
+                        */
+                       if (rlm_policy_find(lexer->policies, lhs) == NULL) {
+                               fprintf(stderr, "%s[%d]: Undefined function \"%s\"\n",
+                                       lexer->filename, lexer->lineno,
+                                       lhs);
+                               rlm_policy_free_item((policy_item_t *) this);
+                               return 0;
+                               
+                       }
+                       
+                       this->lhs = strdup(lhs);
+                       this->lhs_type = POLICY_LEX_BARE_WORD;
+                       this->compare = POLICY_LEX_BARE_WORD;
+                       this->child_condition = POLICY_LEX_BARE_WORD;
+
+                       if (!parse_call(lexer, &this->child, lhs)) {
+                               return 0;
+                       }
+                       break;
+               } /* else it's a comparison? */
+
        case POLICY_LEX_DOUBLE_QUOTED_STRING:
                this->lhs_type = token;
 
@@ -1048,9 +1080,10 @@ static int parse_statement(policy_lex_file_t *lexer, policy_item_t **tail)
                         *      Is a named policy, parse the reference to it.
                         */
                        if (rlm_policy_find(lexer->policies, lhs) != NULL) {
-                               if (parse_call(lexer, tail, lhs)) {
-                                       return 1;
+                               if (!parse_call(lexer, tail, lhs)) {
+                                       return 0;
                                }
+                               return 1;
                        }
 
                        /*
index ca28da0..41841c7 100644 (file)
@@ -111,6 +111,7 @@ typedef enum policy_reserved_word_t {
        POLICY_RESERVED_NUM_WORDS
 } policy_reserved_word_t;
 
+
 #define POLICY_DEBUG_NONE           0
 #define POLICY_DEBUG_PEEK           (1 << 0)
 #define        POLICY_DEBUG_PRINT_TOKENS   (1 << 1)