Policy functions can now have return codes. The default is "ok".
authoraland <aland>
Thu, 10 Feb 2005 22:56:37 +0000 (22:56 +0000)
committeraland <aland>
Thu, 10 Feb 2005 22:56:37 +0000 (22:56 +0000)
The return codes are the module return codes, for simplicity.

The return codes can be checked in conditions, so:

if (foo() == ok) {
...
        } else {
...
}

will work.  There's no fail-over, or assignment of return codes
to variables, or possibility to check multiple return codes.

This is NOT a real language.  It's a nasty hack to get interesting
things done...

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

index 0c35594..c1c441b 100644 (file)
@@ -113,8 +113,8 @@ static void policy_print(const policy_item_t *item, int indent)
                                        break;
                                }
 
-                               if (condition->lhs_type == POLICY_LEX_BARE_WORD) {
-                                       printf("%s", condition->lhs);
+                               if (condition->lhs_type == POLICY_LEX_FUNCTION) {
+                                       printf("%s()", condition->lhs);
                                } else {
                                        /*
                                         *      FIXME: escape ",
@@ -124,25 +124,21 @@ static void policy_print(const policy_item_t *item, int indent)
                                        printf("\"%s\"", condition->lhs);
                                }
 
-                               if (condition->compare == POLICY_LEX_BARE_WORD) {
-                                       printf("()");
+                               /*
+                                *      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);
                                } else {
                                        /*
-                                        *      We always print this condition.
+                                        *      FIXME: escape ",
+                                        *      and move all of this logic
+                                        *      to a function.
                                         */
-                                       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("\"%s\"", condition->rhs);
                                }
                                printf(")");
                                
@@ -223,6 +219,18 @@ static void policy_print(const policy_item_t *item, int indent)
                        }
                        break;
 
+               case POLICY_TYPE_RETURN:
+                       {
+                               const policy_return_t *this;
+
+                               this = (const policy_return_t *) item;
+                               if (indent) printf("%*s", indent, " ");
+                               printf("return %s\n",
+                                      lrad_int2str(policy_return_codes,
+                                                   this->rcode, "???"));
+                       }
+                       break;
+
                default:
                        if (indent) printf("%*s", indent, " ");
                        printf("[HUH?]\n");
@@ -252,6 +260,7 @@ void rlm_policy_print(const policy_item_t *item)
 typedef struct policy_state_t {
        rlm_policy_t    *inst;
        REQUEST         *request; /* so it's not passed on the C stack */
+       int             rcode;  /* for functions, etc. */
        int             depth;
        const policy_item_t *stack[POLICY_MAX_STACK];
 } policy_state_t;
@@ -373,6 +382,10 @@ static int evaluate_print(policy_state_t *state, const policy_item_t *item)
                printf("%s", buffer);
        }
 
+       /*
+        *      Doesn't change state->rcode
+        */
+
        return 1;
 }
 
@@ -465,7 +478,7 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
        int rcode;
        const policy_condition_t *this;
        VALUE_PAIR *vp;
-       char *data = NULL;
+       const char *data = NULL;
        int compare;
 #ifdef HAVE_REGEX_H
        regex_t reg;
@@ -479,11 +492,22 @@ static int evaluate_condition(policy_state_t *state, const policy_item_t *item)
        /*
         *      FIXME: Don't always do this...
         */
-       if ((this->compare != POLICY_LEX_L_BRACKET) &&
-           (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING)) {
-               if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
-                               state->request, NULL) > 0) {
-                       data = lhs_buffer;
+       if (this->compare != POLICY_LEX_L_BRACKET) {
+               if (this->lhs_type == POLICY_LEX_FUNCTION) {
+                       /*
+                        *      We can't call evaluate_call here,
+                        *      because that just pushes stuff onto
+                        *      the stack, and we want to actually
+                        *      evaluate all of it...
+                        */
+                       rcode = policy_evaluate_name(state, this->lhs);
+                       data = lrad_int2str(policy_return_codes, rcode, "???");
+                       strNcpy(lhs_buffer, data, sizeof(lhs_buffer)); /* FIXME: yuck */
+               } else if (this->lhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) {
+                       if (radius_xlat(lhs_buffer, sizeof(lhs_buffer), this->lhs,
+                                       state->request, NULL) > 0) {
+                               data = lhs_buffer;
+                       }
                }
        }
        
@@ -497,18 +521,6 @@ 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);
@@ -887,12 +899,14 @@ static int evaluate_attr_list(policy_state_t *state, const policy_item_t *item)
                return 0;
        }
 
+       state->rcode = RLM_MODULE_UPDATED; /* we did stuff */
+
        return 1;
 }
 
 
 /*
- *     Evaluate an 'call foo' statement
+ *     Evaluate a reference call to a module.
  */
 static int evaluate_call(policy_state_t *state, const policy_item_t *item)
 {
@@ -910,6 +924,12 @@ 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);
 
+       /*
+        *      Push the name of the function onto the stack,
+        *      so that we can catch recursive calls.
+        *
+        *      The "pop" function will skip over it when it sees it.
+        */
        rcode = policy_stack_push(state, (const policy_item_t *) policy);
        if (!rcode) {
                return rcode;
@@ -929,6 +949,20 @@ static int evaluate_call(policy_state_t *state, const policy_item_t *item)
 
 
 /*
+ *     Evaluate a return statement
+ */
+static int evaluate_return(policy_state_t *state, const policy_item_t *item)
+{
+       const policy_return_t *this;
+
+       this = (const policy_return_t *) item;
+       state->rcode = this->rcode;
+       
+       return 1;               /* we succeeded */
+}
+
+
+/*
  *     State machine stuff.
  */
 typedef int (*policy_evaluate_type_t)(policy_state_t *, const policy_item_t *);
@@ -945,7 +979,8 @@ static policy_evaluate_type_t evaluate_functions[POLICY_TYPE_NUM_TYPES] = {
        evaluate_attr_list,
        evaluate_print,
        NULL,                   /* define a named policy.. */
-       evaluate_call
+       evaluate_call,
+       evaluate_return
 };
 
 
@@ -990,7 +1025,7 @@ static int policy_evaluate_name(policy_state_t *state, const char *name)
                }
        } /* loop until the stack is empty */
 
-       return RLM_MODULE_OK;
+       return state->rcode;
 }
 
 
@@ -1007,6 +1042,7 @@ int rlm_policy_evaluate(rlm_policy_t *inst, REQUEST *request, const char *name)
        memset(state, 0, sizeof(*state));
        state->request = request;
        state->inst = inst;
+       state->rcode = RLM_MODULE_OK;
 
        rcode = policy_evaluate_name(state, name);
 
index 78a6d04..54366e3 100644 (file)
 #include <dirent.h>
 #endif
 
+#include <modules.h>
+
+const LRAD_NAME_NUMBER policy_return_codes[] = {
+       { "reject", RLM_MODULE_REJECT },
+       { "fail", RLM_MODULE_FAIL },
+       { "ok", RLM_MODULE_OK },
+       { "handled", RLM_MODULE_HANDLED },
+       { "invalid", RLM_MODULE_INVALID },
+       { "userlock", RLM_MODULE_USERLOCK },
+       { "notfound", RLM_MODULE_NOTFOUND },
+       { "noop", RLM_MODULE_NOOP },
+       { "updated", RLM_MODULE_UPDATED },
+       { NULL, RLM_MODULE_NUMCODES }
+};
+
 /*
  *     Explanations of what the lexical tokens are.
  */
@@ -388,8 +403,6 @@ 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
@@ -517,6 +530,7 @@ const LRAD_NAME_NUMBER policy_reserved_words[] = {
        { "proxy-request", POLICY_RESERVED_PROXY_REQUEST },
        { "proxy-reply", POLICY_RESERVED_PROXY_REPLY },
        { "include", POLICY_RESERVED_INCLUDE },
+       { "return", POLICY_RESERVED_RETURN },
        { NULL, POLICY_RESERVED_UNKNOWN }
 };
 
@@ -632,15 +646,30 @@ static int parse_condition(policy_lex_file_t *lexer, policy_item_t **tail)
                                
                        }
                        
-                       this->lhs = strdup(lhs);
-                       this->lhs_type = POLICY_LEX_BARE_WORD;
-                       this->compare = POLICY_LEX_BARE_WORD;
-                       this->child_condition = POLICY_LEX_BARE_WORD;
+                       /*
+                        *      this->lhs set up below, after "check"
+                        */
+                       this->lhs_type = POLICY_LEX_FUNCTION;
 
-                       if (!parse_call(lexer, &this->child, lhs)) {
+                       /*
+                        *      Copied from parse_call
+                        */
+                       token = policy_lex_file(lexer, 0, NULL, 0);
+                       if (token != POLICY_LEX_L_BRACKET) {
+                               fprintf(stderr, "%s[%d]: Expected left bracket, got \"%s\"\n",
+                                       lexer->filename, lexer->lineno,
+                                       lrad_int2str(rlm_policy_tokens, token, "?"));
                                return 0;
                        }
-                       break;
+                       
+                       token = policy_lex_file(lexer, 0, NULL, 0);
+                       if (token != POLICY_LEX_R_BRACKET) {
+                               fprintf(stderr, "%s[%d]: Expected right bracket, got \"%s\"\n",
+                                       lexer->filename, lexer->lineno,
+                                       lrad_int2str(rlm_policy_tokens, token, "?"));
+                               return 0;
+                       }
+                       goto check;
                } /* else it's a comparison? */
 
        case POLICY_LEX_DOUBLE_QUOTED_STRING:
@@ -649,6 +678,7 @@ static int parse_condition(policy_lex_file_t *lexer, policy_item_t **tail)
                /*
                 *      Got word.  May just be test for existence.
                 */
+       check:
                token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK, NULL, 0);
                if (token == POLICY_LEX_R_BRACKET) {
                        debug_tokens("[TEST %s] ", lhs);
@@ -892,6 +922,54 @@ static int parse_attribute_block(policy_lex_file_t *lexer,
 
 
 /*
+ *     Parse a return statement.
+ */
+static int parse_return(policy_lex_file_t *lexer, policy_item_t **tail)
+{
+       int rcode;
+       policy_lex_t token;
+       char buffer[32];
+       policy_return_t *this;
+
+       token = policy_lex_file(lexer, 0, buffer, sizeof(buffer));
+       if (token != POLICY_LEX_BARE_WORD) {
+               fprintf(stderr, "%s[%d]: Unexpected token %s\n",
+                       lexer->filename, lexer->lineno,
+                       lrad_int2str(rlm_policy_tokens, token, "?"));
+               return 0;
+       }
+
+       rcode = lrad_str2int(policy_return_codes, buffer, RLM_MODULE_NUMCODES);
+       if (rcode == RLM_MODULE_NUMCODES) {
+               fprintf(stderr, "%s[%d]: Invalid return code %s\n",
+                       lexer->filename, lexer->lineno, buffer);
+               return 0;
+       }
+
+       /*
+        *      Look for more sutff
+        */
+       token = policy_lex_file(lexer, POLICY_LEX_FLAG_PEEK,
+                               NULL, sizeof(0));
+       if (token != POLICY_LEX_RC_BRACKET) {
+               fprintf(stderr, "%s[%d]: return statement must be the last statement in a policy.\n",
+                       lexer->filename, lexer->lineno);
+               return 0;
+       }
+
+       this = rad_malloc(sizeof(*this));
+       memset(this, 0, sizeof(*this));
+
+       this->item.type = POLICY_TYPE_RETURN;
+       this->item.lineno = lexer->lineno;
+       this->rcode = rcode;
+
+       *tail = (policy_item_t *) this;
+
+       return 1;
+}
+
+/*
  *     Parse one statement.  'foo = bar', or 'if (...) {...}', or '{...}',
  *     and so on.
  */
@@ -945,6 +1023,13 @@ static int parse_statement(policy_lex_file_t *lexer, policy_item_t **tail)
                        return 0;
                        break;
                        
+               case POLICY_RESERVED_RETURN:
+                       if (parse_return(lexer, tail)) {
+                               return 1;
+                       }
+                       return 0;
+                       break;
+                       
                case POLICY_RESERVED_UNKNOWN: /* wasn't a reserved word */
                        /*
                         *      Is a named policy, parse the reference to it.
@@ -1208,7 +1293,7 @@ static int parse_named_policy(policy_lex_file_t *lexer)
         *      For now, policy names aren't scoped, they're global.
         */
        if (!rlm_policy_insert(lexer->policies, this)) {
-               fprintf(stderr, "Failed to insert %s\n", this->name);
+               fprintf(stderr, "Failed to insert policy \"%s\"\n", this->name);
                rlm_policy_free_item((policy_item_t *) this);
                return 0;
        }
@@ -1269,9 +1354,11 @@ static int parse_include(policy_lex_file_t *lexer)
                         */
                        while ((dp = readdir(dir)) != NULL) {
                                if (dp->d_name[0] == '.') continue;
-                               
+                               if (strchr(dp->d_name, '~') != NULL) continue;
+
                                strNcpy(p, dp->d_name,
                                        sizeof(buffer) - (p - buffer));
+                               debug_tokens("\nreading file %s\n", buffer);
                                if (!rlm_policy_parse(lexer->policies, buffer)) {
                                        closedir(dir);
                                        return 0;
@@ -1289,6 +1376,7 @@ static int parse_include(policy_lex_file_t *lexer)
        /*
         *      Handle one include file.
         */
+       debug_tokens("\nreading file %s\n", buffer);
        if (!rlm_policy_parse(lexer->policies, buffer)) {
                return 0;
        }
@@ -1304,7 +1392,7 @@ int rlm_policy_parse(rbtree_t *policies, const char *filename)
 {
        FILE *fp;
        policy_lex_t token;
-       policy_lex_file_t mylexer, *lexer;
+       policy_lex_file_t mylexer, *lexer = NULL;
        char buffer[32];
 
        fp = fopen(filename, "r");
index 1045e8d..f997a9f 100644 (file)
@@ -74,6 +74,7 @@ typedef enum policy_lex_t {
        POLICY_LEX_MINUS_EQUALS, /* -= */
        POLICY_LEX_CONCAT_EQUALS, /* .= */
        POLICY_LEX_VARIABLE,    /* %{foo} */
+       POLICY_LEX_FUNCTION,    /* Hmmm... */
        POLICY_LEX_DOUBLE_QUOTED_STRING,
        POLICY_LEX_SINGLE_QUOTED_STRING,
        POLICY_LEX_BACK_QUOTED_STRING,
@@ -89,6 +90,7 @@ typedef enum policy_type_t {
        POLICY_TYPE_PRINT,
        POLICY_TYPE_NAMED_POLICY,
        POLICY_TYPE_CALL,
+       POLICY_TYPE_RETURN,
        POLICY_TYPE_NUM_TYPES
 } policy_type_t;
 
@@ -109,6 +111,7 @@ typedef enum policy_reserved_word_t {
        POLICY_RESERVED_PRINT,
        POLICY_RESERVED_POLICY,
        POLICY_RESERVED_INCLUDE,
+       POLICY_RESERVED_RETURN,
        POLICY_RESERVED_NUM_WORDS
 } policy_reserved_word_t;
 
@@ -171,6 +174,15 @@ typedef struct policy_call_t {
 
 
 /*
+ *     Hold a return code
+ */
+typedef struct policy_return_t {
+       policy_item_t   item;
+       int             rcode;
+} policy_return_t;
+
+
+/*
  *     Holds an assignment.
  */
 typedef struct policy_assignment_t {
@@ -228,6 +240,7 @@ typedef struct rlm_policy_t {
  */
 extern const LRAD_NAME_NUMBER rlm_policy_tokens[];
 extern const LRAD_NAME_NUMBER policy_reserved_words[];
+extern const LRAD_NAME_NUMBER policy_return_codes[];
 
 extern int rlm_policy_insert(rbtree_t *head, policy_named_t *policy);
 extern policy_named_t *rlm_policy_find(rbtree_t *head, const char *name);