FITNESS FOR A PARTICULAR PURPOSE.
*/
+
#include "tac_plus.h"
+
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
-#include "regexp.h"
+#include <string.h>
+
+#ifndef WITH_INCLUDED_REGEX
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+#endif
+
+#include "cfgfile.h"
+#include "report.h"
+#include "utils.h"
+#include "hash.h"
+#include "parse.h"
+#include "main.h"
+#include "do_author.h" /* for "struct identity" */
+
+#ifdef WITH_INCLUDED_REGEX
+#include "tac_regexp.h"
+#endif
+
+
+static void sym_get TAC_ARGS((void));
+static void when_expr_root_init TAC_ARGS((void));
+static void rch TAC_ARGS((void));
+static int parse_entity TAC_ARGS((int entity_type));
+static NODE *parse_svcs TAC_ARGS((void));
+static int parse_conditional_block TAC_ARGS((ENTITY *entity));
+static NODE *parse_cmd_matches TAC_ARGS((void));
+static NODE *parse_attrs TAC_ARGS((void));
+static void getsym TAC_ARGS((void));
+static ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
+static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
+
/*
- <config> := <decl>*
+ <config> := <decl>*
- <decl> := <top_level_decl> | <user_decl>
+ <decl> := <top_level_decl> | <entity_decl>
- <top_level_decl> := <authen_default> |
- accounting file = <string>
- default authorization = permit |
- key = <string>
+ <top_level_decl> := <authen_default> |
+ accounting file = <string> |
+ default authorization = permit |
+ key = <string> |
+ authorization = ( first | recursive )
- <authen_default> := default authentication = file <filename>
+ <authen_default> := default authentication = file <filename>
#if defined(DB)
- | db <string> )
+ | db <string>
#endif
-
-<permission> := permit | deny
- <filename> := <string>
+ <permission> := permit | deny
+
+ <filename> := <string>
- <password> := <string>
+ <password> := <string>
- <user_decl> := user = <string> {
- [ default service = [ permit | deny ] ]
- <user_attr>*
- <svc>*
- }
+ <user_decl> := user = <string> {
+ [ <service_default> ]
+ <user_attr>*
+ <svc>*
+ }
- <password_spec> := file <filename> |
- skey |
- cleartext <password> |
- des <password> |
+ <host_decl> := host = <string> {
+ [ <service_default> ]
+ <host_attr>*
+ <svc>*
+ }
-#ifdef USE_PAM
- pam <pam_service> |
-#endif
-#if defined(DB)
- db <string>
+ <group_decl> := group = <string> {
+ [ <service_default> ]
+ <group_attr>*
+ <svc>*
+ }
+
+ <service_default> := default service = ( permit | deny | default )
+
+ <password_spec> := file <filename> |
+ skey |
+ cleartext <password> |
+ des <password> |
+
+#ifdef USE_PAM
+ pam <pam_service> |
#endif
- nopassword
+#if defined(DB)
+ db <string>
+#endif
+ nopassword
- <user_attr> := name = <string> |
+ <user_attr> := name = <string> |
login = <password_spec> |
- member = <string> |
- expires = <string> |
- arap = cleartext <string> |
- chap = cleartext <string> |
+ member = <string> |
+ expires = <string> |
+ arap = cleartext <string> |
+ chap = cleartext <string> |
#ifdef MSCHAP
- ms-chap = cleartext <string> |
+ ms-chap = cleartext <string> |
+#endif
+ pap = cleartext <string> |
+ pap = des <string> |
+#ifdef USE_PAM
+ pap = pam <pam_service> |
#endif
- pap = cleartext <string> |
- pap = des <string> |
-#ifdef USE_PAM
- pap = pam <pam_service> |
-#endif
- opap = cleartext <string> |
- global = cleartext <string> |
- msg = <string>
- before authorization = <string> |
- after authorization = <string>
+ opap = cleartext <string> |
+ global = cleartext <string> |
+ msg = <string>
+ before authorization = <string> |
+ after authorization = <string> |
+ <when_attr>
+
+ <host_attr> := key = <string> |
+ <user_attr>
+
+ <group_attr> := enlist = <entity_spec> |
+ key = <string> |
+ <user_attr>
+
+ <when_attr> := member = <string> |
+ enlist = <entity_spec> |
+ <svc> |
+ <when_attr_block>
+
+ <when_attr_block> := <when_decl> {
+ <when_attr>*
+ }
- <svc> := <svc_auth> | <cmd_auth>
+ <svc> := <svc_auth> | <cmd_auth>
- <cmd_auth> := cmd = <string> {
- <cmd-match>*
- }
+ <cmd_auth> := cmd = <string> {
+ <when_match>*
+ }
- <cmd-match> := <permission> <string>
+ <when_match> := <permission> <string> |
+ <when_match_block>
- <svc_auth> := service = ( exec | arap | slip | ppp protocol = <string> {
- [ default attribute = permit ]
- <attr_value_pair>*
- }
+ <when_match_block> := <when_decl> {
+ <when_match>*
+ }
- <attr_value_pair> := [ optional ] <string> = <string>
+ <svc_auth> := service = ( exec | arap | slip | ppp protocol = <string> ) {
+# first matching <svc_auth> is the FINAL one, no further graph scanning occurs!
+ [ default attribute = permit ]
+ <when_AV_pair>*
+ }
+ <when_AV_pair> := [ optional ] <string> = <string> |
+ <when_AV_pair_block>
+
+ <when_AV_pair_block> := <when_decl> {
+ <when_AV_pair>*
+ }
+
+ <when_decl> := when = <expr>
+
+# to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
+ <expr> := <entity_spec> |
+ not <expr> |
+ '(' <expr_or> ')' |
+ '(' <expr_and> ')'
+
+ <expr_or> := <expr> |
+ <expr> or <expr_or>
+
+ <expr_and> := <expr> |
+ <expr> and <expr_and>
+
+ <entity_spec> := ( user | host | group ) <string>
*/
static char sym_buf[MAX_INPUT_LINE_LEN]; /* parse buffer */
static FILE *cf = NULL; /* config file pointer */
static int sym_error = 0; /* a parsing error has occurred */
static int no_user_dflt = 0; /* default if user doesn't exist */
+ /* ='default authorization': 0/S_permit */
+static int algorithm_recursive = 0; /* use newer authorization alogrithm? */
+ /* 1 if 'authorization = recursive' */
static char *authen_default = NULL; /* top level authentication default */
-static int authen_default_method = 0; /*For method check */
+ /* ='default authentication' */
+static int authen_default_method = 0; /* For method check */
+ /* ='default authentication' symbol */
static char *nopasswd_str = "nopassword";
-/* A host definition structure. Currently unused, but when we start
- configuring host-specific information e.g. per-host keys, this is
- where it should be kept.
-
- The first 2 fields (name and hash) are used by the hash table
- routines to hash this structure into a table. Do not (re)move them */
-
-struct host {
- char *name; /* host name */
- void *hash; /* hash table next pointer */
- int line; /* line number defined on */
- char *key; /* host spesific key */
- char *type; /* host type */
-};
-
-/* A user or group definition
-
- The first 2 fields (name and hash) are used by the hash table
- routines to hash this structure into a table. Move them at your
- peril */
-
-struct user {
- char *name; /* username */
- void *hash; /* hash table next pointer */
- int line; /* line number defined on */
- long flags; /* flags field */
-
-#define FLAG_ISUSER 1 /* this structure represents a user */
-#define FLAG_ISGROUP 2 /* this structure represents a group */
-#define FLAG_SEEN 4 /* for circular definition detection */
-
- char *full_name; /* users full name */
- char *login; /* Login password */
- int nopasswd; /* user requires no password */
- char *global; /* password to use if none set */
- char *member; /* group we are a member of */
- char *expires; /* expiration date */
- char *arap; /* our arap secret */
- char *pap; /* our pap secret */
- char *opap; /* our outbound pap secret */
- char *chap; /* our chap secret */
-#ifdef MSCHAP
- char *mschap; /* our mschap secret */
-#endif /* MSCHAP */
- char *msg; /* a message for this user */
- char *before_author; /* command to run before authorization */
- char *after_author; /* command to run after authorization */
- int svc_dflt; /* default authorization behaviour for svc or
- * cmd */
- NODE *svcs; /* pointer to svc nodes */
-#ifdef MAXSESS
- int maxsess; /* Max sessions/user */
-#endif /* MAXSESS */
- char *time; /* Timestamp */
-};
-
-typedef struct host HOST;
-typedef struct user USER;
/* Only the first 2 fields (name and hash) are used by the hash table
routines to hashh structures into a table.
*/
-union hash {
- struct user u;
- struct host h;
-};
-
-typedef union hash HASH;
+static void *grouptable[HASH_TAB_SIZE]; /* Table of group declarations */
+static void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
+static void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
-void *grouptable[HASH_TAB_SIZE];/* Table of group declarations */
-void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
-void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
+struct enlist_entity_item {
+ struct enlist_entity_item *next;
+ int parent_type; char *parent;
+ int child_type; char * child; /* will be created when not found (for "enlist") */
+ struct expr *when;
+ int line;
+};
+static struct enlist_entity_item * enlist_entity_list;
+static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
-static void
- sym_get();
+static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
#ifdef __STDC__
+
#include <stdarg.h> /* ANSI C, variable length args */
static void
parse_error(char *fmt,...)
-#else
+
+#else /* __STDC__ */
+
#include <varargs.h> /* has 'vararg' definitions */
/* VARARGS2 */
static void
parse_error(fmt, va_alist)
char *fmt;
-
va_dcl /* no terminating semi-colon */
-#endif
+
+#endif /* __STDC__ */
{
char msg[256]; /* temporary string */
va_list ap;
tac_exit(1);
}
-char *
+const char *cfg_nodestring TAC_ARGS((int type));
+
+const char *
cfg_nodestring(type)
int type;
{
}
}
+const char *entity_type_to_string TAC_ARGS((int entity_type));
+
+const char *
+entity_type_to_string(entity_type)
+int entity_type;
+{
+ switch (entity_type) {
+ case S_user:
+ return ("user");
+ case S_host:
+ return ("host");
+ case S_group:
+ return ("group");
+ }
+ return (NULL);
+}
+
+static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
+
+static void **
+entity_type_to_hashtable(entity_type)
+int entity_type;
+{
+ switch (entity_type) {
+ case S_user:
+ return (usertable);
+ case S_host:
+ return (hosttable);
+ case S_group:
+ return (grouptable);
+ }
+ return (NULL);
+}
+
+void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
+
+void
+scan_invalidate_entities(what)
+enum invalidate_scan what;
+{
+ scan_invalidate_entities_hashtable( usertable, what);
+ scan_invalidate_entities_hashtable( hosttable, what);
+ scan_invalidate_entities_hashtable(grouptable, what);
+}
+
+
+static void free_attrs TAC_ARGS((NODE *node));
+
static void
free_attrs(node)
NODE *node;
NODE *next;
while (node) {
+ unlink_expr(node->when);
+ free_expr(node->when);
+ node->when = NULL;
+
switch (node->type) {
case N_optarg:
case N_arg:
if (debug & DEBUG_CLEAN_FLAG)
report(LOG_DEBUG, "free_cmd_match %s %s",
cfg_nodestring(node->type),
- node->value);
+ (const char *) node->value);
break;
default:
- report(LOG_ERR, "Illegal node type %s for free_attrs",
+ report(LOG_ERR, "Illegal node type %s for free_attrs",
cfg_nodestring(node->type));
return;
}
}
}
+static void free_cmd_matches TAC_ARGS((NODE *node));
+
static void
free_cmd_matches(node)
NODE *node;
if (debug & DEBUG_CLEAN_FLAG)
report(LOG_DEBUG, "free_cmd_match %s %s",
cfg_nodestring(node->type),
- node->value);
+ (const char *) node->value);
+
+ unlink_expr(node->when);
+ free_expr(node->when);
+ node->when = NULL;
free(node->value); /* text */
- free(node->value1); /* regexp compiled text */
+
+#ifdef WITH_INCLUDED_REGEX
+
+ free(node->value1); /* tac_regexp compiled text */
+
+#else /* WITH_INCLUDED_REGEX */
+
+ regfree((regex_t *) node->value1); /* POSIX regex compiled text */
+
+#endif /* WITH_INCLUDED_REGEX */
+
next = node->next;
free(node);
node = next;
}
}
+static void free_svcs TAC_ARGS((NODE *node));
+
static void
free_svcs(node)
NODE *node;
NODE *next;
while (node) {
+ unlink_expr(node->when);
+ free_expr(node->when);
+ node->when = NULL;
switch (node->type) {
case N_svc_cmd:
if (debug & DEBUG_CLEAN_FLAG)
report(LOG_DEBUG, "free %s %s",
- cfg_nodestring(node->type), node->value);
+ cfg_nodestring(node->type),
+ (const char *) node->value);
free(node->value); /* cmd name */
free_cmd_matches(node->value1);
next = node->next;
}
}
+static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
+
+static void
+free_enlist_entity_item(item)
+struct enlist_entity_item *item;
+{
+ free(item->parent);
+ free(item->child);
+ free_expr(item->when);
+}
+
+
+static void free_entity TAC_ARGS((ENTITY *entity));
+
static void
-free_userstruct(user)
-USER *user;
+free_entity(entity)
+ENTITY *entity;
{
if (debug & DEBUG_CLEAN_FLAG)
report(LOG_DEBUG, "free %s %s",
- (user->flags & FLAG_ISUSER) ? "user" : "group",
- user->name);
-
- if (user->name)
- free(user->name);
- if (user->full_name)
- free(user->full_name);
- if (user->login)
- free(user->login);
- if (user->member)
- free(user->member);
- if (user->expires)
- free(user->expires);
- if (user->time)
- free(user->time);
- if (user->arap)
- free(user->arap);
- if (user->chap)
- free(user->chap);
+ entity_type_to_string(entity->type), entity->name);
+
+ /* function MUST be called while the whole entity is still VALID! */
+ scan_free_entity(entity);
+
+ if (entity->name)
+ free(entity->name);
+ if (entity->full_name)
+ free(entity->full_name);
+ if (entity->login)
+ free(entity->login);
+ if (entity->expires)
+ free(entity->expires);
+ if (entity->time)
+ free(entity->time);
+ if (entity->arap)
+ free(entity->arap);
+ if (entity->chap)
+ free(entity->chap);
#ifdef MSCHAP
- if (user->mschap)
- free(user->mschap);
+ if (entity->mschap)
+ free(entity->mschap);
#endif /* MSCHAP */
- if (user->pap)
- free(user->pap);
- if (user->opap)
- free(user->opap);
- if (user->global)
- free(user->global);
- if (user->msg)
- free(user->msg);
- if (user->before_author)
- free(user->before_author);
- if (user->after_author)
- free(user->after_author);
- free_svcs(user->svcs);
+ if (entity->pap)
+ free(entity->pap);
+ if (entity->opap)
+ free(entity->opap);
+ if (entity->global)
+ free(entity->global);
+ if (entity->msg)
+ free(entity->msg);
+ if (entity->before_author)
+ free(entity->before_author);
+ if (entity->after_author)
+ free(entity->after_author);
+ if (entity->key)
+ free(entity->key);
+ free_svcs(entity->svcs);
}
+static void free_hashtable TAC_ARGS((void **hashtable));
+
static void
-free_hoststruct(host)
-HOST *host;
+free_hashtable(hashtable)
+void **hashtable;
{
- if (debug & DEBUG_CLEAN_FLAG)
- report(LOG_DEBUG, "free %s",
- host->name);
+ int i;
+ ENTITY *entity,**entityp;
- if (host->name)
- free(host->name);
-
- if (host->key)
- free(host->key);
-
- if (host->type)
- free(host->type);
+ for (i = 0; i < HASH_TAB_SIZE; i++) {
+ entityp = (ENTITY **) (hashtable+i);
+ while ((entity = *entityp)) {
+ *entityp = entity->hash;
+ free_entity(entity);
+ free(entity);
+ }
+ }
}
+
/*
* Exported routines
*/
+void cfg_clean_config TAC_ARGS((void));
+
/* Free all allocated structures preparatory to re-reading the config file */
void
cfg_clean_config()
{
- int i;
- USER *entry, *next;
- HOST *host_entry,*hn;
+ struct enlist_entity_item *enlist_entity_item;
if (authen_default) {
free(authen_default);
authen_default = NULL;
}
-
- if (authen_default_method) {
+
+ if (algorithm_recursive) {
+ algorithm_recursive = 0;
+ }
+
+ if (authen_default_method) {
authen_default_method = 0;
}
free(session.acctfile);
session.acctfile = NULL;
}
-
+
if (session.db_acct) {
free(session.db_acct);
session.db_acct = NULL;
}
- /* clean the hosttable */
- for (i = 0; i < HASH_TAB_SIZE; i++) {
- host_entry = (HOST *) hosttable[i];
- while (host_entry) {
- hn = host_entry->hash;
- free_hoststruct(host_entry);
- free(host_entry);
- host_entry = hn;
- }
- hosttable[i] = NULL;
- }
-
- /* the grouptable */
- for (i = 0; i < HASH_TAB_SIZE; i++) {
- entry = (USER *) grouptable[i];
- while (entry) {
- next = entry->hash;
- free_userstruct(entry);
- free(entry);
- entry = next;
- }
- grouptable[i] = NULL;
- }
+ free_hashtable( usertable);
+ free_hashtable( hosttable);
+ free_hashtable(grouptable);
- /* the usertable */
- for (i = 0; i < HASH_TAB_SIZE; i++) {
- entry = (USER *) usertable[i];
- while (entry) {
- next = entry->hash;
- free_userstruct(entry);
- free(entry);
- entry = next;
- }
- usertable[i] = NULL;
+ while (enlist_entity_list) {
+ enlist_entity_item = enlist_entity_list;
+ enlist_entity_list = enlist_entity_item->next;
+ free_enlist_entity_item(enlist_entity_item);
+ free(enlist_entity_item);
}
+ enlist_entity_list_tailp = &enlist_entity_list;
}
+static int parse_permission TAC_ARGS((void));
+
static int
parse_permission()
{
return (symbol);
}
+static int parse TAC_ARGS((int symbol));
+
static int
parse(symbol)
int symbol;
return (0);
}
+static int parse_opt_svc_default TAC_ARGS((void));
+
static int
parse_opt_svc_default()
{
+ int retval;
+
if (sym_code != S_default) {
return (0);
}
parse(S_default);
parse(S_svc);
parse(S_separator);
- if (sym_code == S_permit) {
- parse(S_permit);
- return (S_permit);
+
+ switch (sym_code) {
+ default:
+ parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
+ sym_buf, sym_line);
+ return (1);
+
+ case S_default:
+ if (!algorithm_recursive) {
+ parse_error("'default service = %s' supported only if set top level 'authorization = recursive', on line %d",
+ sym_buf, sym_line);
+ return (1);
+ }
+ /* FALLTHRU */
+ case S_permit:
+ case S_deny:
+ retval = sym_code;
+ sym_get();
+ return (retval);
}
- parse(S_deny);
- return (S_deny);
}
+static int parse_opt_attr_default TAC_ARGS((void));
+
static int
parse_opt_attr_default()
{
return (S_permit);
}
-static int parse_user();
-static int parse_host();
-
-static void
- rch();
-
/*
Parse lines in the config file, creating data structures
Return 1 on error, otherwise 0 */
+static int parse_decls TAC_ARGS((void));
+
static int
parse_decls()
{
- no_user_dflt = 0; /* default if user doesn't exist */
+ no_user_dflt = 0; /* default if user doesn't exist */
+ algorithm_recursive = 0; /* use backward compatible alg. by default */
+ when_expr_root_init();
+ enlist_entity_list_tailp = &enlist_entity_list;
sym_code = 0;
rch();
bzero(grouptable, sizeof(grouptable));
bzero(usertable, sizeof(usertable));
- bzero(hosttable, sizeof(hosttable));
+ bzero(hosttable, sizeof(hosttable));
sym_get();
sym_get();
parse(S_file);
parse(S_separator);
- if (session.acctfile)
+ if (session.acctfile)
free(session.acctfile);
session.acctfile = tac_strdup(sym_buf);
sym_get();
continue;
-#ifdef DB
+#ifdef DB
case S_db_accounting:
sym_get();
parse(S_separator);
- if (session.db_acct)
+ if (session.db_acct)
free(session.db_acct);
session.db_acct = tac_strdup(sym_buf);
sym_get();
parse(S_separator);
switch(sym_code) {
-
+
case S_file:
#ifdef DB
case S_db:
#endif
#ifdef USE_LDAP
- case S_ldap;
+ case S_ldap:
#endif
#ifdef USE_PAM
case S_pam:
parse(S_separator);
parse(S_permit);
no_user_dflt = S_permit;
- report(LOG_INFO,
+ report(LOG_INFO,
"default authorization = permit is now deprecated. Please use user = DEFAULT instead");
continue;
}
+ case S_authorization:
+ sym_get();
+ parse(S_separator);
+ switch (sym_code) {
+ default:
+ parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
+ sym_buf, sym_line);
+ return (1);
+
+ case S_first:
+ parse(S_first);
+ algorithm_recursive = 0;
+ continue;
+
+ case S_recursive:
+ parse(S_recursive);
+ algorithm_recursive = 1;
+ continue;
+ }
+
case S_key:
/* Process a key declaration. */
sym_get();
session.keyline = sym_line;
sym_get();
continue;
-
- case S_host:
- parse_host();
- continue;
-
+
case S_user:
+ case S_host:
case S_group:
- parse_user();
+ parse_entity(sym_code);
continue;
- /* case S_host: parse_host(); continue; */
-
default:
parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
return (1);
}
}
-static NODE *parse_svcs();
-
/* Assign a value to a field. Issue an error message and return 1 if
it's already been assigned. This is a macro because I was sick of
repeating the same code fragment over and over */
} \
field = tac_strdup(sym_buf);
-static int
-parse_host()
-{
- HOST *h;
- HOST *host = (HOST *) tac_malloc(sizeof(HOST));
- int save_sym;
- char buf[MAX_INPUT_LINE_LEN];
+static struct expr *when_expr_root;
+#define WHEN_EXPR_ROOT_SANE() \
+ (when_expr_root && !when_expr_root->next && when_expr_root->type==S_and)
+#define WHEN_EXPR_ROOT_EMPTY() \
+ (WHEN_EXPR_ROOT_SANE() && !when_expr_root->u.and_or.child_first)
- bzero(host, sizeof(HOST));
+static struct expr *parse_expr_node TAC_ARGS((int single_item));
- sym_get();
- parse(S_separator);
- host->name = tac_strdup(sym_buf);
- host->line = sym_line;
-
- h = hash_add_entry(hosttable, (void *) host);
-
- if (h) {
- parse_error("multiply defined %s on lines %d and %d",
- host->name, h->line, sym_line);
- return (1);
- }
+static struct expr *
+parse_expr_node(single_item)
+int single_item;
+{
+ struct expr *expr_root = NULL;
+ struct expr **succ_exprp = &expr_root;
+ struct expr *expr;
- sym_get();
- parse(S_openbra);
-
while (1) {
switch (sym_code) {
- case S_eof:
- return (0);
- case S_key:
- ASSIGN(host->key);
- sym_get();
- continue;
- case S_type:
- ASSIGN(host->type);
- sym_get();
- continue;
-
- case S_closebra:
- parse(S_closebra);
- return (0);
+
+ case S_not:
+ expr = (struct expr *) tac_malloc(sizeof(struct expr));
+ expr->line = sym_line;
+ *succ_exprp = expr;
+ expr->next = NULL;
+ succ_exprp = &expr->next;
+ expr->type = S_not;
+ sym_get();
+ expr->u.not.child = parse_expr_node(1 /* single_item */);
+ if (!expr->u.not.child) {
+ free_expr(expr_root);
+ return (NULL);
+ }
+ break;
+
+ case S_user:
+ case S_host:
+ case S_group:
+ expr = (struct expr *) tac_malloc(sizeof(struct expr));
+ expr->line = sym_line;
+ *succ_exprp = expr;
+ expr->next = NULL;
+ succ_exprp = &expr->next;
+ expr->type = sym_code;
+ sym_get();
+ expr->u.entity.name = tac_strdup(sym_buf);
+ sym_get();
+ expr->u.entity.entity = NULL; /* not known yet */
+ break;
+
+ case S_openparen:
+ sym_get();
+ expr = parse_expr_node(0 /* single_item */);
+ *succ_exprp = expr;
+ parse(S_closeparen);
+
+ if (expr->next) {
+ report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
+ free_expr(expr_root);
+ return (NULL);
+ }
+ succ_exprp = &expr->next;
+ break;
default:
- parse_error("Unrecognised keyword %s for host %s on line %d",
- sym_buf, host->name,sym_line);
+ parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
+ sym_buf, sym_line);
+ free_expr(expr_root);
+ return (NULL);
+ }
- return (0);
- }
- } /* while */
-} /* finish parse_host */
+ if (single_item) /* used by 'not' operator with high precedence */
+ return (expr_root);
+ switch (sym_code) {
-static int
-parse_user()
-{
- USER *n;
- int isuser;
- USER *user = (USER *) tac_malloc(sizeof(USER));
- int save_sym;
- char **fieldp;
- char buf[MAX_INPUT_LINE_LEN];
+ case S_and:
+ case S_or:
+ if (expr_root->type == (sym_code==S_and ? S_or : S_and)) {
+ parse_error("ambiguous use of 'and' together with 'or', parentheses required on line %d",
+ sym_line);
+ free_expr(expr_root);
+ return (NULL);
+ }
+ if (expr_root->type != sym_code) {
+ expr = (struct expr *) tac_malloc(sizeof(struct expr));
+ expr->line = sym_line;
+ expr->next = NULL;
+ expr->type = sym_code;
+ expr->u.and_or.child_first = expr_root;
+ expr_root = expr;
+ }
+ sym_get();
+ continue;
+ }
- bzero(user, sizeof(USER));
+ return(expr_root);
+ }
+}
- isuser = (sym_code == S_user);
+static struct expr *parse_when_decl TAC_ARGS((void));
- sym_get();
- parse(S_separator);
- user->name = tac_strdup(sym_buf);
- user->line = sym_line;
-
- if (isuser) {
- user->flags |= FLAG_ISUSER;
- n = hash_add_entry(usertable, (void *) user);
- } else {
- user->flags |= FLAG_ISGROUP;
- n = hash_add_entry(grouptable, (void *) user);
+static struct expr *
+parse_when_decl()
+{
+ parse(S_when);
+ if (!algorithm_recursive) {
+ parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
+ sym_line);
+ return (NULL);
}
+ parse(S_separator);
+ return (parse_expr_node(0 /* single_item */));
+}
- if (n) {
- parse_error("multiply defined %s %s on lines %d and %d",
- isuser ? "user" : "group",
- user->name, n->line, sym_line);
+static void when_expr_root_init TAC_ARGS((void));
+
+static void
+when_expr_root_init()
+{
+ free_expr(when_expr_root);
+ when_expr_root = new_expr(S_and);
+}
+
+static int push_parsed_when_decl TAC_ARGS((void));
+
+static int
+push_parsed_when_decl()
+{
+ struct expr *parsed_expr;
+
+ parsed_expr = parse_when_decl();
+ if (!parsed_expr)
+ return (1);
+ if (!WHEN_EXPR_ROOT_SANE()) {
+ report(LOG_ERR, "INTERNAL: when_expr_root not valid during push_parsed_when_decl()!");
+ free_expr(parsed_expr);
return (1);
}
- sym_get();
- parse(S_openbra);
+ if (parsed_expr->next) {
+ report(LOG_ERR, "INTERNAL: Illegal filled next field of parsed expr");
+ free_expr(parsed_expr);
+ return (1);
+ }
+ parsed_expr->next = when_expr_root->u.and_or.child_first;
+ when_expr_root->u.and_or.child_first = parsed_expr;
+ when_expr_root->line = parsed_expr->line;
+ return (0);
+}
- /* Is the default deny for svcs or cmds to be overridden? */
- user->svc_dflt = parse_opt_svc_default();
+static int pop_when_decl TAC_ARGS((void));
- while (1) {
- switch (sym_code) {
- case S_eof:
- return (0);
-
- case S_time:
- ASSIGN(user->time);
- sym_get();
- continue;
+static int
+pop_when_decl()
+{
+ struct expr *first_expr;
- case S_before:
- sym_get();
- parse(S_authorization);
- if (user->before_author)
- free(user->before_author);
- user->before_author = tac_strdup(sym_buf);
- sym_get();
- continue;
+ if (!WHEN_EXPR_ROOT_SANE()) {
+ report(LOG_ERR, "INTERNAL: when_expr_root not valid during pop_when_decl()!");
+ return (1);
+ }
+ first_expr = when_expr_root->u.and_or.child_first;
+ if (!first_expr) {
+ report(LOG_ERR, "No expr in stack and pop_when_decl() called");
+ return (1);
+ }
+ when_expr_root->u.and_or.child_first = first_expr->next;
+ first_expr->next = NULL;
+ free_expr(first_expr);
+ return (0);
+}
- case S_after:
- sym_get();
- parse(S_authorization);
- if (user->after_author)
- free(user->after_author);
- user->after_author = tac_strdup(sym_buf);
- sym_get();
- continue;
+static struct expr *copy_current_when_decl TAC_ARGS((void));
- case S_svc:
- case S_cmd:
-
- if (user->svcs) {
- /*
- * Already parsed some services/commands. Thanks to Gabor Kiss
- * who found this bug.
- */
- NODE *p;
- for (p=user->svcs; p->next; p=p->next)
- /* NULL STMT */;
- p->next = parse_svcs();
- } else {
- user->svcs = parse_svcs();
- }
- continue;
+static struct expr *
+copy_current_when_decl()
+{
+ return (dupl_expr(when_expr_root));
+}
- case S_login:
- if (user->login) {
- parse_error("Duplicate value for %s %s and %s on line %d",
- codestring(sym_code), user->login,
- sym_buf, sym_line);
- tac_exit(1);
- }
- sym_get();
- parse(S_separator);
- switch(sym_code) {
+static struct expr *when_expr_dungeon;
- case S_skey:
- user->login = tac_strdup(sym_buf);
- break;
+static void starve_when_decl TAC_ARGS((void));
- case S_nopasswd:
+static void
+starve_when_decl()
+{
+ if (!WHEN_EXPR_ROOT_SANE()) {
+ report(LOG_WARNING, "INTERNAL: when_expr_root not sane during starve_when_decl!");
+ }
+ when_expr_root->next = when_expr_dungeon;
+ when_expr_dungeon = when_expr_root;
+ when_expr_root = NULL;
+ when_expr_root_init();
+}
+
+static int feed_when_decl TAC_ARGS((void));
+
+static int
+feed_when_decl()
+{
+ if (!when_expr_dungeon) {
+ report(LOG_ERR, "INTERNAL: No expr in dungeon and feed_when_decl() called");
+ return (1);
+ }
+ if (!WHEN_EXPR_ROOT_EMPTY()) {
+ report(LOG_WARNING, "INTERNAL: Some 'when' expression found still pushed in dungeon during feed_when_decl()!");
+ }
+ free_expr(when_expr_root);
+ when_expr_root = when_expr_dungeon;
+ when_expr_dungeon = when_expr_dungeon->next;
+ when_expr_root->next = NULL;
+ return (0);
+}
+
+ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
+
+ENTITY *
+entity_lookup(type, name)
+int type;
+const char *name;
+{
+ return (hash_lookup(entity_type_to_hashtable(type), name));
+}
+
+static int enlist_entity_connect TAC_ARGS((void));
+
+static int
+enlist_entity_connect()
+{
+ struct enlist_entity_item *item;
+ ENTITY *parent_entity, *child_entity;
+
+ while ((item=enlist_entity_list)) {
+
+ parent_entity = entity_lookup(item->parent_type, item->parent);
+ if (!parent_entity) {
+ parse_error("Entity %s %s not defined, referenced as parent on line %d",
+ entity_type_to_string(item->parent_type), item->parent, item->line);
+ return (1);
+ }
+ child_entity = entity_lookup(item-> child_type, item-> child);
+ if (!child_entity) {
+ child_entity = new_entity(item->child_type, item->child, item->line);
+ if (!child_entity)
+ return (1); /* 'hash_add_entry()' conflict */
+ item->child = NULL; /* don't free string ref'ed from 'child_entity'! */
+ }
+
+ if (!enlist_entity_direct(parent_entity, child_entity, item->when))
+ return (1); /* entities not found */
+
+ enlist_entity_list = item->next;
+ item->when = NULL;
+ free_enlist_entity_item(item);
+ free(item);
+ }
+ enlist_entity_list_tailp = &enlist_entity_list;
+ return (0);
+}
+
+static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
+
+static void
+enlist_entity(parent_type, parent, child_type, child)
+int parent_type;
+const char *parent;
+int child_type;
+const char *child;
+{
+ struct enlist_entity_item *item =
+ (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
+
+ item->next = NULL;
+ *enlist_entity_list_tailp = item;
+ enlist_entity_list_tailp = &item->next;
+
+ item->parent_type = parent_type;
+ item->parent = tac_strdup(parent);
+ item-> child_type = child_type;
+ item->child = tac_strdup(child);
+ item->when = copy_current_when_decl();
+ item->line = sym_line;
+}
+
+static int parse_entity_spec TAC_ARGS((void));
+
+/* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
+static int
+parse_entity_spec()
+{
+ int retval;
+
+ if (sym_code != S_user
+ && sym_code != S_host
+ && sym_code != S_group
+ ) {
+ parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
+ sym_buf, sym_line);
+ return (0);
+ }
+
+ retval = sym_code;
+ sym_get();
+
+ return (retval);
+}
+
+static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
+
+static int
+parse_conditional_block_item(entity)
+ENTITY *entity;
+{
+ switch (sym_code) {
+ case S_eof:
+ return (1);
+
+ /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
+
+ default:
+ parse_error("Unrecognised keyword %s for entity on line %d",
+ sym_buf, sym_line);
+ return (1);
+
+ case S_member:
+ sym_get();
+ parse(S_separator);
+ enlist_entity(S_group, sym_buf, entity->type, entity->name);
+ sym_get();
+ break;
+
+ case S_enlist: {
+ int parsed_entity_type;
+
+ if (entity->type != S_group) {
+ parse_error("'enlist' keyword allowed only in 'group' section on line %d",
+ sym_line);
+ return (1);
+ }
+ sym_get();
+ parse(S_separator);
+ parsed_entity_type = parse_entity_spec();
+ if (!parsed_entity_type)
+ return (1);
+ enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
+ sym_get();
+ break;
+ }
+
+ case S_svc:
+ case S_cmd:
+
+ if (entity->svcs) {
+ /*
+ * Already parsed some services/commands. Thanks to Gabor Kiss
+ * who found this bug.
+ */
+ NODE *p;
+ for (p=entity->svcs; p->next; p=p->next)
+ /* NULL STMT */;
+ p->next = parse_svcs();
+ } else {
+ entity->svcs = parse_svcs();
+ }
+ break;
+
+ case S_when:
+ if (parse_conditional_block(entity))
+ return (1);
+ break;
+ }
+
+ return (0);
+}
+
+static int parse_conditional_block TAC_ARGS((ENTITY *entity));
+
+static int
+parse_conditional_block(entity)
+ENTITY *entity;
+{
+ int retval = -1 /* GCC paranoia */;
+
+ if (push_parsed_when_decl())
+ return (1);
+ parse(S_openbra);
+
+ while (1) {
+ if (sym_code == S_closebra) {
+ sym_get();
+ retval = 0; /* success */
+ break;
+ }
+
+ if (parse_conditional_block_item(entity)) {
+ retval = 1; /* failure */
+ break;
+ }
+ }
+
+ if (pop_when_decl())
+ return (1);
+
+ return (retval);
+}
+
+/* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
+
+static ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
+
+static ENTITY *
+new_entity(type, name, line)
+int type;
+char *name;
+int line;
+{
+ ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
+ ENTITY *hash_conflict;
+
+ bzero(entity, sizeof(ENTITY));
+ tac_list_init(&entity->to_parent_membership_list);
+ tac_list_init(&entity->to_child_membership_list );
+ entity->to_child_membership_num = 0;
+ scan_init_entity(entity);
+
+ entity->type = type;
+ entity->name = name;
+ entity->line = line;
+
+ hash_conflict = hash_add_entry(entity_type_to_hashtable(type), (void *) entity);
+ if (hash_conflict) {
+ parse_error("multiply defined %s %s on lines %d and %d",
+ entity_type_to_string(type),
+ entity->name, hash_conflict->line, sym_line);
+ free (entity);
+ return (NULL);
+ }
+
+ return (entity);
+}
+
+static int parse_entity TAC_ARGS((int entity_type));
+
+static int
+parse_entity(entity_type)
+int entity_type;
+{
+ ENTITY *entity;
+ int save_sym;
+ char **fieldp = NULL /* GCC paranoia */;
+ char buf[MAX_INPUT_LINE_LEN];
+
+ sym_get();
+ parse(S_separator);
+
+ entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
+ if (!entity)
+ return (1); /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
+
+ sym_get();
+ parse(S_openbra);
+
+ /* Is the default deny for svcs or cmds to be overridden? */
+ entity->svc_dflt = parse_opt_svc_default();
+
+ while (1) {
+ if (entity_type != S_user)
+ switch (sym_code) {
+ case S_key:
+ ASSIGN(entity->key);
+ sym_get();
+ continue;
+ }
+
+ switch (sym_code) {
+ case S_eof:
+ return (0);
+
+ case S_time:
+ ASSIGN(entity->time);
+ sym_get();
+ continue;
+
+ case S_before:
+ sym_get();
+ parse(S_authorization);
+ if (entity->before_author)
+ free(entity->before_author);
+ entity->before_author = tac_strdup(sym_buf);
+ sym_get();
+ continue;
+
+ case S_after:
+ sym_get();
+ parse(S_authorization);
+ if (entity->after_author)
+ free(entity->after_author);
+ entity->after_author = tac_strdup(sym_buf);
+ sym_get();
+ continue;
+
+ case S_login:
+ if (entity->login) {
+ parse_error("Duplicate value for %s %s and %s on line %d",
+ codestring(sym_code), entity->login,
+ sym_buf, sym_line);
+ tac_exit(1);
+ }
+ sym_get();
+ parse(S_separator);
+ switch(sym_code) {
+
+ case S_skey:
+ entity->login = tac_strdup(sym_buf);
+ break;
+
+ case S_nopasswd:
/* set to dummy string, so that we detect a duplicate
* password definition attempt
*/
- user->login = tac_strdup(nopasswd_str);
- user->nopasswd = 1;
+ entity->login = tac_strdup(nopasswd_str);
+ entity->nopasswd = 1;
break;
-
+
case S_file:
case S_cleartext:
case S_des:
-#ifdef USE_PAM
- case S_pam:
-#endif /* USE_PAM */
+#ifdef USE_PAM
+ case S_pam:
+#endif /* USE_PAM */
#ifdef DB
case S_db:
#endif /* USE DB */
sprintf(buf, "%s ", sym_buf);
sym_get();
strcat(buf, sym_buf);
- user->login = tac_strdup(buf);
+ entity->login = tac_strdup(buf);
break;
-
+
default:
#ifdef USE_PAM
parse_error(
"expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
sym_line);
-#else
+#else
parse_error(
- "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
+ "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
sym_line);
-#endif /* USE_PAM */
+#endif /* USE_PAM */
}
sym_get();
continue;
case S_pap:
- if (user->pap) {
+ if (entity->pap) {
parse_error("Duplicate value for %s %s and %s on line %d",
- codestring(sym_code), user->pap,
+ codestring(sym_code), entity->pap,
sym_buf, sym_line);
tac_exit(1);
}
case S_cleartext:
case S_des:
-#ifdef USE_PAM
+#ifdef USE_PAM
case S_pam:
-#endif /*USE_PAM */
+#endif /*USE_PAM */
sprintf(buf, "%s ", sym_buf);
sym_get();
strcat(buf, sym_buf);
- user->pap = tac_strdup(buf);
- break;
+ entity->pap = tac_strdup(buf);
+ break;
sprintf(buf, "%s ", sym_buf);
- user->pap = tac_strdup(buf);
+ entity->pap = tac_strdup(buf);
break;
default:
sym_line);
#else
parse_error(
- "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
+ "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
sym_line);
#endif /*USE_PAM */
}
continue;
case S_name:
- ASSIGN(user->full_name);
- sym_get();
- continue;
-
- case S_member:
- ASSIGN(user->member);
+ ASSIGN(entity->full_name);
sym_get();
continue;
-
case S_expires:
- ASSIGN(user->expires);
+ ASSIGN(entity->expires);
sym_get();
continue;
-
+
case S_message:
- ASSIGN(user->msg);
+ ASSIGN(entity->msg);
sym_get();
continue;
case S_opap:
case S_global:
save_sym = sym_code;
- sym_get();
- parse(S_separator);
+ sym_get();
+ parse(S_separator);
sprintf(buf, "%s ", sym_buf);
parse(S_cleartext);
strcat(buf, sym_buf);
- if (save_sym == S_arap)
- fieldp = &user->arap;
- if (save_sym == S_chap)
- fieldp = &user->chap;
+ switch (save_sym) {
+ case S_arap:
+ fieldp = &entity->arap;
+ break;
+ case S_chap:
+ fieldp = &entity->chap;
+ break;
#ifdef MSCHAP
- if (save_sym == S_mschap)
- fieldp = &user->mschap;
+ case S_mschap:
+ fieldp = &entity->mschap;
+ break;
#endif /* MSCHAP */
- if (save_sym == S_pap)
- fieldp = &user->pap;
- if (save_sym == S_opap)
- fieldp = &user->opap;
- if (save_sym == S_global)
- fieldp = &user->global;
+ case S_pap:
+ fieldp = &entity->pap;
+ break;
+ case S_opap:
+ fieldp = &entity->opap;
+ break;
+ case S_global:
+ fieldp = &entity->global;
+ break;
+ default:
+ report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
+ sym_line);
+ continue;
+ }
if (*fieldp) {
parse_error("Duplicate value for %s %s and %s on line %d",
#ifdef MAXSESS
case S_maxsess:
- sym_get();
+ sym_get();
parse(S_separator);
- if (sscanf(sym_buf, "%d", &user->maxsess) != 1) {
+ if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
parse_error("expecting integer, found '%s' on line %d",
sym_buf, sym_line);
}
sym_get();
continue;
#endif /* MAXSESS */
-
+
default:
if (STREQ(sym_buf, "password")) {
fprintf(stderr,
"\npassword = <string> is obsolete. Use login = des <string>\n");
}
- parse_error("Unrecognised keyword %s for user on line %d",
- sym_buf, sym_line);
- return (0);
+ if (parse_conditional_block_item(entity))
+ return (0); /* error message already printed */
}
}
}
-static NODE *parse_attrs();
-static NODE *parse_cmd_matches();
+static NODE *parse_svcs TAC_ARGS((void));
static NODE *
parse_svcs()
sym_get();
parse(S_openbra);
-
+ starve_when_decl();
result->value1 = parse_cmd_matches();
+ parse(S_closebra);
+ if (feed_when_decl())
+ tac_exit(1); /* no error return possibility */
+
result->type = N_svc_cmd;
+ result->when = copy_current_when_decl();
+ expr_sink_register(result->when);
- parse(S_closebra);
result->next = parse_svcs();
return (result);
}
result->value1 = tac_strdup(sym_buf);
break;
}
+
sym_get();
parse(S_openbra);
+ starve_when_decl();
+
result->dflt = parse_opt_attr_default();
result->value = parse_attrs();
+
parse(S_closebra);
+ feed_when_decl();
+
+ result->when = copy_current_when_decl();
+ expr_sink_register(result->when);
+
result->next = parse_svcs();
return (result);
}
-/* <cmd-match> := <permission> <string> */
+/* <cmd_match> := <permission> <string> */
+
+static NODE *parse_cmd_matches TAC_ARGS((void));
static NODE *
parse_cmd_matches()
{
+ NODE *retval = NULL, **succp = &retval;
NODE *result;
- if (sym_code != S_permit && sym_code != S_deny) {
- return (NULL);
- }
- result = (NODE *) tac_malloc(sizeof(NODE));
+ for (;;) {
+ switch (sym_code) {
+ default:
+ return (retval);
- bzero(result, sizeof(NODE));
- result->line = sym_line;
+ case S_when:
+ if (push_parsed_when_decl())
+ tac_exit(1); /* no error return possibility */
+ parse(S_openbra);
+ result = parse_cmd_matches();
+ parse(S_closebra);
+ if (pop_when_decl())
+ tac_exit(1); /* no error return possibility */
+ break;
- result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
- result->value = tac_strdup(sym_buf);
+ case S_permit:
+ case S_deny:
- result->value1 = (void *) regcomp(result->value);
- if (!result->value1) {
- report(LOG_ERR, "in regular expression %s on line %d",
- sym_buf, sym_line);
- tac_exit(1);
- }
- sym_get();
+ result = (NODE *) tac_malloc(sizeof(NODE));
- result->next = parse_cmd_matches();
+ bzero(result, sizeof(NODE));
+ result->line = sym_line;
- return (result);
+ result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
+ result->value = tac_strdup(sym_buf);
+
+#ifdef WITH_INCLUDED_REGEX
+
+ result->value1 = (void *) tac_regcomp(result->value);
+
+#else /* WITH_INCLUDED_REGEX */
+
+ result->value1 = tac_malloc(sizeof(regex_t));
+ if (regcomp(result->value1, result->value /* regex */, REG_NOSUB /* cflags */)) {
+ free(result->value1);
+ result->value1 = NULL;
+ }
+
+#endif /* WITH_INCLUDED_REGEX */
+
+ if (!result->value1) {
+ report(LOG_ERR, "in regular expression %s on line %d",
+ sym_buf, sym_line);
+ tac_exit(1);
+ }
+ sym_get();
+
+ result->when = copy_current_when_decl();
+ expr_sink_register(result->when);
+
+ result->next = NULL;
+ }
+ *succp = result;
+ while (result->next)
+ result = result->next; /* skip parsed chain from parse_cmd_matches() */
+ succp = &result->next;
+ }
+ /* NOTREACHED */
}
+static NODE *parse_attrs TAC_ARGS((void));
+
static NODE *
parse_attrs()
{
+ NODE *retval = NULL, **succp = &retval;
NODE *result;
char buf[MAX_INPUT_LINE_LEN];
- int optional = 0;
+ int optional;
- if (sym_code == S_closebra) {
- return (NULL);
- }
- result = (NODE *) tac_malloc(sizeof(NODE));
+ for (;;) {
+ optional = 0;
- bzero(result, sizeof(NODE));
- result->line = sym_line;
+ switch (sym_code) {
+ case S_closebra:
+ return (retval);
- if (sym_code == S_optional) {
- optional++;
- sym_get();
- }
- result->type = optional ? N_optarg : N_arg;
+ case S_when:
+ if (push_parsed_when_decl())
+ tac_exit(1); /* no error return possibility */
+ parse(S_openbra);
+ result = parse_attrs();
+ parse(S_closebra);
+ if (pop_when_decl())
+ tac_exit(1); /* no error return possibility */
+ break;
- strcpy(buf, sym_buf);
- parse(S_string);
- strcat(buf, sym_buf);
- parse(S_separator);
- strcat(buf, sym_buf);
- parse(S_string);
+ case S_optional:
+ optional = 1;
+ sym_get();
+ /* FALLTHRU */
+ default:
+ result = (NODE *) tac_malloc(sizeof(NODE));
- result->value = tac_strdup(buf);
- result->next = parse_attrs();
- return (result);
+ bzero(result, sizeof(NODE));
+ result->line = sym_line;
+
+ result->type = optional ? N_optarg : N_arg;
+
+ strcpy(buf, sym_buf);
+ parse(S_string);
+ strcat(buf, sym_buf);
+ parse(S_separator);
+ strcat(buf, sym_buf);
+ parse(S_string);
+
+ result->value = tac_strdup(buf);
+
+ result->when = copy_current_when_decl();
+ expr_sink_register(result->when);
+
+ result->next = NULL;
+ }
+ *succp = result;
+ while (result->next)
+ result = result->next; /* skip parsed chain from parse_attrs() */
+ succp = &result->next;
+ }
+ /* NOTREACHED */
}
-static void
- getsym();
+static void sym_get TAC_ARGS((void));
static void
sym_get()
}
}
+static char *sym_buf_add TAC_ARGS((int c));
+
static char *
sym_buf_add(c)
-char c;
+int c; /* promoted "char" type */
{
if (sym_pos >= MAX_INPUT_LINE_LEN) {
sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
sym_buf[sym_pos++] = c;
return(sym_buf);
}
-
+
+static void getsym TAC_ARGS((void));
+
static void
getsym()
{
rch();
return;
+ case '(':
+ strcpy(sym_buf, "(");
+ sym_code = S_openparen;
+ rch();
+ return;
+
+ case ')':
+ strcpy(sym_buf, ")");
+ sym_code = S_closeparen;
+ rch();
+ return;
+
case '#':
while ((sym_ch != '\n') && (sym_ch != EOF))
rch();
rch();
return;
}
-
+
/* fall through */
case '"':
if (!sym_buf_add(sym_ch)) {
}
}
+static void rch TAC_ARGS((void));
+
static void
rch()
{
}
-/* For a user or group, find the value of a field. Does not recurse. */
-VALUE
-get_value(user, field)
-USER *user;
+static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
+
+/* Find the value of a field. Does not recurse. */
+static VALUE
+get_value(entity, field)
+ENTITY *entity;
int field;
{
VALUE v;
+ v.pval = NULL; /* do both just for sure... */
v.intval = 0;
- if (!user) {
- parse_error("get_value: illegal user");
+ if (!entity) {
+ parse_error("get_value: illegal entity");
return (v);
}
switch (field) {
case S_name:
- v.pval = user->name;
+ v.pval = entity->name;
break;
case S_login:
- v.pval = user->login;
+ v.pval = entity->login;
break;
case S_global:
- v.pval = user->global;
- break;
-
- case S_member:
- v.pval = user->member;
+ v.pval = entity->global;
break;
case S_expires:
- v.pval = user->expires;
+ v.pval = entity->expires;
break;
case S_arap:
- v.pval = user->arap;
+ v.pval = entity->arap;
break;
case S_chap:
- v.pval = user->chap;
+ v.pval = entity->chap;
break;
#ifdef MSCHAP
case S_mschap:
- v.pval = user->mschap;
+ v.pval = entity->mschap;
break;
#endif /* MSCHAP */
case S_pap:
- v.pval = user->pap;
+ v.pval = entity->pap;
break;
case S_opap:
- v.pval = user->opap;
+ v.pval = entity->opap;
break;
case S_message:
- v.pval = user->msg;
+ v.pval = entity->msg;
break;
case S_svc:
- v.pval = user->svcs;
+ v.pval = entity->svcs;
break;
case S_before:
- v.pval = user->before_author;
+ v.pval = entity->before_author;
break;
case S_after:
- v.pval = user->after_author;
+ v.pval = entity->after_author;
break;
case S_svc_dflt:
- v.intval = user->svc_dflt;
+ v.intval = entity->svc_dflt;
break;
#ifdef MAXSESS
case S_maxsess:
- v.intval = user->maxsess;
+ v.intval = entity->maxsess;
break;
-#endif
+#endif
case S_nopasswd:
- v.intval = user->nopasswd;
+ v.intval = entity->nopasswd;
break;
-
+
case S_time:
- v.pval = user->time;
+ v.pval = entity->time;
+ break;
+
+ case S_key:
+ if (entity->type == S_user) {
+ report(LOG_ERR, "get_value: S_key field not supported in %s %s",
+ entity_type_to_string(entity->type), entity->name);
+ v.pval = NULL;
+ return(v);
+ }
+ v.pval = entity->key;
break;
default:
return (v);
}
-/* For host , find value of field. Doesn't recursive */
-VALUE
-get_hvalue(host, field)
-HOST *host;
-int field;
+
+/* Internal graph scanning routines */
+
+static enum value_scan_func_result value_scan TAC_ARGS((int type, const char *name, int recurse, value_scan_func_t func, void *func_data));
+
+static enum value_scan_func_result
+value_scan(type, name, recurse, func, func_data)
+int type;
+const char *name;
+int recurse;
+value_scan_func_t func;
+void *func_data;
{
- VALUE v;
- v.intval = 0;
- if(!host) {
- parse_error("get_hvalue: illegal host");
- return (v);
- }
- switch (field) {
- case S_name:
- v.pval = host->name;
- break;
-
- case S_key:
- v.pval = host->key;
- break;
-
- default:
- report(LOG_ERR, "get_value: unknown field %d", field);
- break;
+ ENTITY *entity;
+
+ if (debug & DEBUG_CONFIG_FLAG)
+ report(LOG_DEBUG, "value_scan: find %s %s, recurse=%d",
+ entity_type_to_string(type), name, recurse);
+
+ entity = entity_lookup(type, name);
+ if (!entity) {
+ if (debug & DEBUG_CONFIG_FLAG)
+ report(LOG_DEBUG, "value_scan: no %s named %s",
+ entity_type_to_string(type), name);
+ return (VSFR_CONTINUE);
}
- return (v);
-}
+ return (value_scan_entity(entity, recurse, func, func_data));
+}
/* For each user, check she doesn't circularly reference a
group. Return 1 if it does */
-static int
-circularity_check()
+
+static int circularity_check_failed;
+
+static void circularity_check_fail TAC_ARGS((struct membership *membership));
+
+static void
+circularity_check_fail(membership)
+struct membership *membership;
{
- USER *user, *entry, *group;
- USER **users = (USER **) hash_get_entries(usertable);
- USER **groups = (USER **) hash_get_entries(grouptable);
- USER **p, **q;
+ ENTITY *entity;
- /* users */
- for (p = users; *p; p++) {
- user = *p;
+ circularity_check_failed = 1;
- if (debug & DEBUG_PARSE_FLAG)
- report(LOG_DEBUG, "circularity_check: user=%s", user->name);
+ report(LOG_ERR, "recursively defined groups:");
+ while (membership) {
+ entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);
+ report(LOG_ERR, "%s %s",
+ entity_type_to_string(entity->type), entity->name);
+ membership = value_scan_backward(entity);
+ }
+}
- /* Initialise all groups "seen" flags to zero */
- for (q = groups; *q; q++) {
- group = *q;
- group->flags &= ~FLAG_SEEN;
- }
+static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
- entry = user;
+static enum value_scan_func_result
+circularity_check_func(entity, func_data /* unused */)
+ENTITY *entity;
+void *func_data;
+{
+ /* only useful to speedup case of failure */
+ if (circularity_check_failed)
+ return (VSFR_FOUND);
- while (entry) {
- /* check groups we are a member of */
- char *groupname = entry->member;
+ return (VSFR_CONTINUE);
+}
- if (debug & DEBUG_PARSE_FLAG)
- report(LOG_DEBUG, "\tmember of group %s",
- groupname ? groupname : "<none>");
+static int circularity_check TAC_ARGS((void));
+static int
+circularity_check()
+{
+ ENTITY *entity;
+ ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
+ ENTITY **users;
- /* if not a member of any groups, go on to next user */
- if (!groupname)
- break;
+ /* users */
+ for (users = users_base; *users; users++) {
+ entity = *users;
- 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);
- free(users);
- free(groups);
- return (1);
- }
- if (group->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);
- }
- free(users);
- free(groups);
- return (1);
- }
- group->flags |= FLAG_SEEN; /* mark group as seen */
- entry = group;
- }
+ if (debug & DEBUG_PARSE_FLAG)
+ report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
+
+ circularity_check_failed = 0;
+ value_scan_forward_seen_hook = circularity_check_fail;
+ value_scan_entity(entity, TAC_PLUS_RECURSE,
+ (value_scan_func_t) circularity_check_func, NULL /* func_data-unused */);
+ value_scan_forward_seen_hook = NULL;
+ if (circularity_check_failed)
+ break;
}
- free(users);
- free(groups);
- return (0);
+ free(users_base);
+ return (circularity_check_failed);
}
member of, recursively.
Returns void * because it can return a string or a node pointer
- (should really return a union pointer).
-*/
-static VALUE
-cfg_get_value(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
- USER *user, *group;
- VALUE value;
-
- value.pval = NULL;
-
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_value: name=%s isuser=%d attr=%s rec=%d",
- name, isuser, codestring(attr), recurse);
-
- /* find the user/group entry */
+ (should really return a union pointer).
+*/
- user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
+static VALUE cfg_get_value_VALUE; /* private */
- if (!user) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
- return (value);
- }
+static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
+static enum value_scan_func_result
+cfg_get_value_func(entity,attrp /* func_data */)
+ENTITY *entity;
+int *attrp;
+{
/* found the entry. Lookup value from attr=value */
- value = get_value(user, attr);
+ cfg_get_value_VALUE = get_value(entity, *attrp);
+ if (cfg_get_value_VALUE.pval)
+ return (VSFR_FOUND);
- if (value.pval || !recurse) {
- return (value);
- }
- /* no value. Check containing group */
- if (user->member)
- group = (USER *) hash_lookup(grouptable, user->member);
- else
- group = NULL;
+ return (VSFR_CONTINUE);
+}
- while (group) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
- group->name);
+static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
- value = get_value(group, attr);
+static VALUE
+cfg_get_value(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
+{
+ if (debug & DEBUG_CONFIG_FLAG)
+ report(LOG_DEBUG, "cfg_get_value: type=%s name=%s attr=%s recurse=%d",
+ entity_type_to_string(type), name, codestring(attr), recurse);
- if (value.pval) {
- return (value);
- }
- /* still nothing. Check containing group and so on */
+ cfg_get_value_VALUE.pval = NULL;
+ value_scan(type, name, recurse,
+ (value_scan_func_t) cfg_get_value_func, &attr /* func_data */);
+ return (cfg_get_value_VALUE);
+}
- if (group->member)
- group = (USER *) hash_lookup(grouptable, group->member);
- else
- group = NULL;
- }
- /* no value for this user or her containing groups */
- value.pval = NULL;
- return (value);
-}
+/* Wrappers for cfg_get_value:
+ */
+int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
-/* Wrappers for cfg_get_value */
int
-cfg_get_intvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
+cfg_get_intvalue(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
{
- int val = cfg_get_value(name, isuser, attr, recurse).intval;
+ int val = cfg_get_value(type, name, attr, recurse).intval;
if (debug & DEBUG_CONFIG_FLAG)
report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
return(val);
}
-char *
-cfg_get_pvalue(name, isuser, attr, recurse)
-char *name;
-int isuser, attr, recurse;
-{
- char *p = cfg_get_value(name, isuser, attr, recurse).pval;
-
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
- p ? p : "NULL");
- return(p);
-}
-
-/* For getting host values */
-static VALUE
-cfg_get_hvalue(name, attr)
-char *name;
-int attr;
-{
- HOST *host;
- VALUE value;
-
- value.pval = NULL;
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_hvalue: name=%s attr=%s ",
- name, codestring(attr));
-
- /* find the host entry in hash table */
-
- host = (HOST *) hash_lookup( hosttable, name);
+const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
- if (!host) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
- return (value);
- }
-
- /* found the entry. Lookup value from attr=value */
- value = get_hvalue(host, attr);
-
- if (value.pval) {
- return (value);
- }
- /* No any value for this host */
- value.pval = NULL;
- return (value);
-}
-
-/* Wrappers for cfg_get_hvalue */
-char *
-cfg_get_phvalue(name, attr)
-char *name;
-int attr;
+const char *
+cfg_get_pvalue(type, name, attr, recurse)
+int type;
+const char *name;
+int attr, recurse;
{
- char *p = cfg_get_hvalue(name, attr).pval;
+ char *p = cfg_get_value(type, name, attr, recurse).pval;
if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_phvalue: returns %s",
- p ? p : "NULL");
+ report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
+ p ? p : "NULL");
return(p);
}
-/*
- Read the config file and do some basic sanity checking on
- it. Return 1 if we find any errors. */
+/* Read the config file and do some basic sanity checking on
+ * it. Return 1 if we find any errors.
+ */
+int cfg_read_config TAC_ARGS((const char *cfile));
+int
cfg_read_config(cfile)
-char *cfile;
+const char *cfile;
{
sym_line = 1;
return (1);
}
- if (circularity_check()) {
+ if (0
+ || enlist_entity_connect()
+ || expr_sink_commit()
+ /* circularity is allowed in the new fully-recursive algorithm */
+ || (!algorithm_recursive && circularity_check())
+ ) {
+ fclose(cf);
+ return (1);
+ }
+ if (!WHEN_EXPR_ROOT_EMPTY() || when_expr_dungeon) {
+ report(LOG_ERR, "Some 'when' expression found still pushed on stack");
fclose(cf);
return (1);
}
return (0);
}
-/* return 1 if user exists, 0 otherwise */
+/* return 1 if user exists, 0 otherwise
+ */
+int cfg_user_exists TAC_ARGS((const char *username));
+
int
cfg_user_exists(username)
-char *username;
+const char *username;
{
- USER *user = (USER *) hash_lookup(usertable, username);
-
- return (user != NULL);
+ return (NULL != hash_lookup(usertable, username));
}
/* return expiry string of user. If none, try groups she is a member
- on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_expires(username, recurse)
-char *username;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
+const char *
+cfg_get_expires(username, recurse)
+const char *username;
+int recurse;
{
- return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
+ return (cfg_get_pvalue(S_user, username, S_expires, recurse));
}
/* return time string of user. If none, try groups she is a member
- on, and so on, recursively if recurse is non-zero */
-char *
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
+
+const char *
cfg_get_timestamp(username, recurse)
-char *username;
+const char *username;
+int recurse;
{
- return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
+ return (cfg_get_pvalue(S_user, username, S_time, recurse));
}
-
/* return password string of user. If none, try groups she is a member
- on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_login_secret(user, recurse)
-char *user;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
+const char *
+cfg_get_login_secret(user, recurse)
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
+ return (cfg_get_pvalue(S_user, user, S_login, recurse));
}
/* return value of the nopasswd field. If none, try groups she is a member
- on, and so on, recursively if recurse is non-zero */
+ * on, and so on, recursively if recurse is non-zero
+ */
+int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
+
int
cfg_get_user_nopasswd(user, recurse)
- char *user;
+const char *user;
+int recurse;
{
- return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
+ return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
}
/* return user's secret. If none, try groups she is a member
- on, and so on, recursively if recurse is non-zero */
-char *
-cfg_get_arap_secret(user, recurse)
-char *user;
+ * on, and so on, recursively if recurse is non-zero
+ */
+const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
+const char *
+cfg_get_arap_secret(user, recurse)
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
+ return (cfg_get_pvalue(S_user, user, S_arap, recurse));
}
-char *
-cfg_get_chap_secret(user, recurse)
-char *user;
+const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
+const char *
+cfg_get_chap_secret(user, recurse)
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
+ return (cfg_get_pvalue(S_user, user, S_chap, recurse));
}
#ifdef MSCHAP
-char *
-cfg_get_mschap_secret(user, recurse)
-char *user;
+const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
+cfg_get_mschap_secret(user, recurse)
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
+ return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
}
+
#endif /* MSCHAP */
-char *
+const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
cfg_get_pap_secret(user, recurse)
-char *user;
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
+ return (cfg_get_pvalue(S_user, user, S_pap, recurse));
}
-char *
+const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
+
+const char *
cfg_get_opap_secret(user, recurse)
-char *user;
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
+ return (cfg_get_pvalue(S_user, user, S_opap, recurse));
}
/* return the global password for the user (or the group, etc.) */
-char *
-cfg_get_global_secret(user, recurse)
-char *user;
+const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
+const char *
+cfg_get_global_secret(user, recurse)
+const char *user;
+int recurse;
{
- return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
+ return (cfg_get_pvalue(S_user, user, S_global, recurse));
}
#ifdef USE_PAM
+
/* Return a pointer to a node representing a PAM Service name */
-char *
-cfg_get_pam_service(user,recurse)
-char *user;
+const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
+
+const char *
+cfg_get_pam_service(user, recurse)
+const char *user;
+int recurse;
{
- char *cfg_passwd;
- char *p;
+ const char *cfg_passwd;
+ const char *p;
-cfg_passwd = cfg_get_pap_secret(user, recurse);
-
-if (!cfg_passwd) {
- cfg_passwd = cfg_get_global_secret(user, recurse);
-}
-
-if (!cfg_passwd && !cfg_user_exists(user)) {
+ cfg_passwd = cfg_get_pap_secret(user, recurse);
+
+ if (!cfg_passwd)
+ cfg_passwd = cfg_get_global_secret(user, recurse);
+
+ if (!cfg_passwd && !cfg_user_exists(user)) {
cfg_passwd = cfg_get_authen_default();
switch (cfg_get_authen_default_method()) {
- case (S_pam):
- if (debug & DEBUG_AUTHOR_FLAG)
- report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
- return(cfg_passwd);
- break;
- default:
- if (debug & DEBUG_AUTHOR_FLAG)
- report(LOG_DEBUG, "I havent find any PAM Service!!");
- return(NULL);/* Haven't any PAM Service!! */
+
+ case (S_pam):
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
+ return(cfg_passwd);
+ break;
+
+ default:
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG, "I havent find any PAM Service!!");
+ return(NULL);/* Haven't any PAM Service!! */
}
-}
+ }
-p=tac_find_substring("pam ", cfg_passwd);
+ p = tac_find_substring("pam ", cfg_passwd);
-if(p) { /* We find PAM services */
+ if(p) { /* We find PAM services */
if (debug & DEBUG_AUTHOR_FLAG)
report(LOG_DEBUG, "I get PAM sevice:%s",p);
-return (p);
-}
+ return (p);
+ }
-if (debug & DEBUG_AUTHOR_FLAG)
+ if (debug & DEBUG_AUTHOR_FLAG)
report(LOG_DEBUG, "No any PAM Sevice");
-return(NULL);
+ return(NULL);
}
#endif /* For PAM */
-
/* Return a pointer to a node representing a given service
authorization, taking care of recursion issues correctly. Protocol
- is only read if the type is N_svc_ppp. svcname is only read if type
+ is only read if the svctype is N_svc_ppp. svcname is only read if type
is N_svc.
*/
-NODE *
-cfg_get_svc_node(username, type, protocol, svcname, recurse)
-char *username;
-int type;
-char *protocol, *svcname;
-int recurse;
-{
- USER *user, *group;
- NODE *svc;
-
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG,
- "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
- username,
- cfg_nodestring(type),
- protocol ? protocol : "",
- svcname ? svcname : "",
- recurse);
-
- /* find the user/group entry */
- user = (USER *) hash_lookup(usertable, username);
+struct cfg_get_svc_node_param {
+ int svctype;
+ const char *protocol, *svcname;
+ NODE *node;
+ int retval;
+};
- if (!user) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
- return (NULL);
- }
+static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
- /* found the user entry. Find svc node */
- for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
+static enum value_scan_func_result
+cfg_get_svc_node_func(entity, param /* func_data */)
+ENTITY *entity;
+struct cfg_get_svc_node_param *param;
+{
+ NODE *svc;
+ enum eval_result svc_default;
- if (svc->type != type)
+ for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
+ if (svc->type != param->svctype)
continue;
-
- if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
+ if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
continue;
- }
-
- if (type == N_svc && !STREQ(svc->value1, svcname)) {
+ if (param->svctype == N_svc && param->svcname && !STREQ(svc->value1, param->svcname ))
+ continue;
+ if (expr_eval(svc->when) != ER_TRUE) /* expensive */
continue;
- }
if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG,
+ report(LOG_DEBUG,
"cfg_get_svc_node: found %s proto=%s svcname=%s",
- cfg_nodestring(type),
- protocol ? protocol : "",
- svcname ? svcname : "");
+ cfg_nodestring(param->svctype),
+ param->protocol ? param->protocol : "",
+ param->svcname ? param->svcname : "");
- return(svc);
+ param->node = svc;
+ param->retval = 1;
+ return (VSFR_FOUND);
}
- if (!recurse) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
- return (NULL);
- }
-
- /* no matching node. Check containing group */
- if (user->member)
- group = (USER *) hash_lookup(grouptable, user->member);
- else
- group = NULL;
-
- while (group) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
- group->name);
-
- for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
-
- if (svc->type != type)
- continue;
+ /* look at 'default service' settings */
+ svc_default = entity_svc_default(entity);
+ switch (svc_default) {
- if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
- continue;
- }
+ case ER_TRUE:
+ case ER_FALSE:
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG,
+ "cfg_get_svc_node: svc=%s protocol=%s svcname=%s forced %s by default service",
+ cfg_nodestring(param->svctype),
+ param->protocol ? param->protocol : "",
+ param->svcname ? param->svcname : "",
+ (svc_default == ER_TRUE ? "permit" : "deny"));
+
+ param->retval = (svc_default == ER_TRUE);
+ return (VSFR_FOUND);
+
+ default: /* shouldn't happen */
+ case ER_UNKNOWN:
+ return (VSFR_CONTINUE);
+ }
+ /* NOTREACHED */
+}
- if (type == N_svc && !STREQ(svc->value1, svcname)) {
- continue;
- }
+int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG,
- "cfg_get_svc_node: found %s proto=%s svcname=%s",
- cfg_nodestring(type),
- protocol ? protocol : "",
- svcname ? svcname : "");
+int
+cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
+const char *username;
+int svctype;
+const char *protocol;
+const char *svcname;
+int recurse;
+NODE **nodep;
+{
+ struct cfg_get_svc_node_param param;
+ enum value_scan_func_result vsfr;
- return(svc);
- }
+ param.svctype = svctype;
+ param.protocol = protocol;
+ param.svcname = svcname;
+ param.node = NULL;
+ param.retval = 0;
- /* still nothing. Check containing group and so on */
+ if (debug & DEBUG_CONFIG_FLAG)
+ report(LOG_DEBUG,
+ "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
+ username,
+ cfg_nodestring(svctype),
+ protocol ? protocol : "",
+ svcname ? svcname : "",
+ recurse);
- if (group->member)
- group = (USER *) hash_lookup(grouptable, group->member);
- else
- group = NULL;
- }
+ vsfr = value_scan(S_user, username, recurse,
+ (value_scan_func_t) cfg_get_svc_node_func, ¶m /* func_data */);
+ if (nodep)
+ *nodep = param.node;
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
+ if (vsfr == VSFR_FOUND)
+ return (param.retval);
- /* no matching svc node for this user or her containing groups */
- return (NULL);
+ /* The service does not exist. Do the default */
+ return (cfg_no_user_permitted() ? 1 : 0);
}
-/* Return a pointer to the node representing a set of command regexp
+/* Return a pointer to the node representing a set of command tac_regexp
matches for a user and command, handling recursion issues correctly */
-NODE *
-cfg_get_cmd_node(name, cmdname, recurse)
-char *name, *cmdname;
-int recurse;
+struct cfg_authorize_cmd_param {
+ const char *cmd;
+ const char *args;
+ enum eval_result result;
+};
+
+static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
+
+static enum value_scan_func_result
+cfg_authorize_cmd_func(entity, param /* func_data */)
+ENTITY *entity;
+struct cfg_authorize_cmd_param *param;
{
- USER *user, *group;
NODE *svc;
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_cmd_node: name=%s cmdname=%s rec=%d",
- name, cmdname, recurse);
+ for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
+ NODE *node;
- /* find the user/group entry */
- user = (USER *) hash_lookup(usertable, name);
+ if (svc->type != N_svc_cmd)
+ continue;
+ if (!STREQ(svc->value, param->cmd))
+ continue;
+ if (expr_eval(svc->when) != ER_TRUE) /* expensive */
+ continue;
- if (!user) {
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 */
- svc = (NODE *) get_value(user, S_svc).pval;
-
- 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 %s node",
- cmdname, cfg_nodestring(svc->type));
- return (svc);
- }
- svc = svc->next;
- }
+ report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
+ param->cmd, cfg_nodestring(svc->type));
- if (!recurse) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
- return (NULL);
- }
- /* no matching node. Check containing group */
- if (user->member)
- group = (USER *) hash_lookup(grouptable, user->member);
- else
- group = NULL;
+ /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
- while (group) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
- group->name);
+ for (node = svc->value1; node; node = node->next) {
+ int match;
+
+ if (expr_eval(node->when) != ER_TRUE) /* expensive */
+ continue;
+
+#ifdef WITH_INCLUDED_REGEX
+
+ match = tac_regexec((tac_regexp *) node->value1, param->args);
+
+#else /* WITH_INCLUDED_REGEX */
+
+ match = !regexec((const regex_t *) node->value1, param->args /* string */,
+ 0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
- svc = get_value(group, S_svc).pval;
+#endif /* WITH_INCLUDED_REGEX */
- 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));
- return (svc);
+ if (debug & DEBUG_AUTHOR_FLAG) {
+ report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
+ node->line, param->cmd,
+ node->type == N_permit ? "permit" : "deny",
+ (const char *) node->value, param->args, (match ? "" : "no "));
+ }
+
+ if (!match)
+ continue;
+
+ switch (node->type) {
+ case N_permit:
+ if (debug & DEBUG_AUTHOR_FLAG) {
+ report(LOG_DEBUG, "%s %s permitted by line %d",
+ param->cmd, param->args, node->line);
+ }
+ param->result = ER_TRUE;
+ return (VSFR_FOUND);
+ break;
+ case N_deny:
+ if (debug & DEBUG_AUTHOR_FLAG) {
+ report(LOG_DEBUG, "%s %s denied by line %d",
+ param->cmd, param->args, node->line);
+ }
+ param->result = ER_FALSE;
+ return (VSFR_FOUND);
+ break;
+ default:
+ report(LOG_ERR, "INTERNAL: illegal configuration node: %s: %s %s",
+ session.peer, param->cmd, param->args);
+ param->result = ER_UNKNOWN; /* error */
+ return (VSFR_FOUND);
}
- svc = svc->next;
}
+ if (!algorithm_recursive) { /* compatibility mode: */
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG, "cmd %s exists, but no args match, denied (as no 'authorization = recursive' found)",
+ param->cmd);
+ param->result = ER_FALSE; /* emulate last "deny .*" */
+ return (VSFR_FOUND);
+ }
+ }
+
+ /* look at 'default service' settings */
+ param->result = entity_svc_default(entity);
+ switch (param->result) {
- /* still nothing. Check containing group and so on */
+ case ER_TRUE:
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
+ return (VSFR_FOUND);
+
+ case ER_FALSE:
+
+ if (debug & DEBUG_AUTHOR_FLAG)
+ report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
+ return (VSFR_FOUND);
- if (group->member)
- group = (USER *) hash_lookup(grouptable, group->member);
- else
- group = NULL;
+ default: /* shouldn't happen */
+ case ER_UNKNOWN:
+ return (VSFR_CONTINUE);
}
+ /* NOTREACHED */
+}
+
+enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
+
+enum eval_result
+cfg_authorize_cmd(username, cmd, args)
+const char *username;
+const char *cmd;
+const char *args;
+{
+ struct cfg_authorize_cmd_param param;
+
+ param.cmd = cmd;
+ param.args = args;
+ param.result = ER_UNKNOWN; /* error */
if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
+ report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
+ username, cmd, args);
- /* no matching cmd node for this user or her containing groups */
- return (NULL);
+ value_scan(S_user, username, TAC_PLUS_RECURSE,
+ (value_scan_func_t) cfg_authorize_cmd_func, ¶m /* func_data */);
+
+ if (param.result != ER_UNKNOWN)
+ return (param.result);
+
+ /* The command does not exist. Do the default */
+ return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
}
/* Return an array of character strings representing configured AV
- * pairs, given a username and a service node.
+ * pairs, given a username and a service node.
*
* In the AV strings returned, manipulate the separator character to
* indicate which args are optional and which are mandatory.
* Lastly, indicate what default permission was configured by setting
* denyp */
+char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
+
char **
cfg_get_svc_attrs(svcnode, denyp)
NODE *svcnode;
i = 0;
for (node = svcnode->value; node; node = node->next) {
- char *arg = tac_strdup(node->value);
- char *p = index(arg, '=');
+ char *arg;
+ char *p;
+
+ if (expr_eval(node->when) != ER_TRUE) /* expensive */
+ continue; /* ignore this node */
+ arg = tac_strdup(node->value);
+ p = index(arg, '=');
if (p && node->type == N_optarg)
*p = '*';
args[i++] = arg;
}
-int
-cfg_user_svc_default_is_permit(user)
-char *user;
+static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
+static enum eval_result
+entity_svc_default(entity)
+ENTITY *entity;
{
- int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
- TAC_PLUS_RECURSE);
-
- switch (permit) {
- default: /* default is deny */
- case S_deny:
- return (0);
+ switch (entity->svc_dflt) {
case S_permit:
- return (1);
+ return (ER_TRUE);
+ case S_deny:
+ return (ER_FALSE);
+ case S_default:
+ case 0: /* not specified */
+ return (ER_UNKNOWN);
+ default:
+ report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
+ return (ER_UNKNOWN);
}
}
+int cfg_no_user_permitted TAC_ARGS((void));
+
int
cfg_no_user_permitted()
{
}
-char *
+const char *cfg_get_authen_default TAC_ARGS((void));
+
+const char *
cfg_get_authen_default()
{
return (authen_default);
}
+int cfg_get_authen_default_method TAC_ARGS((void));
+
/* For describe authentication method(pam,file,db..etc) */
-int
+int
cfg_get_authen_default_method()
{
return (authen_default_method);
}
-/* Return 1 if this user has any ppp services configured. Used for
- authorizing ppp/lcp requests */
-int
-cfg_ppp_is_configured(username, recurse)
- char *username;
- int recurse;
-{
- USER *user, *group;
- NODE *svc;
+/* Host entity management:
+ */
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: username=%s rec=%d",
- username, recurse);
+const char *cfg_get_host_key TAC_ARGS((const char *host));
- /* find the user/group entry */
- user = (USER *) hash_lookup(usertable, username);
+/* For getting host key */
+const char *
+cfg_get_host_key(host)
+const char *host;
+{
+ return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
+}
- if (!user) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s",
- username);
- return (0);
- }
+static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
- /* found the user entry. Find svc node */
- for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
+static ENTITY *
+force_belong_entity(type, name)
+int type;
+const char *name;
+{
+ ENTITY *entity = entity_lookup(type, name);
- if (svc->type != N_svc_ppp)
- continue;
+ if (entity)
+ eval_force_belong_entity(entity);
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
- svc->value1);
-
- return(1);
- }
+ return (entity);
+}
- if (!recurse) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
- return (0);
- }
+/* assumed existing initialized "session.peer*" */
- /* no matching node. Check containing group */
- if (user->member)
- group = (USER *) hash_lookup(grouptable, user->member);
- else
- group = NULL;
+static ENTITY *request_peer_addr;
+static ENTITY *request_peer;
+static ENTITY *request_DEFAULT_group;
- while (group) {
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
- group->name);
+static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
- for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
+static void
+enlist_request_peer(hostname, entityp)
+const char *hostname;
+ENTITY **entityp;
+{
+ *entityp = NULL;
+ if (!hostname)
+ return;
- if (svc->type != N_svc_ppp)
- continue;
+ *entityp = force_belong_entity(S_host, hostname);
+ if (*entityp && request_DEFAULT_group)
+ virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, *entityp /* child */);
+}
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
- svc->value1);
-
- return(1);
- }
+/* Try to build the following scenery:
+ *
+ * host <session.peer_addr> [=ER_TRUE]
+ * |
+ * +-- group <DEFAULT_GROUPNAME>
+ *
+ * host <session.peer > [=ER_TRUE]
+ * |
+ * +-- group <DEFAULT_GROUPNAME>
+ */
- /* still nothing. Check containing group and so on */
+void cfg_request_scan_begin TAC_ARGS((void));
- if (group->member)
- group = (USER *) hash_lookup(grouptable, group->member);
- else
- group = NULL;
- }
+void
+cfg_request_scan_begin()
+{
+ request_scan_begin();
- if (debug & DEBUG_CONFIG_FLAG)
- report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
+ request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
- /* no PPP svc nodes for this user or her containing groups */
- return (0);
+ if (session.peer_addr != session.peer)
+ enlist_request_peer(session.peer_addr, &request_peer_addr);
+ enlist_request_peer(session.peer, &request_peer);
}
-/* For getting host key */
-char *
-cfg_get_host_key(host)
-char *host;
+/* Try to build the following scenery:
+ *
+ * ( user <identity->username> | user <DEFAULT_USERNAME> ) [=ER_TRUE]
+ * |
+ * +-- host <session.peer_addr> [=ER_TRUE]
+ * | |
+ * | +- group <DEFAULT_GROUPNAME>
+ * |
+ * +-- host <session.peer > [=ER_TRUE]
+ * | |
+ * | +-- group <DEFAULT_GROUPNAME>
+ * |
+ * +-- group <DEFAULT_GROUPNAME>
+ */
+
+void cfg_request_identity TAC_ARGS((const struct identity *identity));
+
+void
+cfg_request_identity(identity)
+const struct identity *identity;
{
- return (cfg_get_phvalue(host, S_key));
-}
+ ENTITY *user_entity,*request_DEFAULT_group;
+ if (debug & DEBUG_CONFIG_FLAG)
+ report(LOG_DEBUG, "cfg_request_identity: username=%s, NAS_name=%s, NAS_port=%s, NAC_address=%s, priv_lvl=%d",
+ identity->username, identity->NAS_name, identity->NAS_port, identity->NAC_address, identity->priv_lvl);
+
+ user_entity = force_belong_entity(S_user, identity->username);
+ request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
+
+ if (!user_entity)
+ user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
+
+ request_scan_user_known = 1;
+
+ if (!user_entity)
+ return;
+
+ if (request_peer_addr)
+ virtual_enlist_entity_direct(request_peer_addr /* parent */, user_entity /* child */);
+ if (request_peer )
+ virtual_enlist_entity_direct(request_peer /* parent */, user_entity /* child */);
+ if (request_DEFAULT_group)
+ virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, user_entity /* child */);
+}