2 Copyright (c) 1995-1998 by Cisco systems, Inc.
4 Permission to use, copy, modify, and distribute this software for
5 any purpose and without fee is hereby granted, provided that this
6 copyright and permission notice appear on all copies of the
7 software and supporting documentation, the name of Cisco Systems,
8 Inc. not be used in advertising or publicity pertaining to
9 distribution of the program without specific prior permission, and
10 notice be given in supporting documentation that modification,
11 copying and distribution is by permission of Cisco Systems, Inc.
13 Cisco Systems, Inc. makes no representations about the suitability
14 of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
15 IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16 WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS FOR A PARTICULAR PURPOSE.
28 #ifndef WITH_INCLUDED_REGEX
40 #include "do_author.h" /* for "struct identity" */
42 #ifdef WITH_INCLUDED_REGEX
43 #include "tac_regexp.h"
47 static void sym_get TAC_ARGS((void));
48 static void when_expr_root_init TAC_ARGS((void));
49 static void rch TAC_ARGS((void));
50 static int parse_entity TAC_ARGS((int entity_type));
51 static NODE *parse_svcs TAC_ARGS((void));
52 static int parse_conditional_block TAC_ARGS((ENTITY *entity));
53 static NODE *parse_cmd_matches TAC_ARGS((void));
54 static NODE *parse_attrs TAC_ARGS((void));
55 static void getsym TAC_ARGS((void));
56 static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
62 <decl> := <top_level_decl> | <entity_decl>
64 <top_level_decl> := <authen_default> |
65 accounting file = <string> |
66 default authorization = permit |
68 authorization = ( first | recursive )
70 <authen_default> := default authentication = file <filename>
75 <permission> := permit | deny
77 <filename> := <string>
79 <password> := <string>
81 <user_decl> := user = <string> {
87 <host_decl> := host = <string> {
93 <group_decl> := group = <string> {
99 <service_default> := default service = ( permit | deny | default )
101 <password_spec> := file <filename> |
103 cleartext <password> |
114 <user_attr> := name = <string> |
115 login = <password_spec> |
118 arap = cleartext <string> |
119 chap = cleartext <string> |
121 ms-chap = cleartext <string> |
123 pap = cleartext <string> |
126 pap = pam <pam_service> |
128 opap = cleartext <string> |
129 global = cleartext <string> |
131 before authorization = <string> |
132 after authorization = <string> |
135 <host_attr> := key = <string> |
138 <group_attr> := enlist = <entity_spec> |
142 <when_attr> := member = <string> |
143 enlist = <entity_spec> |
147 <when_attr_block> := <when_decl> {
151 <svc> := <svc_auth> | <cmd_auth>
153 <cmd_auth> := cmd = <string> {
157 <when_match> := <permission> <string> |
160 <when_match_block> := <when_decl> {
164 <svc_auth> := service = ( exec | arap | slip | ppp protocol = <string> ) {
165 # first matching <svc_auth> is the FINAL one, no further graph scanning occurs!
166 [ default attribute = permit ]
170 <when_AV_pair> := [ optional ] <string> = <string> |
173 <when_AV_pair_block> := <when_decl> {
177 <when_decl> := when = <expr>
179 # to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
180 <expr> := <entity_spec> |
185 <expr_or> := <expr> |
188 <expr_and> := <expr> |
189 <expr> and <expr_and>
191 <entity_spec> := ( user | host | group ) <string>
194 static char sym_buf[MAX_INPUT_LINE_LEN]; /* parse buffer */
195 static int sym_pos=0; /* current place in sym_buf */
196 static int sym_ch; /* current parse character */
197 static int sym_code; /* parser output */
198 static int sym_line = 1; /* current line number for parsing */
199 static FILE *cf = NULL; /* config file pointer */
200 static int sym_error = 0; /* a parsing error has occurred */
201 static int no_user_dflt = 0; /* default if user doesn't exist */
202 /* ='default authorization': 0/S_permit */
203 static int algorithm_recursive = 0; /* use newer authorization alogrithm? */
204 /* 1 if 'authorization = recursive' */
205 static char *authen_default = NULL; /* top level authentication default */
206 /* ='default authentication' */
207 static int authen_default_method = 0; /* For method check */
208 /* ='default authentication' symbol */
209 static char *nopasswd_str = "nopassword";
212 /* Only the first 2 fields (name and hash) are used by the hash table
213 routines to hashh structures into a table.
216 static void *grouptable[HASH_TAB_SIZE]; /* Table of group declarations */
217 static void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
218 static void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
221 struct enlist_entity_item {
222 struct enlist_entity_item *next;
223 int parent_type; char *parent;
224 int child_type; char * child; /* will be created when not found (for "enlist") */
228 static struct enlist_entity_item * enlist_entity_list;
229 static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
232 static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
236 #include <stdarg.h> /* ANSI C, variable length args */
238 parse_error(char *fmt,...)
242 #include <varargs.h> /* has 'vararg' definitions */
245 parse_error(fmt, va_alist)
247 va_dcl /* no terminating semi-colon */
249 #endif /* __STDC__ */
251 char msg[256]; /* temporary string */
259 vsprintf(msg, fmt, ap);
262 report(LOG_ERR, "%s", msg);
263 fprintf(stderr, "Error: %s\n", msg);
267 const char *cfg_nodestring TAC_ARGS((int type));
275 return ("unknown node type");
283 return ("N_svc_exec");
285 return ("N_svc_slip");
287 return ("N_svc_ppp");
289 return ("N_svc_arap");
291 return ("N_svc_cmd");
299 const char *entity_type_to_string TAC_ARGS((int entity_type));
302 entity_type_to_string(entity_type)
305 switch (entity_type) {
316 static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
319 entity_type_to_hashtable(entity_type)
322 switch (entity_type) {
333 void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
336 scan_invalidate_entities(what)
337 enum invalidate_scan what;
339 scan_invalidate_entities_hashtable( usertable, what);
340 scan_invalidate_entities_hashtable( hosttable, what);
341 scan_invalidate_entities_hashtable(grouptable, what);
345 static void free_attrs TAC_ARGS((NODE *node));
354 unlink_expr(node->when);
355 free_expr(node->when);
358 switch (node->type) {
361 if (debug & DEBUG_CLEAN_FLAG)
362 report(LOG_DEBUG, "free_cmd_match %s %s",
363 cfg_nodestring(node->type),
364 (const char *) node->value);
367 report(LOG_ERR, "Illegal node type %s for free_attrs",
368 cfg_nodestring(node->type));
379 static void free_cmd_matches TAC_ARGS((NODE *node));
382 free_cmd_matches(node)
388 if (debug & DEBUG_CLEAN_FLAG)
389 report(LOG_DEBUG, "free_cmd_match %s %s",
390 cfg_nodestring(node->type),
391 (const char *) node->value);
393 unlink_expr(node->when);
394 free_expr(node->when);
397 free(node->value); /* text */
399 #ifdef WITH_INCLUDED_REGEX
401 free(node->value1); /* tac_regexp compiled text */
403 #else /* WITH_INCLUDED_REGEX */
405 regfree((regex_t *) node->value1); /* POSIX regex compiled text */
407 #endif /* WITH_INCLUDED_REGEX */
415 static void free_svcs TAC_ARGS((NODE *node));
424 unlink_expr(node->when);
425 free_expr(node->when);
428 switch (node->type) {
430 if (debug & DEBUG_CLEAN_FLAG)
431 report(LOG_DEBUG, "free %s %s",
432 cfg_nodestring(node->type),
433 (const char *) node->value);
434 free(node->value); /* cmd name */
435 free_cmd_matches(node->value1);
448 if (debug & DEBUG_CLEAN_FLAG)
449 report(LOG_DEBUG, "free %s", cfg_nodestring(node->type));
450 free_attrs(node->value);
457 report(LOG_ERR, "Illegal node type %d for free_svcs", node->type);
463 static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
466 free_enlist_entity_item(item)
467 struct enlist_entity_item *item;
471 free_expr(item->when);
475 static void free_entity TAC_ARGS((ENTITY *entity));
481 if (debug & DEBUG_CLEAN_FLAG)
482 report(LOG_DEBUG, "free %s %s",
483 entity_type_to_string(entity->type), entity->name);
485 /* function MUST be called while the whole entity is still VALID! */
486 scan_free_entity(entity);
490 if (entity->full_name)
491 free(entity->full_name);
495 free(entity->expires);
504 free(entity->mschap);
511 free(entity->global);
514 if (entity->before_author)
515 free(entity->before_author);
516 if (entity->after_author)
517 free(entity->after_author);
520 free_svcs(entity->svcs);
523 static void free_hashtable TAC_ARGS((void **hashtable));
526 free_hashtable(hashtable)
530 ENTITY *entity,**entityp;
532 for (i = 0; i < HASH_TAB_SIZE; i++) {
533 entityp = (ENTITY **) (hashtable+i);
534 while ((entity = *entityp)) {
535 *entityp = entity->hash;
547 void cfg_clean_config TAC_ARGS((void));
549 /* Free all allocated structures preparatory to re-reading the config file */
553 struct enlist_entity_item *enlist_entity_item;
555 if (authen_default) {
556 free(authen_default);
557 authen_default = NULL;
560 if (algorithm_recursive) {
561 algorithm_recursive = 0;
564 if (authen_default_method) {
565 authen_default_method = 0;
573 if (session.acctfile) {
574 free(session.acctfile);
575 session.acctfile = NULL;
578 if (session.db_acct) {
579 free(session.db_acct);
580 session.db_acct = NULL;
583 free_hashtable( usertable);
584 free_hashtable( hosttable);
585 free_hashtable(grouptable);
587 while (enlist_entity_list) {
588 enlist_entity_item = enlist_entity_list;
589 enlist_entity_list = enlist_entity_item->next;
590 free_enlist_entity_item(enlist_entity_item);
591 free(enlist_entity_item);
593 enlist_entity_list_tailp = &enlist_entity_list;
596 static int parse_permission TAC_ARGS((void));
601 int symbol = sym_code;
603 if (sym_code != S_permit && sym_code != S_deny) {
604 parse_error("expecting permit or deny but found '%s' on line %d",
613 static int parse TAC_ARGS((int symbol));
620 if (sym_code != symbol) {
621 parse_error("expecting '%s' but found '%s' on line %d",
622 (symbol == S_string ? "string" : codestring(symbol)),
630 static int parse_opt_svc_default TAC_ARGS((void));
633 parse_opt_svc_default()
637 if (sym_code != S_default) {
647 parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
652 if (!algorithm_recursive) {
653 parse_error("'default service = %s' supported only if set top level 'authorization = recursive', on line %d",
666 static int parse_opt_attr_default TAC_ARGS((void));
669 parse_opt_attr_default()
671 if (sym_code != S_default)
682 Parse lines in the config file, creating data structures
683 Return 1 on error, otherwise 0 */
685 static int parse_decls TAC_ARGS((void));
690 no_user_dflt = 0; /* default if user doesn't exist */
691 algorithm_recursive = 0; /* use backward compatible alg. by default */
692 when_expr_root_init();
693 enlist_entity_list_tailp = &enlist_entity_list;
698 bzero(grouptable, sizeof(grouptable));
699 bzero(usertable, sizeof(usertable));
700 bzero(hosttable, sizeof(hosttable));
704 /* Top level of parser */
715 if (session.acctfile)
716 free(session.acctfile);
717 session.acctfile = tac_strdup(sym_buf);
722 case S_db_accounting:
726 free(session.db_acct);
727 session.db_acct = tac_strdup(sym_buf);
737 "Expecting default authorization/authentication on lines %d",
741 case S_authentication:
742 if (authen_default) {
744 "Multiply defined authentication default on line %d",
748 parse(S_authentication);
763 authen_default_method = sym_code;
767 parse_error("expecting default_method keyword after 'default authentication = ' on line %d",sym_line);
772 authen_default = tac_strdup(sym_buf);
776 case S_authorization:
777 parse(S_authorization);
780 no_user_dflt = S_permit;
782 "default authorization = permit is now deprecated. Please use user = DEFAULT instead");
786 case S_authorization:
791 parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
797 algorithm_recursive = 0;
802 algorithm_recursive = 1;
807 /* Process a key declaration. */
811 parse_error("multiply defined key on lines %d and %d",
812 session.keyline, sym_line);
815 session.key = tac_strdup(sym_buf);
816 session.keyline = sym_line;
823 parse_entity(sym_code);
827 parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
833 /* Assign a value to a field. Issue an error message and return 1 if
834 it's already been assigned. This is a macro because I was sick of
835 repeating the same code fragment over and over */
837 #define ASSIGN(field) \
838 sym_get(); parse(S_separator); if (field) { \
839 parse_error("Duplicate value for %s %s and %s on line %d", \
840 codestring(sym_code), field, sym_buf, sym_line); \
843 field = tac_strdup(sym_buf);
845 static struct expr *when_expr_root;
846 #define WHEN_EXPR_ROOT_SANE() \
847 (when_expr_root && !when_expr_root->next && when_expr_root->type==S_and)
848 #define WHEN_EXPR_ROOT_EMPTY() \
849 (WHEN_EXPR_ROOT_SANE() && !when_expr_root->u.and_or.child_first)
851 static struct expr *parse_expr_node TAC_ARGS((int single_item));
854 parse_expr_node(single_item)
857 struct expr *expr_root = NULL;
858 struct expr **succ_exprp = &expr_root;
865 expr = (struct expr *) tac_malloc(sizeof(struct expr));
866 expr->line = sym_line;
869 succ_exprp = &expr->next;
872 expr->u.not.child = parse_expr_node(1 /* single_item */);
873 if (!expr->u.not.child) {
874 free_expr(expr_root);
882 expr = (struct expr *) tac_malloc(sizeof(struct expr));
883 expr->line = sym_line;
886 succ_exprp = &expr->next;
887 expr->type = sym_code;
889 expr->u.entity.name = tac_strdup(sym_buf);
891 expr->u.entity.entity = NULL; /* not known yet */
896 expr = parse_expr_node(0 /* single_item */);
901 report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
902 free_expr(expr_root);
905 succ_exprp = &expr->next;
909 parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
911 free_expr(expr_root);
915 if (single_item) /* used by 'not' operator with high precedence */
922 if (expr_root->type == (sym_code==S_and ? S_or : S_and)) {
923 parse_error("ambiguous use of 'and' together with 'or', parentheses required on line %d",
925 free_expr(expr_root);
928 if (expr_root->type != sym_code) {
929 expr = (struct expr *) tac_malloc(sizeof(struct expr));
930 expr->line = sym_line;
932 expr->type = sym_code;
933 expr->u.and_or.child_first = expr_root;
944 static struct expr *parse_when_decl TAC_ARGS((void));
950 if (!algorithm_recursive) {
951 parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
956 return (parse_expr_node(0 /* single_item */));
959 static void when_expr_root_init TAC_ARGS((void));
962 when_expr_root_init()
964 free_expr(when_expr_root);
965 when_expr_root = new_expr(S_and);
968 static int push_parsed_when_decl TAC_ARGS((void));
971 push_parsed_when_decl()
973 struct expr *parsed_expr;
975 parsed_expr = parse_when_decl();
978 if (!WHEN_EXPR_ROOT_SANE()) {
979 report(LOG_ERR, "INTERNAL: when_expr_root not valid during push_parsed_when_decl()!");
980 free_expr(parsed_expr);
983 if (parsed_expr->next) {
984 report(LOG_ERR, "INTERNAL: Illegal filled next field of parsed expr");
985 free_expr(parsed_expr);
988 parsed_expr->next = when_expr_root->u.and_or.child_first;
989 when_expr_root->u.and_or.child_first = parsed_expr;
990 when_expr_root->line = parsed_expr->line;
994 static int pop_when_decl TAC_ARGS((void));
999 struct expr *first_expr;
1001 if (!WHEN_EXPR_ROOT_SANE()) {
1002 report(LOG_ERR, "INTERNAL: when_expr_root not valid during pop_when_decl()!");
1005 first_expr = when_expr_root->u.and_or.child_first;
1007 report(LOG_ERR, "No expr in stack and pop_when_decl() called");
1010 when_expr_root->u.and_or.child_first = first_expr->next;
1011 first_expr->next = NULL;
1012 free_expr(first_expr);
1016 static struct expr *copy_current_when_decl TAC_ARGS((void));
1018 static struct expr *
1019 copy_current_when_decl()
1021 return (dupl_expr(when_expr_root));
1024 static struct expr *when_expr_dungeon;
1026 static void starve_when_decl TAC_ARGS((void));
1031 if (!WHEN_EXPR_ROOT_SANE()) {
1032 report(LOG_WARNING, "INTERNAL: when_expr_root not sane during starve_when_decl!");
1034 when_expr_root->next = when_expr_dungeon;
1035 when_expr_dungeon = when_expr_root;
1036 when_expr_root = NULL;
1037 when_expr_root_init();
1040 static int feed_when_decl TAC_ARGS((void));
1045 if (!when_expr_dungeon) {
1046 report(LOG_ERR, "INTERNAL: No expr in dungeon and feed_when_decl() called");
1049 if (!WHEN_EXPR_ROOT_EMPTY()) {
1050 report(LOG_WARNING, "INTERNAL: Some 'when' expression found still pushed in dungeon during feed_when_decl()!");
1052 free_expr(when_expr_root);
1053 when_expr_root = when_expr_dungeon;
1054 when_expr_dungeon = when_expr_dungeon->next;
1055 when_expr_root->next = NULL;
1059 ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
1062 entity_lookup(type, name)
1066 return (hash_lookup(entity_type_to_hashtable(type), name));
1069 static int enlist_entity_connect TAC_ARGS((void));
1072 enlist_entity_connect()
1074 struct enlist_entity_item *item;
1075 ENTITY *parent_entity, *child_entity;
1077 while ((item=enlist_entity_list)) {
1079 parent_entity = entity_lookup(item->parent_type, item->parent);
1080 if (!parent_entity) {
1081 parse_error("Entity %s %s not defined, referenced as parent on line %d",
1082 entity_type_to_string(item->parent_type), item->parent, item->line);
1085 child_entity = entity_lookup(item-> child_type, item-> child);
1086 if (!child_entity) {
1087 child_entity = new_entity(item->child_type, item->child, item->line);
1089 return (1); /* 'hash_add_entry()' conflict */
1090 item->child = NULL; /* don't free string ref'ed from 'child_entity'! */
1093 if (!enlist_entity_direct(parent_entity, child_entity, item->when))
1094 return (1); /* entities not found */
1096 enlist_entity_list = item->next;
1098 free_enlist_entity_item(item);
1101 enlist_entity_list_tailp = &enlist_entity_list;
1105 static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
1108 enlist_entity(parent_type, parent, child_type, child)
1114 struct enlist_entity_item *item =
1115 (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
1118 *enlist_entity_list_tailp = item;
1119 enlist_entity_list_tailp = &item->next;
1121 item->parent_type = parent_type;
1122 item->parent = tac_strdup(parent);
1123 item-> child_type = child_type;
1124 item->child = tac_strdup(child);
1125 item->when = copy_current_when_decl();
1126 item->line = sym_line;
1129 static int parse_entity_spec TAC_ARGS((void));
1131 /* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
1137 if (sym_code != S_user
1138 && sym_code != S_host
1139 && sym_code != S_group
1141 parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
1152 static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
1155 parse_conditional_block_item(entity)
1162 /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
1165 parse_error("Unrecognised keyword %s for entity on line %d",
1172 enlist_entity(S_group, sym_buf, entity->type, entity->name);
1177 int parsed_entity_type;
1179 if (entity->type != S_group) {
1180 parse_error("'enlist' keyword allowed only in 'group' section on line %d",
1186 parsed_entity_type = parse_entity_spec();
1187 if (!parsed_entity_type)
1189 enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
1199 * Already parsed some services/commands. Thanks to Gabor Kiss
1200 * who found this bug.
1203 for (p=entity->svcs; p->next; p=p->next)
1205 p->next = parse_svcs();
1207 entity->svcs = parse_svcs();
1212 if (parse_conditional_block(entity))
1220 static int parse_conditional_block TAC_ARGS((ENTITY *entity));
1223 parse_conditional_block(entity)
1226 int retval = -1 /* GCC paranoia */;
1228 if (push_parsed_when_decl())
1233 if (sym_code == S_closebra) {
1235 retval = 0; /* success */
1239 if (parse_conditional_block_item(entity)) {
1240 retval = 1; /* failure */
1245 if (pop_when_decl())
1251 /* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
1253 ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
1256 new_entity(type, name, line)
1261 ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
1262 ENTITY *hash_conflict;
1264 bzero(entity, sizeof(ENTITY));
1265 tac_list_init(&entity->to_parent_membership_list);
1266 tac_list_init(&entity->to_child_membership_list );
1267 entity->to_child_membership_num = 0;
1268 scan_init_entity(entity);
1270 entity->type = type;
1271 entity->name = name;
1272 entity->line = line;
1274 hash_conflict = hash_add_entry(entity_type_to_hashtable(type), (void *) entity);
1275 if (hash_conflict) {
1276 parse_error("multiply defined %s %s on lines %d and %d",
1277 entity_type_to_string(type),
1278 entity->name, hash_conflict->line, sym_line);
1286 static int parse_entity TAC_ARGS((int entity_type));
1289 parse_entity(entity_type)
1294 char **fieldp = NULL /* GCC paranoia */;
1295 char buf[MAX_INPUT_LINE_LEN];
1300 entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
1302 return (1); /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
1307 /* Is the default deny for svcs or cmds to be overridden? */
1308 entity->svc_dflt = parse_opt_svc_default();
1311 if (entity_type != S_user)
1314 ASSIGN(entity->key);
1324 ASSIGN(entity->time);
1330 parse(S_authorization);
1331 if (entity->before_author)
1332 free(entity->before_author);
1333 entity->before_author = tac_strdup(sym_buf);
1339 parse(S_authorization);
1340 if (entity->after_author)
1341 free(entity->after_author);
1342 entity->after_author = tac_strdup(sym_buf);
1347 if (entity->login) {
1348 parse_error("Duplicate value for %s %s and %s on line %d",
1349 codestring(sym_code), entity->login,
1358 entity->login = tac_strdup(sym_buf);
1362 /* set to dummy string, so that we detect a duplicate
1363 * password definition attempt
1365 entity->login = tac_strdup(nopasswd_str);
1366 entity->nopasswd = 1;
1374 #endif /* USE_PAM */
1378 sprintf(buf, "%s ", sym_buf);
1380 strcat(buf, sym_buf);
1381 entity->login = tac_strdup(buf);
1387 "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1391 "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1393 #endif /* USE_PAM */
1400 parse_error("Duplicate value for %s %s and %s on line %d",
1401 codestring(sym_code), entity->pap,
1414 sprintf(buf, "%s ", sym_buf);
1416 strcat(buf, sym_buf);
1417 entity->pap = tac_strdup(buf);
1420 sprintf(buf, "%s ", sym_buf);
1421 entity->pap = tac_strdup(buf);
1427 "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d",
1431 "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
1439 ASSIGN(entity->full_name);
1444 ASSIGN(entity->expires);
1449 ASSIGN(entity->msg);
1460 save_sym = sym_code;
1463 sprintf(buf, "%s ", sym_buf);
1465 strcat(buf, sym_buf);
1469 fieldp = &entity->arap;
1472 fieldp = &entity->chap;
1476 fieldp = &entity->mschap;
1480 fieldp = &entity->pap;
1483 fieldp = &entity->opap;
1486 fieldp = &entity->global;
1489 report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
1495 parse_error("Duplicate value for %s %s and %s on line %d",
1496 codestring(save_sym), *fieldp, sym_buf, sym_line);
1499 *fieldp = tac_strdup(buf);
1511 if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
1512 parse_error("expecting integer, found '%s' on line %d",
1517 #endif /* MAXSESS */
1520 if (STREQ(sym_buf, "password")) {
1522 "\npassword = <string> is obsolete. Use login = des <string>\n");
1525 if (parse_conditional_block_item(entity))
1526 return (0); /* error message already printed */
1531 static NODE *parse_svcs TAC_ARGS((void));
1546 result = (NODE *) tac_malloc(sizeof(NODE));
1548 bzero(result, sizeof(NODE));
1549 result->line = sym_line;
1551 /* cmd declaration */
1552 if (sym_code == S_cmd) {
1555 result->value = tac_strdup(sym_buf);
1560 result->value1 = parse_cmd_matches();
1562 if (feed_when_decl())
1563 tac_exit(1); /* no error return possibility */
1565 result->type = N_svc_cmd;
1566 result->when = copy_current_when_decl();
1567 expr_sink_register(result->when);
1569 result->next = parse_svcs();
1573 /* svc declaration */
1578 parse_error("expecting service type but found %s on line %d",
1583 result->type = N_svc;
1584 /* should perhaps check that this is an allowable service name */
1585 result->value1 = tac_strdup(sym_buf);
1588 result->type = N_svc_exec;
1591 result->type = N_svc_arap;
1594 result->type = N_svc_slip;
1597 result->type = N_svc_ppp;
1601 /* Should perhaps check that this is a known PPP protocol name */
1602 result->value1 = tac_strdup(sym_buf);
1610 result->dflt = parse_opt_attr_default();
1611 result->value = parse_attrs();
1616 result->when = copy_current_when_decl();
1617 expr_sink_register(result->when);
1619 result->next = parse_svcs();
1623 /* <cmd_match> := <permission> <string> */
1625 static NODE *parse_cmd_matches TAC_ARGS((void));
1630 NODE *retval = NULL, **succp = &retval;
1639 if (push_parsed_when_decl())
1640 tac_exit(1); /* no error return possibility */
1642 result = parse_cmd_matches();
1644 if (pop_when_decl())
1645 tac_exit(1); /* no error return possibility */
1651 result = (NODE *) tac_malloc(sizeof(NODE));
1653 bzero(result, sizeof(NODE));
1654 result->line = sym_line;
1656 result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
1657 result->value = tac_strdup(sym_buf);
1659 #ifdef WITH_INCLUDED_REGEX
1661 result->value1 = (void *) tac_regcomp(result->value);
1663 #else /* WITH_INCLUDED_REGEX */
1665 result->value1 = tac_malloc(sizeof(regex_t));
1666 if (regcomp(result->value1, result->value /* regex */, REG_NOSUB /* cflags */)) {
1667 free(result->value1);
1668 result->value1 = NULL;
1671 #endif /* WITH_INCLUDED_REGEX */
1673 if (!result->value1) {
1674 report(LOG_ERR, "in regular expression %s on line %d",
1680 result->when = copy_current_when_decl();
1681 expr_sink_register(result->when);
1683 result->next = NULL;
1686 while (result->next)
1687 result = result->next; /* skip parsed chain from parse_cmd_matches() */
1688 succp = &result->next;
1693 static NODE *parse_attrs TAC_ARGS((void));
1698 NODE *retval = NULL, **succp = &retval;
1700 char buf[MAX_INPUT_LINE_LEN];
1711 if (push_parsed_when_decl())
1712 tac_exit(1); /* no error return possibility */
1714 result = parse_attrs();
1716 if (pop_when_decl())
1717 tac_exit(1); /* no error return possibility */
1725 result = (NODE *) tac_malloc(sizeof(NODE));
1727 bzero(result, sizeof(NODE));
1728 result->line = sym_line;
1730 result->type = optional ? N_optarg : N_arg;
1732 strcpy(buf, sym_buf);
1734 strcat(buf, sym_buf);
1736 strcat(buf, sym_buf);
1739 result->value = tac_strdup(buf);
1741 result->when = copy_current_when_decl();
1742 expr_sink_register(result->when);
1744 result->next = NULL;
1747 while (result->next)
1748 result = result->next; /* skip parsed chain from parse_attrs() */
1749 succp = &result->next;
1755 static void sym_get TAC_ARGS((void));
1762 if (debug & DEBUG_PARSE_FLAG) {
1763 report(LOG_DEBUG, "line=%d sym=%s code=%d buf='%s'",
1764 sym_line, codestring(sym_code), sym_code, sym_buf);
1768 static char *sym_buf_add TAC_ARGS((int c));
1772 int c; /* promoted "char" type */
1774 if (sym_pos >= MAX_INPUT_LINE_LEN) {
1775 sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
1776 if (debug & DEBUG_PARSE_FLAG) {
1777 report(LOG_DEBUG, "line too long: line=%d sym=%s code=%d buf='%s'",
1778 sym_line, codestring(sym_code), sym_code, sym_buf);
1783 sym_buf[sym_pos++] = c;
1787 static void getsym TAC_ARGS((void));
1807 while (sym_ch == ' ' || sym_ch == '\t')
1812 strcpy(sym_buf, "=");
1813 sym_code = S_separator;
1818 strcpy(sym_buf, "{");
1819 sym_code = S_openbra;
1824 strcpy(sym_buf, "}");
1825 sym_code = S_closebra;
1830 strcpy(sym_buf, "(");
1831 sym_code = S_openparen;
1836 strcpy(sym_buf, ")");
1837 sym_code = S_closeparen;
1842 while ((sym_ch != '\n') && (sym_ch != EOF))
1851 if (sym_ch == '"') {
1855 /* backslash-double-quote is supported inside strings */
1857 if (sym_ch == '\\') {
1861 /* preserve the slash for \n */
1862 if (!sym_buf_add('\\')) {
1863 sym_code = S_unknown;
1870 if (!sym_buf_add(sym_ch)) {
1871 sym_code = S_unknown;
1878 sym_code = S_unknown;
1883 if (!sym_buf_add(sym_ch)) {
1884 sym_code = S_unknown;
1892 if (!sym_buf_add('\0')) {
1893 sym_code = S_unknown;
1897 sym_code = S_string;
1902 while (sym_ch != '\t' && sym_ch != ' ' && sym_ch != '='
1903 && sym_ch != '\n') {
1905 if (!sym_buf_add(sym_ch)) {
1906 sym_code = S_unknown;
1913 if (!sym_buf_add('\0')) {
1914 sym_code = S_unknown;
1918 sym_code = keycode(sym_buf);
1919 if (sym_code == S_unknown)
1920 sym_code = S_string;
1925 static void rch TAC_ARGS((void));
1936 if (parse_only && sym_ch != EOF)
1937 fprintf(stderr, "%c", sym_ch);
1941 static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
1943 /* Find the value of a field. Does not recurse. */
1945 get_value(entity, field)
1951 v.pval = NULL; /* do both just for sure... */
1955 parse_error("get_value: illegal entity");
1961 v.pval = entity->name;
1965 v.pval = entity->login;
1969 v.pval = entity->global;
1973 v.pval = entity->expires;
1977 v.pval = entity->arap;
1981 v.pval = entity->chap;
1986 v.pval = entity->mschap;
1991 v.pval = entity->pap;
1995 v.pval = entity->opap;
1999 v.pval = entity->msg;
2003 v.pval = entity->svcs;
2007 v.pval = entity->before_author;
2011 v.pval = entity->after_author;
2015 v.intval = entity->svc_dflt;
2020 v.intval = entity->maxsess;
2025 v.intval = entity->nopasswd;
2029 v.pval = entity->time;
2033 if (entity->type == S_user) {
2034 report(LOG_ERR, "get_value: S_key field not supported in %s %s",
2035 entity_type_to_string(entity->type), entity->name);
2039 v.pval = entity->key;
2043 report(LOG_ERR, "get_value: unknown field %d", field);
2050 /* Internal graph scanning routines */
2052 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));
2054 static enum value_scan_func_result
2055 value_scan(type, name, recurse, func, func_data)
2059 value_scan_func_t func;
2064 if (debug & DEBUG_CONFIG_FLAG)
2065 report(LOG_DEBUG, "value_scan: find %s %s, recurse=%d",
2066 entity_type_to_string(type), name, recurse);
2068 entity = entity_lookup(type, name);
2070 if (debug & DEBUG_CONFIG_FLAG)
2071 report(LOG_DEBUG, "value_scan: no %s named %s",
2072 entity_type_to_string(type), name);
2073 return (VSFR_CONTINUE);
2076 return (value_scan_entity(entity, recurse, func, func_data));
2079 /* For each user, check she doesn't circularly reference a
2080 group. Return 1 if it does */
2082 static int circularity_check_failed;
2084 static void circularity_check_fail TAC_ARGS((struct membership *membership));
2087 circularity_check_fail(membership)
2088 struct membership *membership;
2092 circularity_check_failed = 1;
2094 report(LOG_ERR, "recursively defined groups:");
2095 while (membership) {
2096 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);
2097 report(LOG_ERR, "%s %s",
2098 entity_type_to_string(entity->type), entity->name);
2099 membership = value_scan_backward(entity);
2103 static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
2105 static enum value_scan_func_result
2106 circularity_check_func(entity, func_data /* unused */)
2110 /* only useful to speedup case of failure */
2111 if (circularity_check_failed)
2112 return (VSFR_FOUND);
2114 return (VSFR_CONTINUE);
2117 static int circularity_check TAC_ARGS((void));
2123 ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
2127 for (users = users_base; *users; users++) {
2130 if (debug & DEBUG_PARSE_FLAG)
2131 report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
2133 circularity_check_failed = 0;
2134 value_scan_forward_seen_hook = circularity_check_fail;
2135 value_scan_entity(entity, TAC_PLUS_RECURSE,
2136 (value_scan_func_t) circularity_check_func, NULL /* func_data-unused */);
2137 value_scan_forward_seen_hook = NULL;
2138 if (circularity_check_failed)
2142 return (circularity_check_failed);
2146 /* Return a value for a group or user (isuser says if
2147 this name is a group or a user name).
2149 If no value exists, and recurse is true, also check groups we are a
2150 member of, recursively.
2152 Returns void * because it can return a string or a node pointer
2153 (should really return a union pointer).
2156 static VALUE cfg_get_value_VALUE; /* private */
2158 static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
2160 static enum value_scan_func_result
2161 cfg_get_value_func(entity,attrp /* func_data */)
2165 /* found the entry. Lookup value from attr=value */
2166 cfg_get_value_VALUE = get_value(entity, *attrp);
2167 if (cfg_get_value_VALUE.pval)
2168 return (VSFR_FOUND);
2170 return (VSFR_CONTINUE);
2173 static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
2176 cfg_get_value(type, name, attr, recurse)
2181 if (debug & DEBUG_CONFIG_FLAG)
2182 report(LOG_DEBUG, "cfg_get_value: type=%s name=%s attr=%s recurse=%d",
2183 entity_type_to_string(type), name, codestring(attr), recurse);
2185 cfg_get_value_VALUE.pval = NULL;
2186 value_scan(type, name, recurse,
2187 (value_scan_func_t) cfg_get_value_func, &attr /* func_data */);
2188 return (cfg_get_value_VALUE);
2192 /* Wrappers for cfg_get_value:
2195 int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2198 cfg_get_intvalue(type, name, attr, recurse)
2203 int val = cfg_get_value(type, name, attr, recurse).intval;
2205 if (debug & DEBUG_CONFIG_FLAG)
2206 report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
2210 const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2213 cfg_get_pvalue(type, name, attr, recurse)
2218 char *p = cfg_get_value(type, name, attr, recurse).pval;
2220 if (debug & DEBUG_CONFIG_FLAG)
2221 report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
2226 /* Read the config file and do some basic sanity checking on
2227 * it. Return 1 if we find any errors.
2229 int cfg_read_config TAC_ARGS((const char *cfile));
2232 cfg_read_config(cfile)
2237 if ((cf = fopen(cfile, "r")) == NULL) {
2238 report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting",
2239 cfile, sys_errlist[errno]);
2242 if (parse_decls() || sym_error) {
2248 || enlist_entity_connect()
2249 || expr_sink_commit()
2250 /* circularity is allowed in the new fully-recursive algorithm */
2251 || (!algorithm_recursive && circularity_check())
2256 if (!WHEN_EXPR_ROOT_EMPTY() || when_expr_dungeon) {
2257 report(LOG_ERR, "Some 'when' expression found still pushed on stack");
2266 /* return 1 if user exists, 0 otherwise
2268 int cfg_user_exists TAC_ARGS((const char *username));
2271 cfg_user_exists(username)
2272 const char *username;
2274 return (NULL != hash_lookup(usertable, username));
2277 /* return expiry string of user. If none, try groups she is a member
2278 * on, and so on, recursively if recurse is non-zero
2280 const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
2283 cfg_get_expires(username, recurse)
2284 const char *username;
2287 return (cfg_get_pvalue(S_user, username, S_expires, recurse));
2290 /* return time string of user. If none, try groups she is a member
2291 * on, and so on, recursively if recurse is non-zero
2293 const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
2296 cfg_get_timestamp(username, recurse)
2297 const char *username;
2300 return (cfg_get_pvalue(S_user, username, S_time, recurse));
2303 /* return password string of user. If none, try groups she is a member
2304 * on, and so on, recursively if recurse is non-zero
2306 const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
2309 cfg_get_login_secret(user, recurse)
2313 return (cfg_get_pvalue(S_user, user, S_login, recurse));
2316 /* return value of the nopasswd field. If none, try groups she is a member
2317 * on, and so on, recursively if recurse is non-zero
2319 int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
2322 cfg_get_user_nopasswd(user, recurse)
2326 return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
2329 /* return user's secret. If none, try groups she is a member
2330 * on, and so on, recursively if recurse is non-zero
2332 const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
2335 cfg_get_arap_secret(user, recurse)
2339 return (cfg_get_pvalue(S_user, user, S_arap, recurse));
2342 const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
2345 cfg_get_chap_secret(user, recurse)
2349 return (cfg_get_pvalue(S_user, user, S_chap, recurse));
2354 const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
2357 cfg_get_mschap_secret(user, recurse)
2361 return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
2366 const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
2369 cfg_get_pap_secret(user, recurse)
2373 return (cfg_get_pvalue(S_user, user, S_pap, recurse));
2376 const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
2379 cfg_get_opap_secret(user, recurse)
2383 return (cfg_get_pvalue(S_user, user, S_opap, recurse));
2386 /* return the global password for the user (or the group, etc.) */
2388 const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
2391 cfg_get_global_secret(user, recurse)
2395 return (cfg_get_pvalue(S_user, user, S_global, recurse));
2400 /* Return a pointer to a node representing a PAM Service name */
2402 const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
2405 cfg_get_pam_service(user, recurse)
2409 const char *cfg_passwd;
2412 cfg_passwd = cfg_get_pap_secret(user, recurse);
2415 cfg_passwd = cfg_get_global_secret(user, recurse);
2417 if (!cfg_passwd && !cfg_user_exists(user)) {
2418 cfg_passwd = cfg_get_authen_default();
2419 switch (cfg_get_authen_default_method()) {
2422 if (debug & DEBUG_AUTHOR_FLAG)
2423 report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
2428 if (debug & DEBUG_AUTHOR_FLAG)
2429 report(LOG_DEBUG, "I havent find any PAM Service!!");
2430 return(NULL);/* Haven't any PAM Service!! */
2434 p = tac_find_substring("pam ", cfg_passwd);
2436 if(p) { /* We find PAM services */
2437 if (debug & DEBUG_AUTHOR_FLAG)
2438 report(LOG_DEBUG, "I get PAM sevice:%s",p);
2442 if (debug & DEBUG_AUTHOR_FLAG)
2443 report(LOG_DEBUG, "No any PAM Sevice");
2448 #endif /* For PAM */
2451 /* Return a pointer to a node representing a given service
2452 authorization, taking care of recursion issues correctly. Protocol
2453 is only read if the svctype is N_svc_ppp. svcname is only read if type
2457 struct cfg_get_svc_node_param {
2459 const char *protocol, *svcname;
2464 static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
2466 static enum value_scan_func_result
2467 cfg_get_svc_node_func(entity, param /* func_data */)
2469 struct cfg_get_svc_node_param *param;
2472 enum eval_result svc_default;
2474 for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2475 if (svc->type != param->svctype)
2477 if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
2479 if (param->svctype == N_svc && param->svcname && !STREQ(svc->value1, param->svcname ))
2481 if (expr_eval(svc->when) != ER_TRUE) /* expensive */
2484 if (debug & DEBUG_CONFIG_FLAG)
2486 "cfg_get_svc_node: found %s proto=%s svcname=%s",
2487 cfg_nodestring(param->svctype),
2488 param->protocol ? param->protocol : "",
2489 param->svcname ? param->svcname : "");
2493 return (VSFR_FOUND);
2496 /* look at 'default service' settings */
2497 svc_default = entity_svc_default(entity);
2498 switch (svc_default) {
2502 if (debug & DEBUG_AUTHOR_FLAG)
2504 "cfg_get_svc_node: svc=%s protocol=%s svcname=%s forced %s by default service",
2505 cfg_nodestring(param->svctype),
2506 param->protocol ? param->protocol : "",
2507 param->svcname ? param->svcname : "",
2508 (svc_default == ER_TRUE ? "permit" : "deny"));
2510 param->retval = (svc_default == ER_TRUE);
2511 return (VSFR_FOUND);
2513 default: /* shouldn't happen */
2515 return (VSFR_CONTINUE);
2520 int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
2523 cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
2524 const char *username;
2526 const char *protocol;
2527 const char *svcname;
2531 struct cfg_get_svc_node_param param;
2532 enum value_scan_func_result vsfr;
2534 param.svctype = svctype;
2535 param.protocol = protocol;
2536 param.svcname = svcname;
2540 if (debug & DEBUG_CONFIG_FLAG)
2542 "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
2544 cfg_nodestring(svctype),
2545 protocol ? protocol : "",
2546 svcname ? svcname : "",
2549 vsfr = value_scan(S_user, username, recurse,
2550 (value_scan_func_t) cfg_get_svc_node_func, ¶m /* func_data */);
2552 *nodep = param.node;
2554 if (vsfr == VSFR_FOUND)
2555 return (param.retval);
2557 /* The service does not exist. Do the default */
2558 return (cfg_no_user_permitted() ? 1 : 0);
2561 /* Return a pointer to the node representing a set of command tac_regexp
2562 matches for a user and command, handling recursion issues correctly */
2564 struct cfg_authorize_cmd_param {
2567 enum eval_result result;
2570 static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
2572 static enum value_scan_func_result
2573 cfg_authorize_cmd_func(entity, param /* func_data */)
2575 struct cfg_authorize_cmd_param *param;
2579 for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2582 if (svc->type != N_svc_cmd)
2584 if (!STREQ(svc->value, param->cmd))
2586 if (expr_eval(svc->when) != ER_TRUE) /* expensive */
2589 if (debug & DEBUG_CONFIG_FLAG)
2590 report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
2591 param->cmd, cfg_nodestring(svc->type));
2593 /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
2595 for (node = svc->value1; node; node = node->next) {
2598 if (expr_eval(node->when) != ER_TRUE) /* expensive */
2601 #ifdef WITH_INCLUDED_REGEX
2603 match = tac_regexec((tac_regexp *) node->value1, param->args);
2605 #else /* WITH_INCLUDED_REGEX */
2607 match = !regexec((const regex_t *) node->value1, param->args /* string */,
2608 0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
2610 #endif /* WITH_INCLUDED_REGEX */
2612 if (debug & DEBUG_AUTHOR_FLAG) {
2613 report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
2614 node->line, param->cmd,
2615 node->type == N_permit ? "permit" : "deny",
2616 (const char *) node->value, param->args, (match ? "" : "no "));
2622 switch (node->type) {
2624 if (debug & DEBUG_AUTHOR_FLAG) {
2625 report(LOG_DEBUG, "%s %s permitted by line %d",
2626 param->cmd, param->args, node->line);
2628 param->result = ER_TRUE;
2629 return (VSFR_FOUND);
2632 if (debug & DEBUG_AUTHOR_FLAG) {
2633 report(LOG_DEBUG, "%s %s denied by line %d",
2634 param->cmd, param->args, node->line);
2636 param->result = ER_FALSE;
2637 return (VSFR_FOUND);
2640 report(LOG_ERR, "INTERNAL: illegal configuration node: %s: %s %s",
2641 session.peer, param->cmd, param->args);
2642 param->result = ER_UNKNOWN; /* error */
2643 return (VSFR_FOUND);
2646 if (!algorithm_recursive) { /* compatibility mode: */
2647 if (debug & DEBUG_AUTHOR_FLAG)
2648 report(LOG_DEBUG, "cmd %s exists, but no args match, denied (as no 'authorization = recursive' found)",
2650 param->result = ER_FALSE; /* emulate last "deny .*" */
2651 return (VSFR_FOUND);
2655 /* look at 'default service' settings */
2656 param->result = entity_svc_default(entity);
2657 switch (param->result) {
2660 if (debug & DEBUG_AUTHOR_FLAG)
2661 report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
2662 return (VSFR_FOUND);
2666 if (debug & DEBUG_AUTHOR_FLAG)
2667 report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
2668 return (VSFR_FOUND);
2670 default: /* shouldn't happen */
2672 return (VSFR_CONTINUE);
2677 enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
2680 cfg_authorize_cmd(username, cmd, args)
2681 const char *username;
2685 struct cfg_authorize_cmd_param param;
2689 param.result = ER_UNKNOWN; /* error */
2691 if (debug & DEBUG_CONFIG_FLAG)
2692 report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
2693 username, cmd, args);
2695 value_scan(S_user, username, TAC_PLUS_RECURSE,
2696 (value_scan_func_t) cfg_authorize_cmd_func, ¶m /* func_data */);
2698 if (param.result != ER_UNKNOWN)
2699 return (param.result);
2701 /* The command does not exist. Do the default */
2702 return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
2705 /* Return an array of character strings representing configured AV
2706 * pairs, given a username and a service node.
2708 * In the AV strings returned, manipulate the separator character to
2709 * indicate which args are optional and which are mandatory.
2711 * Lastly, indicate what default permission was configured by setting
2714 char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
2717 cfg_get_svc_attrs(svcnode, denyp)
2730 *denyp = (svcnode->dflt == S_deny);
2733 for (node = svcnode->value; node; node = node->next)
2736 args = (char **) tac_malloc(sizeof(char *) * (i + 1));
2739 for (node = svcnode->value; node; node = node->next) {
2743 if (expr_eval(node->when) != ER_TRUE) /* expensive */
2744 continue; /* ignore this node */
2746 arg = tac_strdup(node->value);
2747 p = index(arg, '=');
2748 if (p && node->type == N_optarg)
2757 static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
2759 static enum eval_result
2760 entity_svc_default(entity)
2763 switch (entity->svc_dflt) {
2769 case 0: /* not specified */
2770 return (ER_UNKNOWN);
2772 report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
2773 return (ER_UNKNOWN);
2777 int cfg_no_user_permitted TAC_ARGS((void));
2780 cfg_no_user_permitted()
2782 if (no_user_dflt == S_permit)
2788 const char *cfg_get_authen_default TAC_ARGS((void));
2791 cfg_get_authen_default()
2793 return (authen_default);
2796 int cfg_get_authen_default_method TAC_ARGS((void));
2798 /* For describe authentication method(pam,file,db..etc) */
2800 cfg_get_authen_default_method()
2802 return (authen_default_method);
2806 /* Host entity management:
2809 const char *cfg_get_host_key TAC_ARGS((const char *host));
2811 /* For getting host key */
2813 cfg_get_host_key(host)
2816 return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
2819 static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
2822 force_belong_entity(type, name)
2826 ENTITY *entity = entity_lookup(type, name);
2829 eval_force_belong_entity(entity);
2834 /* assumed existing initialized "session.peer*" */
2836 static ENTITY *request_peer_addr;
2837 static ENTITY *request_peer;
2838 static ENTITY *request_DEFAULT_group;
2840 static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
2843 enlist_request_peer(hostname, entityp)
2844 const char *hostname;
2851 *entityp = force_belong_entity(S_host, hostname);
2852 if (*entityp && request_DEFAULT_group)
2853 virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, *entityp /* child */);
2856 /* Try to build the following scenery:
2858 * host <session.peer_addr> [=ER_TRUE]
2860 * +-- group <DEFAULT_GROUPNAME>
2862 * host <session.peer > [=ER_TRUE]
2864 * +-- group <DEFAULT_GROUPNAME>
2867 void cfg_request_scan_begin TAC_ARGS((void));
2870 cfg_request_scan_begin()
2872 request_scan_begin();
2874 request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2876 if (session.peer_addr != session.peer)
2877 enlist_request_peer(session.peer_addr, &request_peer_addr);
2878 enlist_request_peer(session.peer, &request_peer);
2881 /* Try to build the following scenery:
2883 * ( user <identity->username> | user <DEFAULT_USERNAME> ) [=ER_TRUE]
2885 * +-- host <session.peer_addr> [=ER_TRUE]
2887 * | +- group <DEFAULT_GROUPNAME>
2889 * +-- host <session.peer > [=ER_TRUE]
2891 * | +-- group <DEFAULT_GROUPNAME>
2893 * +-- group <DEFAULT_GROUPNAME>
2896 void cfg_request_identity TAC_ARGS((const struct identity *identity));
2899 cfg_request_identity(identity)
2900 const struct identity *identity;
2902 ENTITY *user_entity,*request_DEFAULT_group;
2904 if (debug & DEBUG_CONFIG_FLAG)
2905 report(LOG_DEBUG, "cfg_request_identity: username=%s, NAS_name=%s, NAS_port=%s, NAC_address=%s, priv_lvl=%d",
2906 identity->username, identity->NAS_name, identity->NAS_port, identity->NAC_address, identity->priv_lvl);
2908 user_entity = force_belong_entity(S_user, identity->username);
2909 request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2912 user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
2914 request_scan_user_known = 1;
2919 if (request_peer_addr)
2920 virtual_enlist_entity_direct(request_peer_addr /* parent */, user_entity /* child */);
2922 virtual_enlist_entity_direct(request_peer /* parent */, user_entity /* child */);
2923 if (request_DEFAULT_group)
2924 virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, user_entity /* child */);