X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fcrule.c;h=1a1fd2150e53a46cbf8224b771d703bb8d2d6a6e;hb=dc84c4782beab4f9ed5e63f988fc9e4c73141da0;hp=d956ede0edd247d5a58ae21fdd63c654cfac0883;hpb=525130db7bae2c188f1588ca164e82d1ce736f46;p=ircu2.10.12-pk.git diff --git a/ircd/crule.c b/ircd/crule.c index d956ede..1a1fd21 100644 --- a/ircd/crule.c +++ b/ircd/crule.c @@ -1,9 +1,11 @@ -/* - * SmartRoute phase 1 - * connection rule patch +/** + * @file + * @brief Connection rule parser and checker + * @version $Id$ + * * by Tony Vencill (Tonto on IRC) * - * The majority of this file is a recusive descent parser used to convert + * The majority of this file is a recursive descent parser used to convert * connection rules into expression trees when the conf file is read. * All parsing structures and types are hidden in the interest of good * programming style and to make possible future data structure changes @@ -30,8 +32,30 @@ * the rule functions are made empty functions as in the stand-alone * test parser. * - * $Id$ + * The production rules for the grammar are as follows ("rule" is the + * starting production): + * + * rule: + * orexpr END END is end of input or : + * orexpr: + * andexpr + * andexpr || orexpr + * andexpr: + * primary + * primary && andexpr + * primary: + * function + * ! primary + * ( orexpr ) + * function: + * word ( ) word is alphanumeric string, first character + * word ( arglist ) must be a letter + * arglist: + * word + * word , arglist */ +#include "config.h" + #include "crule.h" #ifndef CR_DEBUG @@ -61,7 +85,7 @@ strcpy(x,y); \ } while(0) -/* We don't care about collation discrepacies here, it seems.... */ +/* We don't care about collation discrepancies here, it seems.... */ #define ircd_strcmp strcasecmp #endif @@ -79,45 +103,65 @@ #endif /* some constants and shared data types */ -#define CR_MAXARGLEN 80 /* why 80? why not? it's > hostname lengths */ -#define CR_MAXARGS 3 /* There's a better way to do this, - but not now. */ +#define CR_MAXARGLEN 80 /**< Maximum arg length (must be > HOSTLEN) */ +#define CR_MAXARGS 3 /**< Maximum number of args for a rule */ /* * Some symbols for easy reading */ +/** Input scanner tokens. */ enum crule_token { - CR_UNKNOWN, CR_END, CR_AND, CR_OR, CR_NOT, CR_OPENPAREN, CR_CLOSEPAREN, - CR_COMMA, CR_WORD + CR_UNKNOWN, /**< Unknown token type. */ + CR_END, /**< End of input ('\\0' or ':'). */ + CR_AND, /**< Logical and operator (&&). */ + CR_OR, /**< Logical or operator (||). */ + CR_NOT, /**< Logical not operator (!). */ + CR_OPENPAREN, /**< Open parenthesis. */ + CR_CLOSEPAREN, /**< Close parenthesis. */ + CR_COMMA, /**< Comma. */ + CR_WORD /**< Something that looks like a hostmask (alphanumerics, "*?.-"). */ }; +/** Parser error codes. */ enum crule_errcode { - CR_NOERR, CR_UNEXPCTTOK, CR_UNKNWTOK, CR_EXPCTAND, CR_EXPCTOR, - CR_EXPCTPRIM, CR_EXPCTOPEN, CR_EXPCTCLOSE, CR_UNKNWFUNC, CR_ARGMISMAT + CR_NOERR, /**< No error. */ + CR_UNEXPCTTOK, /**< Invalid token given context. */ + CR_UNKNWTOK, /**< Input did not form a valid token. */ + CR_EXPCTAND, /**< Did not see expected && operator. */ + CR_EXPCTOR, /**< Did not see expected || operator. */ + CR_EXPCTPRIM, /**< Expected a primitive (parentheses, ! or word). */ + CR_EXPCTOPEN, /**< Expected an open parenthesis after function name. */ + CR_EXPCTCLOSE, /**< Expected a close parenthesis to match open parenthesis. */ + CR_UNKNWFUNC, /**< Attempt to use an unknown function. */ + CR_ARGMISMAT /**< Wrong number of arguments to function. */ }; /* * Expression tree structure, function pointer, and tree pointer local! */ +/** Evaluation function for a connection rule. */ typedef int (*crule_funcptr) (int, void **); +/** Node in a connection rule tree. */ struct CRuleNode { - crule_funcptr funcptr; - int numargs; - void *arg[CR_MAXARGS]; /* For operators arg points to a tree element; - for functions arg points to a char string. */ + crule_funcptr funcptr; /**< Evaluation function for this node. */ + int numargs; /**< Number of arguments. */ + void *arg[CR_MAXARGS]; /**< Array of arguments. For operators, each arg + is a tree element; for functions, each arg is + a string. */ }; +/** Typedef to save typing effort. */ typedef struct CRuleNode* CRuleNodePtr; /* local rule function prototypes */ -static int crule_connected(int, void **); -static int crule_directcon(int, void **); -static int crule_via(int, void **); -static int crule_directop(int, void **); -static int crule__andor(int, void **); -static int crule__not(int, void **); +static int crule_connected(int, void *[]); +static int crule_directcon(int, void *[]); +static int crule_via(int, void *[]); +static int crule_directop(int, void *[]); +static int crule__andor(int, void *[]); +static int crule__not(int, void *[]); /* local parsing function prototypes */ static int crule_gettoken(int* token, const char** str); @@ -140,7 +184,7 @@ void print_tree(CRuleNodePtr); #endif #endif -/* error messages */ +/** Error messages, indexed by the corresponding crule_errcode. */ char *crule_errstr[] = { "Unknown error", /* NOERR? - for completeness */ "Unexpected token", /* UNEXPCTTOK */ @@ -154,13 +198,14 @@ char *crule_errstr[] = { "Argument mismatch" /* ARGMISMAT */ }; -/* function table - null terminated */ +/** Connection rule function table entry. */ struct crule_funclistent { - char name[15]; /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */ - int reqnumargs; - crule_funcptr funcptr; + char name[15]; /**< Function name. */ + int reqnumargs; /**< Required number of arguments. */ + crule_funcptr funcptr; /**< Handler function. */ }; +/** Defined connection rules. */ struct crule_funclistent crule_funclist[] = { /* maximum function name length is 14 chars */ {"connected", 1, crule_connected}, @@ -170,32 +215,37 @@ struct crule_funclistent crule_funclist[] = { {"", 0, NULL} /* this must be here to mark end of list */ }; -#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) +/** Check whether any connected server matches crulearg[0]. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ static int crule_connected(int numargs, void *crulearg[]) { +#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) struct Client *acptr; /* taken from m_links */ - for (acptr = GlobalClientList; acptr; acptr = acptr->next) + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { - if (!IsServer(acptr) && !IsMe(acptr)) + if (!IsServer(acptr) || IsMe(acptr)) continue; if (match((char *)crulearg[0], cli_name(acptr))) continue; return (1); } +#endif return (0); } -#else -static int crule_connected(int numargs, void **crulearg) -{ - return (0); -} -#endif -#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) +/** Check whether any directly connected server matches crulearg[0]. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ static int crule_directcon(int numargs, void *crulearg[]) { +#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) int i; struct Client *acptr; @@ -208,42 +258,42 @@ static int crule_directcon(int numargs, void *crulearg[]) continue; return (1); } +#endif return (0); } -#else -static int crule_directcon(int numargs, void **crulearg) -{ - return (0); -} -#endif -#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) +/** Check whether a connected server matching crulearg[1] is + * connnected to me behind one matching crulearg[0]. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ static int crule_via(int numargs, void *crulearg[]) { +#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) struct Client *acptr; /* adapted from m_links */ - for (acptr = GlobalClientList; acptr; acptr = acptr->next) + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { - if (!IsServer(acptr) && !IsMe(acptr)) + if (!IsServer(acptr) || IsMe(acptr)) continue; if (match((char *)crulearg[1], cli_name(acptr))) continue; - if (match((char *)crulearg[0], - cli_name(LocalClientArray[(cli_from(acptr))->fd]))) + if (match((char *)crulearg[0], cli_name(cli_from(acptr)))) continue; return (1); } +#endif return (0); } -#else -static int crule_via(int numargs, void **crulearg) -{ - return (0); -} -#endif -static int crule_directop(int numargs, void **crulearg) +/** Check whether we have a local IRC operator. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ +static int crule_directop(int numargs, void *crulearg[]) { #if !defined(CR_DEBUG) && !defined(CR_CHKCONF) int i; @@ -260,39 +310,47 @@ static int crule_directop(int numargs, void **crulearg) return (0); } +/** Evaluate a connection rule. + * @param[in] rule Rule to evalute. + * @return Non-zero if the rule allows the connection, zero otherwise. + */ +int crule_eval(struct CRuleNode* rule) +{ + return (rule->funcptr(rule->numargs, rule->arg)); +} + +/** Perform an and-or-or test on crulearg[0] and crulearg[1]. + * If crulearg[2] is non-NULL, it means do OR; if it is NULL, do AND. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ static int crule__andor(int numargs, void *crulearg[]) { int result1; - result1 = ((CRuleNodePtr) crulearg[0])->funcptr - (((CRuleNodePtr) crulearg[0])->numargs, - ((CRuleNodePtr) crulearg[0])->arg); + result1 = crule_eval(crulearg[0]); if (crulearg[2]) /* or */ - return (result1 || - ((CRuleNodePtr) crulearg[1])->funcptr - (((CRuleNodePtr) crulearg[1])->numargs, - ((CRuleNodePtr) crulearg[1])->arg)); + return (result1 || crule_eval(crulearg[1])); else - return (result1 && - ((CRuleNodePtr) crulearg[1])->funcptr - (((CRuleNodePtr) crulearg[1])->numargs, - ((CRuleNodePtr) crulearg[1])->arg)); + return (result1 && crule_eval(crulearg[1])); } +/** Logically invert the result of crulearg[0]. + * @param[in] numargs Number of valid args in \a crulearg. + * @param[in] crulearg Argument array. + * @return Non-zero if the condition is true, zero if not. + */ static int crule__not(int numargs, void *crulearg[]) { - return (!((CRuleNodePtr) crulearg[0])->funcptr - (((CRuleNodePtr) crulearg[0])->numargs, - ((CRuleNodePtr) crulearg[0])->arg)); -} - -#if !defined(CR_DEBUG) && !defined(CR_CHKCONF) -int crule_eval(struct CRuleNode* rule) -{ - return (rule->funcptr(rule->numargs, rule->arg)); + return (!crule_eval(crulearg[0])); } -#endif +/** Scan an input token from \a ruleptr. + * @param[out] next_tokp Receives type of next token. + * @param[in,out] ruleptr Next readable character from input. + * @return Either CR_UNKNWTOK if the input was unrecognizable, else CR_NOERR. + */ static int crule_gettoken(int* next_tokp, const char** ruleptr) { char pending = '\0'; @@ -350,6 +408,12 @@ static int crule_gettoken(int* next_tokp, const char** ruleptr) return CR_NOERR; } +/** Scan a word from \a ruleptr. + * @param[out] word Output buffer. + * @param[out] wordlenp Length of word written to \a word (not including terminating NUL). + * @param[in] maxlen Maximum number of bytes writable to \a word. + * @param[in,out] ruleptr Next readable character from input. + */ static void crule_getword(char* word, int* wordlenp, size_t maxlen, const char** ruleptr) { char *word_ptr; @@ -364,26 +428,9 @@ static void crule_getword(char* word, int* wordlenp, size_t maxlen, const char** *wordlenp = word_ptr - word; } -/* - * Grammar - * rule: - * orexpr END END is end of input or : - * orexpr: - * andexpr - * andexpr || orexpr - * andexpr: - * primary - * primary && andexpr - * primary: - * function - * ! primary - * ( orexpr ) - * function: - * word ( ) word is alphanumeric string, first character - * word ( arglist ) must be a letter - * arglist: - * word - * word , arglist +/** Parse an entire rule. + * @param[in] rule Text form of rule. + * @return CRuleNode for rule, or NULL if there was a parse error. */ struct CRuleNode* crule_parse(const char *rule) { @@ -414,6 +461,12 @@ struct CRuleNode* crule_parse(const char *rule) return 0; } +/** Parse an or expression. + * @param[out] orrootp Receives parsed node. + * @param[in,out] next_tokp Next input token type. + * @param[in,out] ruleptr Next input character. + * @return A crule_errcode value. + */ static int crule_parseorexpr(CRuleNodePtr * orrootp, int *next_tokp, const char** ruleptr) { int errcode = CR_NOERR; @@ -469,6 +522,12 @@ static int crule_parseorexpr(CRuleNodePtr * orrootp, int *next_tokp, const char* return (errcode); } +/** Parse an and expression. + * @param[out] androotp Receives parsed node. + * @param[in,out] next_tokp Next input token type. + * @param[in,out] ruleptr Next input character. + * @return A crule_errcode value. + */ static int crule_parseandexpr(CRuleNodePtr * androotp, int *next_tokp, const char** ruleptr) { int errcode = CR_NOERR; @@ -524,6 +583,12 @@ static int crule_parseandexpr(CRuleNodePtr * androotp, int *next_tokp, const cha return (errcode); } +/** Parse a primary expression. + * @param[out] primrootp Receives parsed node. + * @param[in,out] next_tokp Next input token type. + * @param[in,out] ruleptr Next input character. + * @return A crule_errcode value. + */ static int crule_parseprimary(CRuleNodePtr* primrootp, int *next_tokp, const char** ruleptr) { CRuleNodePtr *insertionp; @@ -579,6 +644,12 @@ static int crule_parseprimary(CRuleNodePtr* primrootp, int *next_tokp, const cha return (errcode); } +/** Parse a function call. + * @param[out] funcrootp Receives parsed node. + * @param[in,out] next_tokp Next input token type. + * @param[in,out] ruleptr Next input character. + * @return A crule_errcode value. + */ static int crule_parsefunction(CRuleNodePtr* funcrootp, int* next_tokp, const char** ruleptr) { int errcode = CR_NOERR; @@ -623,6 +694,12 @@ static int crule_parsefunction(CRuleNodePtr* funcrootp, int* next_tokp, const ch return (CR_EXPCTOPEN); } +/** Parse the argument list to a CRuleNode. + * @param[in,out] argrootp Node whos argument list is being populated. + * @param[in,out] next_tokp Next input token type. + * @param[in,out] ruleptr Next input character. + * @return A crule_errcode value. + */ static int crule_parsearglist(CRuleNodePtr argrootp, int *next_tokp, const char** ruleptr) { int errcode = CR_NOERR; @@ -677,9 +754,12 @@ static int crule_parsearglist(CRuleNodePtr argrootp, int *next_tokp, const char* /* * This function is recursive.. I wish I knew a nonrecursive way but - * I dont. anyway, recursion is fun.. :) - * DO NOT CALL THIS FUNTION WITH A POINTER TO A NULL POINTER - * (ie: If *elem is NULL, you're doing it wrong - seg fault) + * I don't. Anyway, recursion is fun.. :) + * DO NOT CALL THIS FUNCTION WITH A POINTER TO A NULL POINTER + * (i.e.: If *elem is NULL, you're doing it wrong - seg fault) + */ +/** Free a connection rule and all its children. + * @param[in,out] elem Pointer to pointer to element to free. MUST NOT BE NULL. */ void crule_free(struct CRuleNode** elem) { @@ -687,7 +767,7 @@ void crule_free(struct CRuleNode** elem) if ((*(elem))->funcptr == crule__not) { - /* type conversions and ()'s are fun! ;) here have an asprin.. */ + /* type conversions and ()'s are fun! ;) here have an aspirin.. */ if ((*(elem))->arg[0] != NULL) crule_free((struct CRuleNode**) &((*(elem))->arg[0])); } @@ -711,6 +791,9 @@ void crule_free(struct CRuleNode** elem) } #ifdef CR_DEBUG +/** Display a connection rule as text. + * @param[in] printelem Connection rule to display. + */ static void print_tree(CRuleNodePtr printelem) { int funcnum, arg; @@ -755,6 +838,9 @@ static void print_tree(CRuleNodePtr printelem) #endif #ifdef CR_DEBUG +/** Read connection rules from stdin and display parsed forms as text. + * @return Zero. + */ int main(void) { char indata[256];