Search
j0ke.net Open Build Service
>
Projects
>
server:monitoring
>
tacacs+
> tacacs+-F4.0.4.15-k1.diff
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File tacacs+-F4.0.4.15-k1.diff of Package tacacs+
diff -urw ../tacacs+-F4.0.4.15/CHANGES ./CHANGES --- ../tacacs+-F4.0.4.15/CHANGES 2007-12-13 20:18:38.000000000 +0100 +++ ./CHANGES 2008-04-19 13:27:50.697162145 +0200 @@ -356,4 +356,15 @@ - Fix syslog facility selection - from Timo Vanoni & Josef Voggesser - Add -G/foreground option - Deal with missing socklen_t -p + +F4.0.4.15-k1 + Set of changes by Gabor Kiss borrowed from patch + http://bakacsin.ki.iif.hu/~kissg/pd/tac_plus/tacacs+-F4.0.4.14-k5.diff. + - Allow multiple group membership + - Fix a config tree traversal bug + - Add new keyword 'return' to ACL-s. If NAS address matches + such a line check of current ACL is terminated and search for + another ACL is continued in higher level groups. + - Add new keyword 'include'. Configuration files can be nested + in any depth. Syntax: is: include = /absolute/path/file + - Fix stderr/stdin confusion with -P option. diff -urw ../tacacs+-F4.0.4.15/config.c ./config.c --- ../tacacs+-F4.0.4.15/config.c 2007-12-13 20:18:38.000000000 +0100 +++ ./config.c 2008-04-19 13:01:43.763373472 +0200 @@ -108,8 +108,8 @@ static int sym_ch; /* current parse character */ static int sym_code; /* parser output */ static int sym_line = 1; /* current line number */ -static FILE *cf = NULL; /* config file pointer */ -static int sym_error = 0; /* a parsing error occurred */ +static FILE *cf = NULL; /* current cfg file pointer */ +static NODE *pending = NULL; /* chain of pending cfg files */ static int no_user_dflt = 0; /* default if user doesn't exist */ static char *authen_default = NULL; /* top level authentication default */ static char *nopasswd_str = "nopassword"; @@ -158,7 +158,7 @@ # endif #endif char *global; /* password to use if none set */ - char *member; /* group we are a member of */ + NODE *member; /* groups we are a member of */ char *expires; /* expiration date */ char *arap; /* our arap secret */ char *pap; /* our pap secret */ @@ -222,7 +222,7 @@ void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */ static VALUE cfg_get_hvalue(char *, int); -static VALUE cfg_get_value(char *, int, int, int); +static VALUE cfg_get_value(char *, int, int, int, ITER_CB *); static int circularity_check(void); static void free_aclstruct(ACL *); static void free_attrs(NODE *); @@ -247,6 +247,15 @@ static int parse_user(void); static void rch(void); static void sym_get(void); +static FILE * open_config(char *); +static int restore_config(void); +static void free_pending(void); + +typedef NODE ITERATOR; +static ITERATOR *new_iterator(char *, int); +static void free_iterator(ITERATOR *); +static NODE *next_iteration(ITERATOR *); +static int depth(ITERATOR *); #ifdef __STDC__ #include <stdarg.h> /* ANSI C, variable length args */ @@ -671,7 +680,7 @@ { ACL *n; ACL *acl = (ACL *) tac_malloc(sizeof(ACL)); - int isdeny = S_permit; + int perm; bzero(acl, sizeof(ACL)); @@ -696,13 +705,13 @@ return(0); case S_deny: - isdeny = S_deny; case S_permit: + case S_return: + perm = sym_code; sym_get(); parse(S_separator); - insert_acl_entry(acl, isdeny); + insert_acl_entry(acl, perm); parse(S_string); - isdeny = S_permit; continue; case S_closebra: @@ -823,6 +832,17 @@ parse_logging(); continue; + case S_include: + /* Process an include file */ + sym_get(); + parse(S_separator); + if (open_config(sym_buf)==NULL) { + parse_error("Cannot include file %s", sym_buf); + return 1; + } + sym_get(); + continue; + default: parse_error("Unrecognised token %s on line %d", sym_buf, sym_line); return(1); @@ -985,6 +1005,7 @@ int save_sym; char **fieldp; char buf[MAX_INPUT_LINE_LEN]; + NODE *newnode; fieldp = NULL; bzero(user, sizeof(USER)); @@ -1189,7 +1210,23 @@ continue; case S_member: - ASSIGN(user->member); + sym_get(); + parse(S_separator); + newnode = (NODE *)tac_malloc(sizeof(NODE)); + newnode->type = N_group; + newnode->value = NULL; + newnode->value1 = tac_strdup(sym_buf); + newnode->next=NULL; + newnode->line = sym_line; + if (user->member) { + /* append chain */ + NODE *p; + for (p=user->member; p->next; p=p->next) /* EMPTY */; + p->next = newnode; + } + else { + user->member = newnode; + } sym_get(); continue; @@ -1573,14 +1610,12 @@ static void rch(void) { - if (sym_error) { - sym_ch = EOF; - return; + while ((sym_ch = getc(cf)) == EOF) { + if (restore_config()) break; } - sym_ch = getc(cf); if (parse_only && sym_ch != EOF) - fprintf(stderr, "%c", sym_ch); + fputc(sym_ch, stdout); } /* For a user or group, find the value of a field. Does not recurse. */ @@ -1735,63 +1770,53 @@ static int circularity_check(void) { - USER *user, *entry, *group; + USER *entry; USER **users = (USER **) hash_get_entries(usertable); USER **groups = (USER **) hash_get_entries(grouptable); USER **p, **q; /* users */ for (p = users; *p; p++) { - user = *p; + ITERATOR *iterator; + NODE *node; if (debug & DEBUG_PARSE_FLAG) - report(LOG_DEBUG, "circularity_check: user=%s", user->name); + report(LOG_DEBUG, "circularity_check: user=%s", (*p)->name); /* Initialise all groups "seen" flags to zero */ for (q = groups; *q; q++) { - group = *q; - group->flags &= ~FLAG_SEEN; + (*q)->flags &= ~FLAG_SEEN; } - entry = user; - - while (entry) { - /* check groups we are a member of */ - char *groupname = entry->member; - - if (debug & DEBUG_PARSE_FLAG) - report(LOG_DEBUG, "\tmember of group %s", - groupname ? groupname : "<none>"); - - - /* if not a member of any groups, go on to next user */ - if (!groupname) - break; + iterator = new_iterator((*p)->name, 1); + node = next_iteration(iterator); - group = (USER *) hash_lookup(grouptable, groupname); - if (!group) { - report(LOG_ERR, "%s=%s, group %s does not exist", - (entry->flags & FLAG_ISUSER) ? "user" : "group", - entry->name, groupname); + while ((node = next_iteration(iterator))) { + entry = node->value; + if (entry == NULL) { free(users); free(groups); return(1); } - if (group->flags & FLAG_SEEN) { + /* check groups we are a member of */ + + if (debug & DEBUG_PARSE_FLAG) + report(LOG_DEBUG, "\t%member of group %s", + entry->name ? entry->name : "<none>"); + + if (entry->flags & FLAG_SEEN) { report(LOG_ERR, "recursively defined groups"); /* print all seen "groups" */ for (q = groups; *q; q++) { - group = *q; - if (group->flags & FLAG_SEEN) - report(LOG_ERR, "%s", group->name); + if ((*q)->flags & FLAG_SEEN) + report(LOG_ERR, "%s", (*q)->name); } free(users); free(groups); return(1); } - group->flags |= FLAG_SEEN; /* mark group as seen */ - entry = group; + entry->flags |= FLAG_SEEN; /* mark group as seen */ } } free(users); @@ -1810,9 +1835,11 @@ * really return a union pointer). */ static VALUE -cfg_get_value(char *name, int isuser, int attr, int recurse) +cfg_get_value(char *name, int isuser, int attr, int recurse, ITER_CB *cb) { USER *user, *group; + ITERATOR *iterator; + NODE *node; VALUE value; memset(&value, 0, sizeof(VALUE)); @@ -1822,44 +1849,42 @@ name, isuser, codestring(attr), recurse); /* find the user/group entry */ - user = (USER *) hash_lookup(isuser ? usertable : grouptable, name); + iterator = new_iterator(name, isuser); - if (!user) { + if (!iterator) { if (debug & DEBUG_CONFIG_FLAG) - report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name); + report(LOG_DEBUG, "cfg_get_value: no %s named %s", + isuser ? "user" : "group", name); return(value); } /* found the entry. Lookup value from attr=value */ + node = next_iteration(iterator); + user = node->value; value = get_value(user, attr); - if (value.pval || !recurse) { + if ((value.pval && (!cb || cb->fn(value, cb) == CFG_GET_TERMINATE)) || + !recurse) { + free_iterator(iterator); return(value); } - /* no value. Check containing group */ - if (user->member) - group = (USER *) hash_lookup(grouptable, user->member); - else - group = NULL; - - while (group) { + /* no value. Traverse tree of containing groups */ + while ((node = next_iteration(iterator))) { + group = node->value; if (debug & DEBUG_CONFIG_FLAG) - report(LOG_DEBUG, "cfg_get_value: recurse group = %s", group->name); + report(LOG_DEBUG, "cfg_get_value: recurse group=%s depth=%d", + group->name, depth(iterator)); value = get_value(group, attr); - if (value.pval) { + if (value.pval && (!cb || cb->fn(value, cb) == CFG_GET_TERMINATE)) { + free_iterator(iterator); return(value); } - /* still nothing. Check containing group and so on */ - - if (group->member) - group = (USER *) hash_lookup(grouptable, group->member); - else - group = NULL; } /* no value for this user or her containing groups */ memset(&value, 0, sizeof(VALUE)); + free_iterator(iterator); return(value); } @@ -1902,7 +1927,7 @@ { int val; - val = cfg_get_value(name, isuser, attr, recurse).intval; + val = cfg_get_value(name, isuser, attr, recurse, NULL).intval; if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val); @@ -1924,11 +1949,11 @@ } char * -cfg_get_pvalue(char *name, int isuser, int attr, int recurse) +cfg_get_pvalue(char *name, int isuser, int attr, int recurse, ITER_CB *cb) { char *p; - p = cfg_get_value(name, isuser, attr, recurse).pval; + p = cfg_get_value(name, isuser, attr, recurse, cb).pval; if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_pvalue: returns %s", @@ -1946,12 +1971,10 @@ { sym_line = 1; - if ((cf = fopen(cfile, "r")) == NULL) { - report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting", - cfile, strerror(errno)); + if (open_config(cfile) == NULL) { return(1); } - if (parse_decls() || sym_error) { + if (parse_decls()) { fclose(cf); return(1); } @@ -1962,9 +1985,83 @@ } fclose(cf); + cf = NULL; return(0); } +static FILE * +open_config(char *filename) +{ + if (cf != NULL) { + struct stat newstat; + NODE *newnode, *node; + + newnode = (NODE *) tac_malloc(sizeof(NODE)); + newnode->type = N_file; + newnode->next = pending; + newnode->value = cf; + newnode->line = sym_line + 1; + cf = NULL; + pending = newnode; + + /* check circularity */ + if (stat(filename, &newstat) == -1) { + report(LOG_ERR, "push_config: cannot fstat file %s: %s", + filename, strerror(errno)); + free_pending(); + return NULL; + } + for (node=pending; node; node=node->next) { + struct stat oldstat; + if (fstat(fileno(((FILE*)(node->value))), &oldstat) == -1) { + report(LOG_ERR, "save_config: cannot fstat file: %s", + strerror(errno)); + free_pending(); + return NULL; + } + if (newstat.st_dev == oldstat.st_dev && + newstat.st_ino == oldstat.st_ino) { + report(LOG_ERR, "save_config: endless loop of nested include files detected"); + free_pending(); + return NULL; + } + } + sym_line = 0; + } + else { + sym_line = 1; + } + if ((cf = fopen(filename, "r")) == NULL) { + report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting", + filename, strerror(errno)); + free_pending(); + return NULL; + } + return cf; +} + +static int +restore_config(void) +{ + NODE *node = pending; + + if (node == NULL) return 1; /* no more pending files */ + + if (cf) fclose(cf); + pending = node->next; + sym_line = node->line; /* restore line number */ + cf = node->value; /* restore file handle */ + + free(node); + + return 0; +} + +static void +free_pending(void) { + while (!restore_config()) /* EMPTY */; +} + /* return 1 if user exists, 0 otherwise */ int cfg_user_exists(char *username) @@ -1983,14 +2080,14 @@ char * cfg_get_expires(char *username, int recurse) { - return(cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse)); + return(cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse, NULL)); } #ifdef ACLS /* * check the acl against the provided ip. return S_permit (succeed) if the - * ip matches a permit, else S_deny (fail) if it matches a deny or does not - * match any of the entries. + * ip matches a 'permit', S_return if if matches a 'return', else S_deny (fail) + * if it matches a 'deny' or does not match any of the entries. */ int cfg_acl_check(char *aclname, char *ip) @@ -2012,8 +2109,10 @@ while (next) { if (regexec(next->value1, ip)) { if (debug & DEBUG_AUTHEN_FLAG) - report(LOG_DEBUG, "ip %s matched %s regex %s of acl filter %s", - ip, next->type == S_deny ? "deny" : "permit", + report(LOG_DEBUG, "ip %s matched '%s' regex '%s' of acl filter %s", + ip, + next->type == S_deny ? "deny" : + next->type == S_permit ? "permit" : "return", next->value, aclname); return(next->type); } @@ -2035,7 +2134,7 @@ char * cfg_get_enable_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_enable, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_enable, recurse, NULL)); } #endif @@ -2067,7 +2166,7 @@ char * cfg_get_login_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse, NULL)); } /* @@ -2087,13 +2186,13 @@ char * cfg_get_arap_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse, NULL)); } char * cfg_get_chap_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse, NULL)); } #ifdef MSCHAP @@ -2107,20 +2206,20 @@ char * cfg_get_pap_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse, NULL)); } char * cfg_get_opap_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse, NULL)); } /* return the global password for the user (or the group, etc.) */ char * cfg_get_global_secret(char *user, int recurse) { - return(cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse)); + return(cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse, NULL)); } /* @@ -2133,6 +2232,8 @@ int recurse) { USER *user, *group; + ITERATOR *iterator; + NODE *node; NODE *svc; if (debug & DEBUG_CONFIG_FLAG) @@ -2142,15 +2243,17 @@ svcname ? svcname : "", recurse); /* find the user/group entry */ - user = (USER *) hash_lookup(usertable, username); + iterator = new_iterator(username, TAC_IS_USER); - if (!user) { + if (!iterator) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username); return(NULL); } /* found the user entry. Find svc node */ + node = next_iteration(iterator); + user = node->value; for (svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) { if (svc->type != type) @@ -2177,19 +2280,16 @@ if (!recurse) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_svc_node: returns NULL"); + free_iterator(iterator); return(NULL); } - /* no matching node. Check containing group */ - if (user->member) - group = (USER *) hash_lookup(grouptable, user->member); - else - group = NULL; - - while (group) { + /* no matching node. Traverse tree of containing groups */ + while ((node = next_iteration(iterator))) { + group = node->value; if (debug & DEBUG_CONFIG_FLAG) - report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s", - group->name); + report(LOG_DEBUG, "cfg_get_svc_node: recurse group=%s depth=%d", + group->name, depth(iterator)); for (svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) { @@ -2210,21 +2310,16 @@ cfg_nodestring(type), protocol ? protocol : "", svcname ? svcname : ""); + free_iterator(iterator); return(svc); } - - /* still nothing. Check containing group and so on */ - - if (group->member) - group = (USER *) hash_lookup(grouptable, group->member); - else - group = NULL; } if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_svc_node: returns NULL"); /* no matching svc node for this user or her containing groups */ + free_iterator(iterator); return(NULL); } @@ -2236,6 +2331,8 @@ cfg_get_cmd_node(char *name, char *cmdname, int recurse) { USER *user, *group; + ITERATOR *iterator; + NODE *node; NODE *svc; if (debug & DEBUG_CONFIG_FLAG) @@ -2243,14 +2340,16 @@ name, cmdname, recurse); /* find the user/group entry */ - user = (USER *) hash_lookup(usertable, name); + iterator = new_iterator(name, TAC_IS_USER); - if (!user) { + if (!iterator) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name); return(NULL); } /* found the user entry. Find svc node */ + node = next_iteration(iterator); + user = node->value; svc = (NODE *) get_value(user, S_svc).pval; while (svc) { @@ -2266,43 +2365,32 @@ if (!recurse) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL"); + free_iterator(iterator); return(NULL); } - /* no matching node. Check containing group */ - if (user->member) - group = (USER *) hash_lookup(grouptable, user->member); - else - group = NULL; - - while (group) { + /* no matching node. Traverse tree of containing groups */ + while ((node = next_iteration(iterator))) { + group = node->value; if (debug & DEBUG_CONFIG_FLAG) - report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s", - group->name); + report(LOG_DEBUG, "cfg_get_cmd_node: recurse group=%s depth=%d", + group->name, depth(iterator)); - svc = get_value(group, S_svc).pval; + for (svc = get_value(group, S_svc).pval; svc; svc = svc->next) { + if (svc->type != N_svc_cmd || !STREQ(svc->value, cmdname)) continue; - while (svc) { - if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s node %s", cmdname, cfg_nodestring(svc->type)); + free_iterator(iterator); return(svc); } - svc = svc->next; - } - - /* still nothing. Check containing group and so on */ - - if (group->member) - group = (USER *) hash_lookup(grouptable, group->member); - else - group = NULL; } if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL"); /* no matching cmd node for this user or her containing groups */ + free_iterator(iterator); return(NULL); } @@ -2386,6 +2474,8 @@ cfg_ppp_is_configured(char *username, int recurse) { USER *user, *group; + ITERATOR *iterator; + NODE *node; NODE *svc; if (debug & DEBUG_CONFIG_FLAG) @@ -2393,9 +2483,9 @@ username, recurse); /* find the user/group entry */ - user = (USER *) hash_lookup(usertable, username); + iterator = new_iterator(username, TAC_IS_USER); - if (!user) { + if (!iterator) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s", username); @@ -2403,6 +2493,8 @@ } /* found the user entry. Find svc node */ + node = next_iteration(iterator); + user = node->value; for (svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) { if (svc->type != N_svc_ppp) @@ -2412,25 +2504,23 @@ report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node", svc->value1); + free_iterator(iterator); return(1); } if (!recurse) { if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0"); + free_iterator(iterator); return(0); } - /* no matching node. Check containing group */ - if (user->member) - group = (USER *) hash_lookup(grouptable, user->member); - else - group = NULL; - - while (group) { + /* no matching node. Traverse tree of containing groups */ + while ((node = next_iteration(iterator))) { + group = node->value; if (debug & DEBUG_CONFIG_FLAG) - report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s", - group->name); + report(LOG_DEBUG,"cfg_ppp_is_configured: recurse group=%s depth=%d", + group->name, depth(iterator)); for (svc = (NODE *)get_value(group, S_svc).pval; svc; svc = svc->next) { @@ -2441,20 +2531,152 @@ report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s " "node", svc->value1); + free_iterator(iterator); return(1); } - - /* still nothing. Check containing group and so on */ - - if (group->member) - group = (USER *) hash_lookup(grouptable, group->member); - else - group = NULL; } if (debug & DEBUG_CONFIG_FLAG) report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0"); /* no PPP svc nodes for this user or her containing groups */ + free_iterator(iterator); return(0); } + +/*********************************************************************/ + +/* + * Iterator handling routines. + */ + +static NODE * +node_lookup(NODE *node, int isuser) +{ + if (node==NULL) return NULL; + if (node->value) return node; + node->value = hash_lookup(isuser ? usertable:grouptable, node->value1); + if (node->value) return node; + report(LOG_ERR, "%s %s does not exist", + isuser ? "user" : "group", node->value1); + return NULL; +} + +static void +free_iterator(ITERATOR *iterator) +{ + if (iterator->value && ((NODE*)(iterator->value))->line==-1) { + if (debug & DEBUG_CLEAN_FLAG) + report(LOG_DEBUG, "free guard node"); + free(iterator->value); /* free guard */ + } + if (iterator->next) + free_iterator(iterator->next); + if (debug & DEBUG_CLEAN_FLAG) + report(LOG_DEBUG, "free iterator"); + free(iterator); +} + +/* + * iterator fields: + * type: S_iterator + * next: deeper iterator + * value: chain of S_group nodes + * value1: temporary pointer to S_group nodes + * line: depth + * + * group node fields: + * type: S_group + * next: next group node at the same level + * value: pointer to user/group structure + * value1: string pointer to user/group name (guard: NULL) + * line: line no. (guard: -1) + */ + +static ITERATOR * +new_iterator(char *name, int isuser) +{ + ITERATOR *iterator; + NODE *guard; + USER *user; + + user = hash_lookup(isuser ? usertable : grouptable, name); + if (user == NULL) return NULL; + + guard = (NODE *) tac_malloc(sizeof(NODE)); + guard->type = N_group; + guard->next = NULL; + guard->value = user; + guard->value1 = NULL; + guard->line = -1; /* guard marker */ + + iterator = (ITERATOR *) tac_malloc(sizeof(NODE)); + iterator->type = N_iterator; + iterator->next = NULL; + iterator->value = NULL; /* marks unprocessed root */ + iterator->value1 = guard; /* temporary pointer to root */ + iterator->line = 0; /* tree depth */ + + return iterator; +} + +/* + * Find next node. + */ +static NODE * +next_iteration(ITERATOR *iterator) +{ + NODE *current, *parent; + int subtree_done = 0; + + if (iterator->next) { + /* recursively descent till the last iterator */ + current = next_iteration(iterator->next); + if (current) return current; + + /* subtree exhausted. cut down iterator chain. */ + free_iterator(iterator->next); + iterator->next = NULL; + subtree_done = 1; + } + + current = iterator->value; /* the last processed node */ + if (current == NULL) { + /* process root of tree */ + return iterator->value = iterator->value1; /* restore saved ptr */ + } + + /* check if it has unprocessed parents */ + parent = ((USER*)(current->value))->member; + if (parent && !subtree_done) { + ITERATOR *new_iterator; + /* go deeper */ + if (node_lookup(parent, !TAC_IS_USER)==NULL) return NULL; + + new_iterator = (ITERATOR *) tac_malloc(sizeof(NODE)); + new_iterator->type = N_iterator; + new_iterator->next = NULL; + new_iterator->value = parent; + new_iterator->value1 = NULL; + new_iterator->line = iterator->line + 1; /* tree depth */ + iterator->next = new_iterator; + return parent; + } + else { + /* step right */ + iterator->value = current = current->next; + if (node_lookup(current, !TAC_IS_USER)==NULL) return NULL; + return current; + } +} + +/* + * Return depth of current node. + * Just for debugging purposes. + */ +static int +depth(ITERATOR *iterator) +{ + while (iterator->next) iterator = iterator->next; + return iterator->line; +} diff -urw ../tacacs+-F4.0.4.15/default_fn.c ./default_fn.c --- ../tacacs+-F4.0.4.15/default_fn.c 2006-12-13 17:42:56.000000000 +0100 +++ ./default_fn.c 2008-04-19 13:01:43.779372186 +0200 @@ -783,14 +783,42 @@ #endif /* MSCHAP */ #ifdef ACLS +struct acl_iter_cb { + int (*fn)(VALUE, ITER_CB *); +/* So far is like ITER_CB */ +/* Function specific fields follow */ + char *NAS_ip; /* input from verify_host() */ + int result; /* return from cfg_acl_check: S_(permit|deny|return) */ + char *aclname; /* just for debugging purposes */ +}; +typedef struct acl_iter_cb ACL_ITER_CB; + +/* + * This callback function is used by verify_host(). + * It will be executed for each ACL-s found during config tree traversal + * while returns CFG_GET_CONTINUE. + * The result of last run of cfg_acl_check() is retrieved by verify_host() + * from 'result' field of callback structure. + */ + +static int +acl_check_cb(VALUE value, ITER_CB *cb) { + ACL_ITER_CB *acl_cb = (ACL_ITER_CB *)cb; + + acl_cb->aclname = (char*)value.pval; + acl_cb->result = cfg_acl_check(acl_cb->aclname, acl_cb->NAS_ip); + return acl_cb->result == S_return ? CFG_GET_CONTINUE : CFG_GET_TERMINATE; +} + /* * Verify that the NAS's peerip matches the host acl filter. * Return S_deny if session.peerip is invalid, else S_permit */ + int verify_host(char *name, struct authen_data *data, int type, int recurse) { - char *val; + ACL_ITER_CB aclcb; /* lookup host acl for user */ if (!cfg_user_exists(name) && cfg_user_exists(DEFAULT_USERNAME)) { @@ -798,14 +826,23 @@ report(LOG_DEBUG, "Authenticating ACLs for user '%s' instead of " "'%s'", DEFAULT_USERNAME, name); } - val = cfg_get_pvalue(DEFAULT_USERNAME, 1, type, recurse); - } else - val = cfg_get_pvalue(name, 1, type, recurse); - - /* no host acl for user */ - if (val == NULL) - return(S_permit); + name = DEFAULT_USERNAME; + } + + aclcb.fn = acl_check_cb; + aclcb.aclname = NULL; + aclcb.NAS_ip = data->NAS_id->NAS_ip; + aclcb.result = S_permit; /* default if no host acl for user */ + + cfg_get_pvalue(name, TAC_IS_USER, type, recurse, (ITER_CB*)(void*)&aclcb); - return(cfg_acl_check(val, data->NAS_id->NAS_ip)); + if (aclcb.result == S_return) { + /* unterminated chain */ + if (debug & DEBUG_AUTHEN_FLAG) { + report(LOG_DEBUG, "ACL chain for user '%s' is unterminated. Last ACL was '%s'.", name, aclcb.aclname); + } + return S_deny; + } + return aclcb.result; } #endif diff -urw ../tacacs+-F4.0.4.15/do_author.c ./do_author.c --- ../tacacs+-F4.0.4.15/do_author.c 2006-12-13 17:42:56.000000000 +0100 +++ ./do_author.c 2008-04-19 13:01:43.839367350 +0200 @@ -191,7 +191,7 @@ * proceed */ cmd = cfg_get_pvalue(username, TAC_IS_USER, - S_before, TAC_PLUS_RECURSE); + S_before, TAC_PLUS_RECURSE, NULL); if (!cmd) return(0); @@ -300,7 +300,7 @@ int out_cnt, i; int status; char *after = cfg_get_pvalue(username, TAC_IS_USER, - S_after, TAC_PLUS_RECURSE); + S_after, TAC_PLUS_RECURSE, NULL); if (!after) return; diff -urw ../tacacs+-F4.0.4.15/parse.c ./parse.c --- ../tacacs+-F4.0.4.15/parse.c 2006-12-13 17:42:57.000000000 +0100 +++ ./parse.c 2008-04-19 13:01:43.879364130 +0200 @@ -117,6 +117,8 @@ #ifdef HAVE_PAM declare("PAM", S_pam); #endif + declare("return", S_return); + declare("include", S_include); } /* Return a keyword code if a keyword is recognized. 0 otherwise */ @@ -256,5 +258,9 @@ case S_pam: return("PAM"); #endif + case S_return: + return("return"); + case S_include: + return("include"); } } diff -urw ../tacacs+-F4.0.4.15/parse.h ./parse.h --- ../tacacs+-F4.0.4.15/parse.h 2006-07-05 21:00:13.000000000 +0200 +++ ./parse.h 2008-04-19 13:01:43.887363487 +0200 @@ -28,6 +28,7 @@ #define S_openbra 107 #define S_closebra 108 #define S_svc_dflt 109 +#define S_include 110 #define S_key 1 #define S_user 2 @@ -86,3 +87,4 @@ #ifdef HAVE_PAM # define S_pam 49 #endif +#define S_return 50 diff -urw ../tacacs+-F4.0.4.15/tac_plus.h ./tac_plus.h --- ../tacacs+-F4.0.4.15/tac_plus.h 2007-12-13 20:18:39.000000000 +0100 +++ ./tac_plus.h 2008-04-19 13:01:43.895362841 +0200 @@ -587,6 +587,9 @@ #define N_permit 57 #define N_deny 58 #define N_svc 59 +#define N_group 60 +#define N_iterator 61 +#define N_file 62 /* A parse tree node */ struct node { @@ -605,6 +608,15 @@ }; typedef union v VALUE; +struct iter_cb { + int (*fn)(VALUE, struct iter_cb *); + /* more members follow ... */ +}; +typedef struct iter_cb ITER_CB; + +#define CFG_GET_TERMINATE 0 +#define CFG_GET_CONTINUE 1 + /* acct.c */ extern void accounting(u_char *); @@ -667,7 +679,7 @@ char *cfg_get_expires(char *, int); int cfg_get_intvalue(char *, int, int, int); char *cfg_get_phvalue(char *, int); -char *cfg_get_pvalue(char *, int, int, int); +char *cfg_get_pvalue(char *, int, int, int, ITER_CB *); char *cfg_get_global_secret(char *, int); char *cfg_get_host_key(char *); char *cfg_get_host_prompt(char *); diff -urw ../tacacs+-F4.0.4.15/version.h.in ./version.h.in --- ../tacacs+-F4.0.4.15/version.h.in 2007-12-13 20:18:39.000000000 +0100 +++ ./version.h.in 2008-04-19 13:02:17.428661656 +0200 @@ -3,6 +3,6 @@ #define VERSION_H char package[] = "tacacs+"; -char version[] = "F4.0.4.15"; +char version[] = "F4.0.4.15-k1"; #endif