Release bumped to "gts4".
[tac_plus.git] / cfgfile.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
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.
12
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.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #ifndef WITH_INCLUDED_REGEX
29 #ifdef HAVE_REGEX_H
30 #include <regex.h>
31 #endif
32 #endif
33
34 #include "cfgfile.h"
35 #include "report.h"
36 #include "utils.h"
37 #include "hash.h"
38 #include "parse.h"
39 #include "main.h"
40 #include "do_author.h"                  /* for "struct identity" */
41
42 #ifdef WITH_INCLUDED_REGEX
43 #include "tac_regexp.h"
44 #endif
45
46
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));
57
58
59 /*
60    <config>           := <decl>*
61
62    <decl>             := <top_level_decl> | <entity_decl>
63
64    <top_level_decl>   := <authen_default> |
65                          accounting file = <string> |
66                          default authorization = permit |
67                          key = <string> |
68                          authorization = ( first | recursive )
69
70    <authen_default>   := default authentication = file <filename>
71 #if defined(DB)
72                          | db <string>
73 #endif
74
75    <permission>       := permit | deny
76
77    <filename>         := <string>
78
79    <password>         := <string>
80
81    <user_decl>        := user  = <string> {
82                            [ <service_default> ]
83                            <user_attr>*
84                            <svc>*
85                          }
86
87    <host_decl>        := host  = <string> {
88                            [ <service_default> ]
89                            <host_attr>*
90                            <svc>*
91                          }
92
93    <group_decl>       := group = <string> {
94                            [ <service_default> ]
95                            <group_attr>*
96                            <svc>*
97                          }
98
99    <service_default>  := default service = ( permit | deny | default )
100
101    <password_spec>    := file <filename> |
102                          skey |
103                          cleartext <password> |
104                          des <password> |
105
106 #ifdef USE_PAM
107                          pam <pam_service> |
108 #endif
109 #if defined(DB)
110                          db <string>
111 #endif
112                          nopassword
113
114    <user_attr>       :=  name     = <string> |
115                          login    = <password_spec> |
116                          member   = <string> |
117                          expires  = <string> |
118                          arap     = cleartext <string> |
119                          chap     = cleartext <string> |
120 #ifdef MSCHAP
121                          ms-chap  = cleartext <string> |
122 #endif
123                          pap      = cleartext <string> |
124                          pap      = des <string> |
125 #ifdef USE_PAM
126                          pap      = pam <pam_service> |
127 #endif
128                          opap     = cleartext <string> |
129                          global   = cleartext <string> |
130                          msg      = <string>
131                          before authorization = <string> |
132                          after  authorization = <string> |
133                          <when_attr>
134
135    <host_attr>       :=  key      = <string> |
136                          <user_attr>
137
138    <group_attr>      :=  enlist   = <entity_spec> |
139                          key      = <string> |
140                          <user_attr>
141
142    <when_attr>       := member   = <string> |
143                         enlist   = <entity_spec> |
144                         <svc> |
145                         <when_attr_block>
146
147    <when_attr_block> := <when_decl> {
148                           <when_attr>*
149                         }
150
151    <svc>             := <svc_auth> | <cmd_auth>
152
153    <cmd_auth>        := cmd = <string> {
154                           <when_match>*
155                         }
156
157    <when_match>      := <permission> <string> |
158                         <when_match_block>
159
160    <when_match_block> := <when_decl> {
161                            <when_match>*
162                          }
163
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 ]
167                           <when_AV_pair>*
168                         }
169
170    <when_AV_pair>    := [ optional ] <string> = <string> |
171                         <when_AV_pair_block>
172
173    <when_AV_pair_block> := <when_decl> {
174                              <when_AV_pair>*
175                            }
176
177    <when_decl>       := when = <expr>
178
179 # to avoid ambiguous precence by forbid of "or" & "and" without parentheses:
180    <expr>            := <entity_spec> |
181                         not <expr> |
182                         '(' <expr_or>  ')' |
183                         '(' <expr_and> ')'
184
185    <expr_or>         := <expr> |
186                         <expr> or  <expr_or>
187
188    <expr_and>        := <expr> |
189                         <expr> and <expr_and>
190
191    <entity_spec>     := ( user | host | group ) <string>
192 */
193
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";
210
211
212 /* Only the first 2 fields (name and hash) are used by the hash table
213    routines to hashh structures into a table.
214 */
215
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 */
219
220
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") */
225     struct expr *when;
226     int line;
227 };
228 static struct enlist_entity_item * enlist_entity_list;
229 static struct enlist_entity_item **enlist_entity_list_tailp = &enlist_entity_list;
230
231
232 static void parse_error TAC_ARGS((char *fmt,...)) G_GNUC_PRINTF(1, 2);
233
234 #ifdef __STDC__
235
236 #include <stdarg.h>             /* ANSI C, variable length args */
237 static void
238 parse_error(char *fmt,...)
239
240 #else /* __STDC__ */
241
242 #include <varargs.h>            /* has 'vararg' definitions */
243 /* VARARGS2 */
244 static void
245 parse_error(fmt, va_alist)
246 char *fmt;
247 va_dcl                          /* no terminating semi-colon */
248
249 #endif /* __STDC__ */
250 {
251     char msg[256];              /* temporary string */
252     va_list ap;
253
254 #ifdef __STDC__
255     va_start(ap, fmt);
256 #else
257     va_start(ap);
258 #endif
259     vsprintf(msg, fmt, ap);
260     va_end(ap);
261
262     report(LOG_ERR, "%s", msg);
263     fprintf(stderr, "Error: %s\n", msg);
264     tac_exit(1);
265 }
266
267 const char *cfg_nodestring TAC_ARGS((int type));
268
269 const char *
270 cfg_nodestring(type)
271     int type;
272 {
273     switch (type) {
274     default:
275         return ("unknown node type");
276     case N_arg:
277         return ("N_arg");
278     case N_optarg:
279         return ("N_optarg");
280     case N_svc:
281         return ("N_svc");
282     case N_svc_exec:
283         return ("N_svc_exec");
284     case N_svc_slip:
285         return ("N_svc_slip");
286     case N_svc_ppp:
287         return ("N_svc_ppp");
288     case N_svc_arap:
289         return ("N_svc_arap");
290     case N_svc_cmd:
291         return ("N_svc_cmd");
292     case N_permit:
293         return ("N_permit");
294     case N_deny:
295         return ("N_deny");
296     }
297 }
298
299 const char *entity_type_to_string TAC_ARGS((int entity_type));
300
301 const char *
302 entity_type_to_string(entity_type)
303 int entity_type;
304 {
305     switch (entity_type) {
306     case S_user:
307         return ("user");
308     case S_host:
309         return ("host");
310     case S_group:
311         return ("group");
312     }
313     return (NULL);
314 }
315
316 static void **entity_type_to_hashtable TAC_ARGS((int entity_type));
317
318 static void **
319 entity_type_to_hashtable(entity_type)
320 int entity_type;
321 {
322     switch (entity_type) {
323     case S_user:
324         return (usertable);
325     case S_host:
326         return (hosttable);
327     case S_group:
328         return (grouptable);
329     }
330     return (NULL);
331 }
332
333 void scan_invalidate_entities TAC_ARGS((enum invalidate_scan what));
334
335 void
336 scan_invalidate_entities(what)
337 enum invalidate_scan what;
338 {
339     scan_invalidate_entities_hashtable( usertable, what);
340     scan_invalidate_entities_hashtable( hosttable, what);
341     scan_invalidate_entities_hashtable(grouptable, what);
342 }
343
344
345 static void free_attrs TAC_ARGS((NODE *node));
346
347 static void
348 free_attrs(node)
349 NODE *node;
350 {
351     NODE *next;
352
353     while (node) {
354         unlink_expr(node->when);
355         free_expr(node->when);
356         node->when = NULL;
357
358         switch (node->type) {
359         case N_optarg:
360         case N_arg:
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);
365             break;
366         default:
367             report(LOG_ERR, "Illegal node type %s for free_attrs",
368                    cfg_nodestring(node->type));
369             return;
370         }
371
372         free(node->value);
373         next = node->next;
374         free(node);
375         node = next;
376     }
377 }
378
379 static void free_cmd_matches TAC_ARGS((NODE *node));
380
381 static void
382 free_cmd_matches(node)
383 NODE *node;
384 {
385     NODE *next;
386
387     while (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);
392
393         unlink_expr(node->when);
394         free_expr(node->when);
395         node->when = NULL;
396
397         free(node->value);      /* text */
398
399 #ifdef WITH_INCLUDED_REGEX
400
401         free(node->value1);     /* tac_regexp compiled text */
402
403 #else /* WITH_INCLUDED_REGEX */
404
405         regfree((regex_t *) node->value1);      /* POSIX regex compiled text */
406
407 #endif /* WITH_INCLUDED_REGEX */
408
409         next = node->next;
410         free(node);
411         node = next;
412     }
413 }
414
415 static void free_svcs TAC_ARGS((NODE *node));
416
417 static void
418 free_svcs(node)
419 NODE *node;
420 {
421     NODE *next;
422
423     while (node) {
424         unlink_expr(node->when);
425         free_expr(node->when);
426         node->when = NULL;
427
428         switch (node->type) {
429         case N_svc_cmd:
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);
436             next = node->next;
437             free(node);
438             node = next;
439             continue;
440
441         case N_svc:
442         case N_svc_ppp:
443             free(node->value1);
444             /* FALL-THROUGH */
445         case N_svc_exec:
446         case N_svc_arap:
447         case N_svc_slip:
448             if (debug & DEBUG_CLEAN_FLAG)
449                 report(LOG_DEBUG, "free %s", cfg_nodestring(node->type));
450             free_attrs(node->value);
451             next = node->next;
452             free(node);
453             node = next;
454             continue;
455
456         default:
457             report(LOG_ERR, "Illegal node type %d for free_svcs", node->type);
458             return;
459         }
460     }
461 }
462
463 static void free_enlist_entity_item TAC_ARGS((struct enlist_entity_item *item));
464
465 static void
466 free_enlist_entity_item(item)
467 struct enlist_entity_item *item;
468 {
469     free(item->parent);
470     free(item->child);
471     free_expr(item->when);
472 }
473
474
475 static void free_entity TAC_ARGS((ENTITY *entity));
476
477 static void
478 free_entity(entity)
479 ENTITY *entity;
480 {
481     if (debug & DEBUG_CLEAN_FLAG)
482         report(LOG_DEBUG, "free %s %s",
483                 entity_type_to_string(entity->type), entity->name);
484
485     /* function MUST be called while the whole entity is still VALID! */
486     scan_free_entity(entity);
487
488     if (entity->name)
489         free(entity->name);
490     if (entity->full_name)
491         free(entity->full_name);
492     if (entity->login)
493         free(entity->login);
494     if (entity->expires)
495         free(entity->expires);
496     if (entity->time)
497         free(entity->time);
498     if (entity->arap)
499         free(entity->arap);
500     if (entity->chap)
501         free(entity->chap);
502 #ifdef MSCHAP
503     if (entity->mschap)
504         free(entity->mschap);
505 #endif /* MSCHAP */
506     if (entity->pap)
507         free(entity->pap);
508     if (entity->opap)
509         free(entity->opap);
510     if (entity->global)
511         free(entity->global);
512     if (entity->msg)
513         free(entity->msg);
514     if (entity->before_author)
515         free(entity->before_author);
516     if (entity->after_author)
517         free(entity->after_author);
518     if (entity->key)
519         free(entity->key);
520     free_svcs(entity->svcs);
521 }
522
523 static void free_hashtable TAC_ARGS((void **hashtable));
524
525 static void
526 free_hashtable(hashtable)
527 void **hashtable;
528 {
529     int i;
530     ENTITY *entity,**entityp;
531
532     for (i = 0; i < HASH_TAB_SIZE; i++) {
533         entityp = (ENTITY **) (hashtable+i);
534         while ((entity = *entityp)) {
535             *entityp = entity->hash;
536             free_entity(entity);
537             free(entity);
538         }
539     }
540 }
541
542
543 /*
544  * Exported routines
545  */
546
547 void cfg_clean_config TAC_ARGS((void));
548
549 /* Free all allocated structures preparatory to re-reading the config file */
550 void
551 cfg_clean_config()
552 {
553     struct enlist_entity_item *enlist_entity_item;
554
555     if (authen_default) {
556         free(authen_default);
557         authen_default = NULL;
558     }
559
560     if (algorithm_recursive) {
561         algorithm_recursive = 0;
562     }
563
564     if (authen_default_method) {
565         authen_default_method = 0;
566     }
567
568     if (session.key) {
569         free(session.key);
570         session.key = NULL;
571     }
572
573     if (session.acctfile) {
574         free(session.acctfile);
575         session.acctfile = NULL;
576     }
577
578     if (session.db_acct) {
579         free(session.db_acct);
580         session.db_acct = NULL;
581     }
582
583     free_hashtable( usertable);
584     free_hashtable( hosttable);
585     free_hashtable(grouptable);
586
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);
592     }
593     enlist_entity_list_tailp = &enlist_entity_list;
594 }
595
596 static int parse_permission TAC_ARGS((void));
597
598 static int
599 parse_permission()
600 {
601     int symbol = sym_code;
602
603     if (sym_code != S_permit && sym_code != S_deny) {
604         parse_error("expecting permit or deny but found '%s' on line %d",
605                     sym_buf, sym_line);
606         return (0);
607     }
608     sym_get();
609
610     return (symbol);
611 }
612
613 static int parse TAC_ARGS((int symbol));
614
615 static int
616 parse(symbol)
617 int symbol;
618
619 {
620     if (sym_code != symbol) {
621         parse_error("expecting '%s' but found '%s' on line %d",
622                     (symbol == S_string ? "string" : codestring(symbol)),
623                     sym_buf, sym_line);
624         return (1);
625     }
626     sym_get();
627     return (0);
628 }
629
630 static int parse_opt_svc_default TAC_ARGS((void));
631
632 static int
633 parse_opt_svc_default()
634 {
635     int retval;
636
637     if (sym_code != S_default) {
638         return (0);
639     }
640
641     parse(S_default);
642     parse(S_svc);
643     parse(S_separator);
644
645     switch (sym_code) {
646     default:
647         parse_error("expecting 'permit', 'deny' or 'default' but found '%s' on line %d",
648                     sym_buf, sym_line);
649         return (1);
650
651     case S_default:
652         if (!algorithm_recursive) {
653             parse_error("'default service = %s' supported only if set top level 'authorization = recursive', on line %d",
654                         sym_buf, sym_line);
655             return (1);
656         }
657         /* FALLTHRU */
658     case S_permit:
659     case S_deny:
660         retval = sym_code;
661         sym_get();
662         return (retval);
663     }
664 }
665
666 static int parse_opt_attr_default TAC_ARGS((void));
667
668 static int
669 parse_opt_attr_default()
670 {
671     if (sym_code != S_default)
672         return (S_deny);
673
674     parse(S_default);
675     parse(S_attr);
676     parse(S_separator);
677     parse(S_permit);
678     return (S_permit);
679 }
680
681 /*
682    Parse lines in the config file, creating data structures
683    Return 1 on error, otherwise 0 */
684
685 static int parse_decls TAC_ARGS((void));
686
687 static int
688 parse_decls()
689 {
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;
694
695     sym_code = 0;
696     rch();
697
698     bzero(grouptable, sizeof(grouptable));
699     bzero(usertable, sizeof(usertable));
700     bzero(hosttable, sizeof(hosttable));
701
702     sym_get();
703
704     /* Top level of parser */
705     while (1) {
706
707         switch (sym_code) {
708         case S_eof:
709             return (0);
710
711         case S_accounting:
712             sym_get();
713             parse(S_file);
714             parse(S_separator);
715             if (session.acctfile)
716                 free(session.acctfile);
717             session.acctfile = tac_strdup(sym_buf);
718             sym_get();
719             continue;
720
721 #ifdef DB
722         case S_db_accounting:
723             sym_get();
724             parse(S_separator);
725             if (session.db_acct)
726                 free(session.db_acct);
727             session.db_acct = tac_strdup(sym_buf);
728             sym_get();
729             continue;
730 #endif
731
732         case S_default:
733             sym_get();
734             switch (sym_code) {
735             default:
736                 parse_error(
737                 "Expecting default authorization/authentication on lines %d",
738                             sym_line);
739                 return (1);
740
741             case S_authentication:
742                 if (authen_default) {
743                     parse_error(
744                     "Multiply defined authentication default on line %d",
745                                 sym_line);
746                     return (1);
747                 }
748                 parse(S_authentication);
749                 parse(S_separator);
750
751                 switch(sym_code) {
752
753                 case S_file:
754 #ifdef DB
755                 case S_db:
756 #endif
757 #ifdef USE_LDAP
758                 case S_ldap:
759 #endif
760 #ifdef USE_PAM
761                 case S_pam:
762 #endif
763                 authen_default_method = sym_code;
764                 break;
765
766                 default:
767                 parse_error("expecting default_method keyword after 'default authentication = ' on line %d",sym_line);
768                 return (1);
769                 }
770                 sym_get();
771
772                 authen_default = tac_strdup(sym_buf);
773                 sym_get();
774                 continue;
775
776             case S_authorization:
777                 parse(S_authorization);
778                 parse(S_separator);
779                 parse(S_permit);
780                 no_user_dflt = S_permit;
781                 report(LOG_INFO,
782                        "default authorization = permit is now deprecated. Please use user = DEFAULT instead");
783                 continue;
784             }
785
786         case S_authorization:
787             sym_get();
788             parse(S_separator);
789             switch (sym_code) {
790             default:
791                 parse_error("expecting 'first' or 'recursive' but found '%s' on line %d",
792                             sym_buf, sym_line);
793                 return (1);
794
795             case S_first:
796                 parse(S_first);
797                 algorithm_recursive = 0;
798                 continue;
799
800             case S_recursive:
801                 parse(S_recursive);
802                 algorithm_recursive = 1;
803                 continue;
804             }
805
806         case S_key:
807             /* Process a key declaration. */
808             sym_get();
809             parse(S_separator);
810             if (session.key) {
811                 parse_error("multiply defined key on lines %d and %d",
812                             session.keyline, sym_line);
813                 return (1);
814             }
815             session.key = tac_strdup(sym_buf);
816             session.keyline = sym_line;
817             sym_get();
818             continue;
819
820         case S_user:
821         case S_host:
822         case S_group:
823             parse_entity(sym_code);
824             continue;
825
826         default:
827             parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
828             return (1);
829         }
830     }
831 }
832
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 */
836
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); \
841         tac_exit(1); \
842     } \
843     field = tac_strdup(sym_buf);
844
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)
850
851 static struct expr *parse_expr_node TAC_ARGS((int single_item));
852
853 static struct expr *
854 parse_expr_node(single_item)
855 int single_item;
856 {
857     struct expr *expr_root = NULL;
858     struct expr **succ_exprp = &expr_root;
859     struct expr *expr;
860
861     while (1) {
862         switch (sym_code) {
863
864         case S_not:
865             expr = (struct expr *) tac_malloc(sizeof(struct expr));
866             expr->line = sym_line;
867             *succ_exprp = expr;
868             expr->next = NULL;
869             succ_exprp = &expr->next;
870             expr->type = S_not;
871             sym_get();
872             expr->u.not.child = parse_expr_node(1 /* single_item */);
873             if (!expr->u.not.child) {
874                 free_expr(expr_root);
875                 return (NULL);
876             }
877             break;
878
879         case S_user:
880         case S_host:
881         case S_group:
882             expr = (struct expr *) tac_malloc(sizeof(struct expr));
883             expr->line = sym_line;
884             *succ_exprp = expr;
885             expr->next = NULL;
886             succ_exprp = &expr->next;
887             expr->type = sym_code;
888             sym_get();
889             expr->u.entity.name = tac_strdup(sym_buf);
890             sym_get();
891             expr->u.entity.entity = NULL;       /* not known yet */
892             break;
893
894         case S_openparen:
895             sym_get();
896             expr = parse_expr_node(0 /* single_item */);
897             *succ_exprp = expr;
898             parse(S_closeparen);
899
900             if (expr->next) {
901                 report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
902                 free_expr(expr_root);
903                 return (NULL);
904             }
905             succ_exprp = &expr->next;
906             break;
907
908         default:
909             parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
910                     sym_buf, sym_line);
911             free_expr(expr_root);
912             return (NULL);
913         }
914
915         if (single_item)                /* used by 'not' operator with high precedence */
916             return (expr_root);
917
918         switch (sym_code) {
919
920         case S_and:
921         case S_or:
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",
924                         sym_line);
925                 free_expr(expr_root);
926                 return (NULL);
927             }
928             if (expr_root->type != sym_code) {
929                 expr = (struct expr *) tac_malloc(sizeof(struct expr));
930                 expr->line = sym_line;
931                 expr->next = NULL;
932                 expr->type = sym_code;
933                 expr->u.and_or.child_first = expr_root;
934                 expr_root = expr;
935             }
936             sym_get();
937             continue;
938         }
939
940         return(expr_root);
941     }
942 }
943
944 static struct expr *parse_when_decl TAC_ARGS((void));
945
946 static struct expr *
947 parse_when_decl()
948 {
949     parse(S_when);
950     if (!algorithm_recursive) {
951         parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
952                     sym_line);
953         return (NULL);
954     }
955     parse(S_separator);
956     return (parse_expr_node(0 /* single_item */));
957 }
958
959 static void when_expr_root_init TAC_ARGS((void));
960
961 static void
962 when_expr_root_init()
963 {
964     free_expr(when_expr_root);
965     when_expr_root = new_expr(S_and);
966 }
967
968 static int push_parsed_when_decl TAC_ARGS((void));
969
970 static int
971 push_parsed_when_decl()
972 {
973     struct expr *parsed_expr;
974
975     parsed_expr = parse_when_decl();
976     if (!parsed_expr)
977         return (1);
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);
981         return (1);
982     }
983     if (parsed_expr->next) {
984         report(LOG_ERR, "INTERNAL: Illegal filled next field of parsed expr");
985         free_expr(parsed_expr);
986         return (1);
987     }
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;
991     return (0);
992 }
993
994 static int pop_when_decl TAC_ARGS((void));
995
996 static int
997 pop_when_decl()
998 {
999     struct expr *first_expr;
1000
1001     if (!WHEN_EXPR_ROOT_SANE()) {
1002         report(LOG_ERR, "INTERNAL: when_expr_root not valid during pop_when_decl()!");
1003         return (1);
1004     }
1005     first_expr = when_expr_root->u.and_or.child_first;
1006     if (!first_expr) {
1007         report(LOG_ERR, "No expr in stack and pop_when_decl() called");
1008         return (1);
1009     }
1010     when_expr_root->u.and_or.child_first = first_expr->next;
1011     first_expr->next = NULL;
1012     free_expr(first_expr);
1013     return (0);
1014 }
1015
1016 static struct expr *copy_current_when_decl TAC_ARGS((void));
1017
1018 static struct expr *
1019 copy_current_when_decl()
1020 {
1021     return (dupl_expr(when_expr_root));
1022 }
1023
1024 static struct expr *when_expr_dungeon;
1025
1026 static void starve_when_decl TAC_ARGS((void));
1027
1028 static void
1029 starve_when_decl()
1030 {
1031     if (!WHEN_EXPR_ROOT_SANE()) {
1032         report(LOG_WARNING, "INTERNAL: when_expr_root not sane during starve_when_decl!");
1033     }
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();
1038 }
1039
1040 static int feed_when_decl TAC_ARGS((void));
1041
1042 static int
1043 feed_when_decl()
1044 {
1045     if (!when_expr_dungeon) {
1046         report(LOG_ERR, "INTERNAL: No expr in dungeon and feed_when_decl() called");
1047         return (1);
1048     }
1049     if (!WHEN_EXPR_ROOT_EMPTY()) {
1050         report(LOG_WARNING, "INTERNAL: Some 'when' expression found still pushed in dungeon during feed_when_decl()!");
1051     }
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;
1056     return (0);
1057 }
1058
1059 ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
1060
1061 ENTITY *
1062 entity_lookup(type, name)
1063 int type;
1064 const char *name;
1065 {
1066     return (hash_lookup(entity_type_to_hashtable(type), name));
1067 }
1068
1069 static int enlist_entity_connect TAC_ARGS((void));
1070
1071 static int
1072 enlist_entity_connect()
1073 {
1074     struct enlist_entity_item *item;
1075     ENTITY *parent_entity, *child_entity;
1076
1077     while ((item=enlist_entity_list)) {
1078
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);
1083             return (1);
1084         }
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);
1088             if (!child_entity)
1089                 return (1);             /* 'hash_add_entry()' conflict */
1090             item->child = NULL;         /* don't free string ref'ed from 'child_entity'! */
1091         }
1092
1093         if (!enlist_entity_direct(parent_entity, child_entity, item->when))
1094             return (1);         /* entities not found */
1095
1096         enlist_entity_list = item->next;
1097         item->when = NULL;
1098         free_enlist_entity_item(item);
1099         free(item);
1100     }
1101     enlist_entity_list_tailp = &enlist_entity_list;
1102     return (0);
1103 }
1104
1105 static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
1106
1107 static void
1108 enlist_entity(parent_type, parent, child_type, child)
1109 int parent_type;
1110 const char *parent;
1111 int child_type;
1112 const char *child;
1113 {
1114     struct enlist_entity_item *item =
1115                 (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
1116
1117     item->next = NULL;
1118     *enlist_entity_list_tailp = item;
1119     enlist_entity_list_tailp = &item->next;
1120
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;
1127 }
1128
1129 static int parse_entity_spec TAC_ARGS((void));
1130
1131 /* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
1132 static int
1133 parse_entity_spec()
1134 {
1135     int retval;
1136
1137     if (sym_code != S_user
1138      && sym_code != S_host
1139      && sym_code != S_group
1140         ) {
1141         parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
1142                     sym_buf, sym_line);
1143         return (0);
1144     }
1145
1146     retval = sym_code;
1147     sym_get();
1148
1149     return (retval);
1150 }
1151
1152 static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
1153
1154 static int
1155 parse_conditional_block_item(entity)
1156 ENTITY *entity;
1157 {
1158     switch (sym_code) {
1159     case S_eof:
1160         return (1);
1161
1162     /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
1163
1164     default:
1165         parse_error("Unrecognised keyword %s for entity on line %d",
1166                     sym_buf, sym_line);
1167         return (1);
1168
1169     case S_member:
1170         sym_get();
1171         parse(S_separator);
1172         enlist_entity(S_group, sym_buf, entity->type, entity->name);
1173         sym_get();
1174         break;
1175
1176     case S_enlist: {
1177         int parsed_entity_type;
1178
1179         if (entity->type != S_group) {
1180             parse_error("'enlist' keyword allowed only in 'group' section on line %d",
1181                         sym_line);
1182             return (1);
1183         }
1184         sym_get();
1185         parse(S_separator);
1186         parsed_entity_type = parse_entity_spec();
1187         if (!parsed_entity_type)
1188             return (1);
1189         enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
1190         sym_get();
1191         break;
1192         }
1193
1194     case S_svc:
1195     case S_cmd:
1196
1197         if (entity->svcs) {
1198             /*
1199              * Already parsed some services/commands. Thanks to Gabor Kiss
1200              * who found this bug.
1201              */
1202             NODE *p;
1203             for (p=entity->svcs; p->next; p=p->next)
1204                 /* NULL STMT */;
1205             p->next = parse_svcs();
1206         } else {
1207             entity->svcs = parse_svcs();
1208         }
1209         break;
1210
1211     case S_when:
1212         if (parse_conditional_block(entity))
1213             return (1);
1214         break;
1215     }
1216
1217     return (0);
1218 }
1219
1220 static int parse_conditional_block TAC_ARGS((ENTITY *entity));
1221
1222 static int
1223 parse_conditional_block(entity)
1224 ENTITY *entity;
1225 {
1226     int retval = -1 /* GCC paranoia */;
1227
1228     if (push_parsed_when_decl())
1229         return (1);
1230     parse(S_openbra);
1231
1232     while (1) {
1233         if (sym_code == S_closebra) {
1234             sym_get();
1235             retval = 0;         /* success */
1236             break;
1237         }
1238
1239         if (parse_conditional_block_item(entity)) {
1240             retval = 1;         /* failure */
1241             break;
1242         }
1243     }
1244
1245     if (pop_when_decl())
1246         return (1);
1247
1248     return (retval);
1249 }
1250
1251 /* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
1252
1253 ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
1254
1255 ENTITY *
1256 new_entity(type, name, line)
1257 int type;
1258 char *name;
1259 int line;
1260 {
1261     ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
1262     ENTITY *hash_conflict;
1263
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);
1269
1270     entity->type = type;
1271     entity->name = name;
1272     entity->line = line;
1273
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);
1279         free (entity);
1280         return (NULL);
1281     }
1282
1283     return (entity);
1284 }
1285
1286 static int parse_entity TAC_ARGS((int entity_type));
1287
1288 static int
1289 parse_entity(entity_type)
1290 int entity_type;
1291 {
1292     ENTITY *entity;
1293     int save_sym;
1294     char **fieldp = NULL /* GCC paranoia */;
1295     char buf[MAX_INPUT_LINE_LEN];
1296
1297     sym_get();
1298     parse(S_separator);
1299
1300     entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
1301     if (!entity)
1302         return (1);             /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
1303
1304     sym_get();
1305     parse(S_openbra);
1306
1307     /* Is the default deny for svcs or cmds to be overridden? */
1308     entity->svc_dflt = parse_opt_svc_default();
1309
1310     while (1) {
1311         if (entity_type != S_user)
1312             switch (sym_code) {
1313             case S_key:
1314                 ASSIGN(entity->key);
1315                 sym_get();
1316                 continue;
1317             }
1318
1319         switch (sym_code) {
1320         case S_eof:
1321             return (0);
1322
1323         case S_time:
1324            ASSIGN(entity->time);
1325            sym_get();
1326            continue;
1327
1328         case S_before:
1329             sym_get();
1330             parse(S_authorization);
1331             if (entity->before_author)
1332                 free(entity->before_author);
1333             entity->before_author = tac_strdup(sym_buf);
1334             sym_get();
1335             continue;
1336
1337         case S_after:
1338             sym_get();
1339             parse(S_authorization);
1340             if (entity->after_author)
1341                 free(entity->after_author);
1342             entity->after_author = tac_strdup(sym_buf);
1343             sym_get();
1344             continue;
1345
1346         case S_login:
1347             if (entity->login) {
1348                 parse_error("Duplicate value for %s %s and %s on line %d",
1349                             codestring(sym_code), entity->login,
1350                             sym_buf, sym_line);
1351                 tac_exit(1);
1352             }
1353             sym_get();
1354             parse(S_separator);
1355             switch(sym_code) {
1356
1357             case S_skey:
1358                 entity->login = tac_strdup(sym_buf);
1359                 break;
1360
1361             case S_nopasswd:
1362                 /* set to dummy string, so that we detect a duplicate
1363                  * password definition attempt
1364                  */
1365                 entity->login = tac_strdup(nopasswd_str);
1366                 entity->nopasswd = 1;
1367                 break;
1368
1369             case S_file:
1370             case S_cleartext:
1371             case S_des:
1372 #ifdef USE_PAM
1373             case S_pam:
1374 #endif /* USE_PAM */
1375 #ifdef DB
1376             case S_db:
1377 #endif /* USE DB */
1378                 sprintf(buf, "%s ", sym_buf);
1379                 sym_get();
1380                 strcat(buf, sym_buf);
1381                 entity->login = tac_strdup(buf);
1382                 break;
1383
1384             default:
1385 #ifdef USE_PAM
1386                 parse_error(
1387  "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1388                             sym_line);
1389 #else
1390                 parse_error(
1391  "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1392                             sym_line);
1393 #endif /* USE_PAM */
1394             }
1395             sym_get();
1396             continue;
1397
1398         case S_pap:
1399             if (entity->pap) {
1400                 parse_error("Duplicate value for %s %s and %s on line %d",
1401                             codestring(sym_code), entity->pap,
1402                             sym_buf, sym_line);
1403                 tac_exit(1);
1404             }
1405             sym_get();
1406             parse(S_separator);
1407             switch(sym_code) {
1408
1409             case S_cleartext:
1410             case S_des:
1411 #ifdef USE_PAM
1412             case S_pam:
1413 #endif /*USE_PAM */
1414                 sprintf(buf, "%s ", sym_buf);
1415                 sym_get();
1416                 strcat(buf, sym_buf);
1417                 entity->pap = tac_strdup(buf);
1418                 break;
1419
1420                 sprintf(buf, "%s ", sym_buf);
1421                 entity->pap = tac_strdup(buf);
1422                 break;
1423
1424             default:
1425 #ifdef USE_PAM
1426                 parse_error(
1427  "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d",
1428  sym_line);
1429 #else
1430                 parse_error(
1431  "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
1432  sym_line);
1433 #endif /*USE_PAM */
1434             }
1435             sym_get();
1436             continue;
1437
1438         case S_name:
1439             ASSIGN(entity->full_name);
1440             sym_get();
1441             continue;
1442
1443         case S_expires:
1444             ASSIGN(entity->expires);
1445             sym_get();
1446             continue;
1447
1448         case S_message:
1449             ASSIGN(entity->msg);
1450             sym_get();
1451             continue;
1452
1453         case S_arap:
1454         case S_chap:
1455 #ifdef MSCHAP
1456         case S_mschap:
1457 #endif /* MSCHAP */
1458         case S_opap:
1459         case S_global:
1460             save_sym = sym_code;
1461             sym_get();
1462             parse(S_separator);
1463             sprintf(buf, "%s ", sym_buf);
1464             parse(S_cleartext);
1465             strcat(buf, sym_buf);
1466
1467             switch (save_sym) {
1468             case S_arap:
1469                 fieldp = &entity->arap;
1470                 break;
1471             case S_chap:
1472                 fieldp = &entity->chap;
1473                 break;
1474 #ifdef MSCHAP
1475             case S_mschap:
1476                 fieldp = &entity->mschap;
1477                 break;
1478 #endif /* MSCHAP */
1479             case S_pap:
1480                 fieldp = &entity->pap;
1481                 break;
1482             case S_opap:
1483                 fieldp = &entity->opap;
1484                 break;
1485             case S_global:
1486                 fieldp = &entity->global;
1487                 break;
1488             default:
1489                 report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
1490                         sym_line);
1491                 continue;
1492             }
1493
1494             if (*fieldp) {
1495                 parse_error("Duplicate value for %s %s and %s on line %d",
1496                             codestring(save_sym), *fieldp, sym_buf, sym_line);
1497                 tac_exit(1);
1498             }
1499             *fieldp = tac_strdup(buf);
1500             sym_get();
1501             continue;
1502
1503         case S_closebra:
1504             parse(S_closebra);
1505             return (0);
1506
1507 #ifdef MAXSESS
1508         case S_maxsess:
1509             sym_get();
1510             parse(S_separator);
1511             if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
1512                 parse_error("expecting integer, found '%s' on line %d",
1513                     sym_buf, sym_line);
1514             }
1515             sym_get();
1516             continue;
1517 #endif /* MAXSESS */
1518
1519         default:
1520             if (STREQ(sym_buf, "password")) {
1521                 fprintf(stderr,
1522                         "\npassword = <string> is obsolete. Use login = des <string>\n");
1523             }
1524
1525             if (parse_conditional_block_item(entity))
1526                 return (0);             /* error message already printed */
1527         }
1528     }
1529 }
1530
1531 static NODE *parse_svcs TAC_ARGS((void));
1532
1533 static NODE *
1534 parse_svcs()
1535 {
1536     NODE *result;
1537
1538     switch (sym_code) {
1539     default:
1540         return (NULL);
1541     case S_svc:
1542     case S_cmd:
1543         break;
1544     }
1545
1546     result = (NODE *) tac_malloc(sizeof(NODE));
1547
1548     bzero(result, sizeof(NODE));
1549     result->line = sym_line;
1550
1551     /* cmd declaration */
1552     if (sym_code == S_cmd) {
1553         parse(S_cmd);
1554         parse(S_separator);
1555         result->value = tac_strdup(sym_buf);
1556
1557         sym_get();
1558         parse(S_openbra);
1559         starve_when_decl();
1560         result->value1 = parse_cmd_matches();
1561         parse(S_closebra);
1562         if (feed_when_decl())
1563                 tac_exit(1);            /* no error return possibility */
1564
1565         result->type = N_svc_cmd;
1566         result->when = copy_current_when_decl();
1567         expr_sink_register(result->when);
1568
1569         result->next = parse_svcs();
1570         return (result);
1571     }
1572
1573     /* svc declaration */
1574     parse(S_svc);
1575     parse(S_separator);
1576     switch (sym_code) {
1577     default:
1578         parse_error("expecting service type but found %s on line %d",
1579                     sym_buf, sym_line);
1580         return (NULL);
1581
1582     case S_string:
1583         result->type = N_svc;
1584         /* should perhaps check that this is an allowable service name */
1585         result->value1 = tac_strdup(sym_buf);
1586         break;
1587     case S_exec:
1588         result->type = N_svc_exec;
1589         break;
1590     case S_arap:
1591         result->type = N_svc_arap;
1592         break;
1593     case S_slip:
1594         result->type = N_svc_slip;
1595         break;
1596     case S_ppp:
1597         result->type = N_svc_ppp;
1598         parse(S_ppp);
1599         parse(S_protocol);
1600         parse(S_separator);
1601         /* Should perhaps check that this is a known PPP protocol name */
1602         result->value1 = tac_strdup(sym_buf);
1603         break;
1604     }
1605
1606     sym_get();
1607     parse(S_openbra);
1608     starve_when_decl();
1609
1610     result->dflt = parse_opt_attr_default();
1611     result->value = parse_attrs();
1612
1613     parse(S_closebra);
1614     feed_when_decl();
1615
1616     result->when = copy_current_when_decl();
1617     expr_sink_register(result->when);
1618
1619     result->next = parse_svcs();
1620     return (result);
1621 }
1622
1623 /*  <cmd_match>  := <permission> <string> */
1624
1625 static NODE *parse_cmd_matches TAC_ARGS((void));
1626
1627 static NODE *
1628 parse_cmd_matches()
1629 {
1630     NODE *retval = NULL, **succp = &retval;
1631     NODE *result;
1632
1633     for (;;) {
1634         switch (sym_code) {
1635         default:
1636             return (retval);
1637
1638         case S_when:
1639             if (push_parsed_when_decl())
1640                 tac_exit(1);            /* no error return possibility */
1641             parse(S_openbra);
1642             result = parse_cmd_matches();
1643             parse(S_closebra);
1644             if (pop_when_decl())
1645                 tac_exit(1);            /* no error return possibility */
1646             break;
1647
1648         case S_permit:
1649         case S_deny:
1650
1651             result = (NODE *) tac_malloc(sizeof(NODE));
1652
1653             bzero(result, sizeof(NODE));
1654             result->line = sym_line;
1655
1656             result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
1657             result->value = tac_strdup(sym_buf);
1658
1659 #ifdef WITH_INCLUDED_REGEX
1660
1661             result->value1 = (void *) tac_regcomp(result->value);
1662
1663 #else /* WITH_INCLUDED_REGEX */
1664
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;
1669             }
1670
1671 #endif /* WITH_INCLUDED_REGEX */
1672
1673             if (!result->value1) {
1674                 report(LOG_ERR, "in regular expression %s on line %d",
1675                        sym_buf, sym_line);
1676                 tac_exit(1);
1677             }
1678             sym_get();
1679
1680             result->when = copy_current_when_decl();
1681             expr_sink_register(result->when);
1682
1683             result->next = NULL;
1684         }
1685         *succp = result;
1686         while (result->next)
1687             result = result->next;      /* skip parsed chain from parse_cmd_matches() */
1688         succp = &result->next;
1689     }
1690     /* NOTREACHED */
1691 }
1692
1693 static NODE *parse_attrs TAC_ARGS((void));
1694
1695 static NODE *
1696 parse_attrs()
1697 {
1698     NODE *retval = NULL, **succp = &retval;
1699     NODE *result;
1700     char buf[MAX_INPUT_LINE_LEN];
1701     int optional;
1702
1703     for (;;) {
1704         optional = 0;
1705
1706         switch (sym_code) {
1707         case S_closebra:
1708             return (retval);
1709
1710         case S_when:
1711             if (push_parsed_when_decl())
1712                 tac_exit(1);            /* no error return possibility */
1713             parse(S_openbra);
1714             result = parse_attrs();
1715             parse(S_closebra);
1716             if (pop_when_decl())
1717                 tac_exit(1);            /* no error return possibility */
1718             break;
1719
1720         case S_optional:
1721             optional = 1;
1722             sym_get();
1723             /* FALLTHRU */
1724         default:
1725             result = (NODE *) tac_malloc(sizeof(NODE));
1726
1727             bzero(result, sizeof(NODE));
1728             result->line = sym_line;
1729
1730             result->type = optional ? N_optarg : N_arg;
1731
1732             strcpy(buf, sym_buf);
1733             parse(S_string);
1734             strcat(buf, sym_buf);
1735             parse(S_separator);
1736             strcat(buf, sym_buf);
1737             parse(S_string);
1738
1739             result->value = tac_strdup(buf);
1740
1741             result->when = copy_current_when_decl();
1742             expr_sink_register(result->when);
1743
1744             result->next = NULL;
1745         }
1746         *succp = result;
1747         while (result->next)
1748             result = result->next;      /* skip parsed chain from parse_attrs() */
1749         succp = &result->next;
1750     }
1751     /* NOTREACHED */
1752 }
1753
1754
1755 static void sym_get TAC_ARGS((void));
1756
1757 static void
1758 sym_get()
1759 {
1760     getsym();
1761
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);
1765     }
1766 }
1767
1768 static char *sym_buf_add TAC_ARGS((int c));
1769
1770 static char *
1771 sym_buf_add(c)
1772 int c;                          /* promoted "char" type */
1773 {
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);
1779         }
1780         return(NULL);
1781     }
1782
1783     sym_buf[sym_pos++] = c;
1784     return(sym_buf);
1785 }
1786
1787 static void getsym TAC_ARGS((void));
1788
1789 static void
1790 getsym()
1791 {
1792
1793 next:
1794     switch (sym_ch) {
1795
1796     case EOF:
1797         sym_code = S_eof;
1798         return;
1799
1800     case '\n':
1801         sym_line++;
1802         rch();
1803         goto next;
1804
1805     case '\t':
1806     case ' ':
1807         while (sym_ch == ' ' || sym_ch == '\t')
1808             rch();
1809         goto next;
1810
1811     case '=':
1812         strcpy(sym_buf, "=");
1813         sym_code = S_separator;
1814         rch();
1815         return;
1816
1817     case '{':
1818         strcpy(sym_buf, "{");
1819         sym_code = S_openbra;
1820         rch();
1821         return;
1822
1823     case '}':
1824         strcpy(sym_buf, "}");
1825         sym_code = S_closebra;
1826         rch();
1827         return;
1828
1829     case '(':
1830         strcpy(sym_buf, "(");
1831         sym_code = S_openparen;
1832         rch();
1833         return;
1834
1835     case ')':
1836         strcpy(sym_buf, ")");
1837         sym_code = S_closeparen;
1838         rch();
1839         return;
1840
1841     case '#':
1842         while ((sym_ch != '\n') && (sym_ch != EOF))
1843             rch();
1844         goto next;
1845
1846     case '"':
1847         rch();
1848         sym_pos = 0;
1849         while (1) {
1850
1851             if (sym_ch == '"') {
1852                 break;
1853             }
1854
1855             /* backslash-double-quote is supported inside strings */
1856             /* also allow \n */
1857             if (sym_ch == '\\') {
1858                 rch();
1859                 switch (sym_ch) {
1860                 case 'n':
1861                     /* preserve the slash for \n */
1862                     if (!sym_buf_add('\\')) {
1863                         sym_code = S_unknown;
1864                         rch();
1865                         return;
1866                     }
1867
1868                     /* fall through */
1869                 case '"':
1870                     if (!sym_buf_add(sym_ch)) {
1871                         sym_code = S_unknown;
1872                         rch();
1873                         return;
1874                     }
1875                     rch();
1876                     continue;
1877                 default:
1878                     sym_code = S_unknown;
1879                     rch();
1880                     return;
1881                 }
1882             }
1883             if (!sym_buf_add(sym_ch)) {
1884                 sym_code = S_unknown;
1885                 rch();
1886                 return;
1887             }
1888             rch();
1889         }
1890         rch();
1891
1892         if (!sym_buf_add('\0')) {
1893             sym_code = S_unknown;
1894             rch();
1895             return;
1896         }
1897         sym_code = S_string;
1898         return;
1899
1900     default:
1901         sym_pos = 0;
1902         while (sym_ch != '\t' && sym_ch != ' ' && sym_ch != '='
1903                && sym_ch != '\n') {
1904
1905             if (!sym_buf_add(sym_ch)) {
1906                 sym_code = S_unknown;
1907                 rch();
1908                 return;
1909             }
1910             rch();
1911         }
1912
1913         if (!sym_buf_add('\0')) {
1914             sym_code = S_unknown;
1915             rch();
1916             return;
1917         }
1918         sym_code = keycode(sym_buf);
1919         if (sym_code == S_unknown)
1920             sym_code = S_string;
1921         return;
1922     }
1923 }
1924
1925 static void rch TAC_ARGS((void));
1926
1927 static void
1928 rch()
1929 {
1930     if (sym_error) {
1931         sym_ch = EOF;
1932         return;
1933     }
1934     sym_ch = getc(cf);
1935
1936     if (parse_only && sym_ch != EOF)
1937         fprintf(stderr, "%c", sym_ch);
1938 }
1939
1940
1941 static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
1942
1943 /* Find the value of a field. Does not recurse. */
1944 static VALUE
1945 get_value(entity, field)
1946 ENTITY *entity;
1947 int field;
1948 {
1949     VALUE v;
1950
1951     v.pval = NULL;      /* do both just for sure... */
1952     v.intval = 0;
1953
1954     if (!entity) {
1955         parse_error("get_value: illegal entity");
1956         return (v);
1957     }
1958     switch (field) {
1959
1960     case S_name:
1961         v.pval = entity->name;
1962         break;
1963
1964     case S_login:
1965         v.pval = entity->login;
1966         break;
1967
1968     case S_global:
1969         v.pval = entity->global;
1970         break;
1971
1972     case S_expires:
1973         v.pval = entity->expires;
1974         break;
1975
1976     case S_arap:
1977         v.pval = entity->arap;
1978         break;
1979
1980     case S_chap:
1981         v.pval = entity->chap;
1982         break;
1983
1984 #ifdef MSCHAP
1985     case S_mschap:
1986         v.pval = entity->mschap;
1987         break;
1988 #endif /* MSCHAP */
1989
1990     case S_pap:
1991         v.pval = entity->pap;
1992         break;
1993
1994     case S_opap:
1995         v.pval = entity->opap;
1996         break;
1997
1998     case S_message:
1999         v.pval = entity->msg;
2000         break;
2001
2002     case S_svc:
2003         v.pval = entity->svcs;
2004         break;
2005
2006     case S_before:
2007         v.pval = entity->before_author;
2008         break;
2009
2010     case S_after:
2011         v.pval = entity->after_author;
2012         break;
2013
2014     case S_svc_dflt:
2015         v.intval = entity->svc_dflt;
2016         break;
2017
2018 #ifdef MAXSESS
2019     case S_maxsess:
2020         v.intval = entity->maxsess;
2021         break;
2022 #endif
2023
2024     case S_nopasswd:
2025         v.intval = entity->nopasswd;
2026         break;
2027
2028     case S_time:
2029         v.pval = entity->time;
2030         break;
2031
2032     case S_key:
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);
2036             v.pval = NULL;
2037             return(v);
2038         }
2039         v.pval = entity->key;
2040         break;
2041
2042     default:
2043         report(LOG_ERR, "get_value: unknown field %d", field);
2044         break;
2045     }
2046     return (v);
2047 }
2048
2049
2050 /* Internal graph scanning routines */
2051
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));
2053
2054 static enum value_scan_func_result
2055 value_scan(type, name, recurse, func, func_data)
2056 int type;
2057 const char *name;
2058 int recurse;
2059 value_scan_func_t func;
2060 void *func_data;
2061 {
2062     ENTITY *entity;
2063
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);
2067
2068     entity = entity_lookup(type, name);
2069     if (!entity) {
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);
2074     }
2075
2076     return (value_scan_entity(entity, recurse, func, func_data));
2077 }
2078
2079 /* For each user, check she doesn't circularly reference a
2080    group. Return 1 if it does */
2081
2082 static int circularity_check_failed;
2083
2084 static void circularity_check_fail TAC_ARGS((struct membership *membership));
2085
2086 static void
2087 circularity_check_fail(membership)
2088 struct membership *membership;
2089 {
2090     ENTITY *entity;
2091
2092     circularity_check_failed = 1;
2093
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);
2100     }
2101 }
2102
2103 static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
2104
2105 static enum value_scan_func_result
2106 circularity_check_func(entity, func_data /* unused */)
2107 ENTITY *entity;
2108 void *func_data;
2109 {
2110     /* only useful to speedup case of failure */
2111     if (circularity_check_failed)
2112         return (VSFR_FOUND);
2113
2114     return (VSFR_CONTINUE);
2115 }
2116
2117 static int circularity_check TAC_ARGS((void));
2118
2119 static int
2120 circularity_check()
2121 {
2122     ENTITY *entity;
2123     ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
2124     ENTITY **users;
2125
2126     /* users */
2127     for (users = users_base; *users; users++) {
2128         entity = *users;
2129
2130         if (debug & DEBUG_PARSE_FLAG)
2131             report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
2132
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)
2139             break;
2140     }
2141     free(users_base);
2142     return (circularity_check_failed);
2143 }
2144
2145
2146 /* Return a value for a group or user (isuser says if
2147    this name is a group or a user name).
2148
2149    If no value exists, and recurse is true, also check groups we are a
2150    member of, recursively.
2151
2152    Returns void * because it can return a string or a node pointer
2153    (should really return a union pointer).
2154 */
2155
2156 static VALUE cfg_get_value_VALUE;       /* private */
2157
2158 static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
2159
2160 static enum value_scan_func_result
2161 cfg_get_value_func(entity,attrp /* func_data */)
2162 ENTITY *entity;
2163 int *attrp;
2164 {
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);
2169
2170     return (VSFR_CONTINUE);
2171 }
2172
2173 static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
2174
2175 static VALUE
2176 cfg_get_value(type, name, attr, recurse)
2177 int type;
2178 const char *name;
2179 int attr, recurse;
2180 {
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);
2184
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);
2189 }
2190
2191
2192 /* Wrappers for cfg_get_value:
2193  */
2194
2195 int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2196
2197 int
2198 cfg_get_intvalue(type, name, attr, recurse)
2199 int type;
2200 const char *name;
2201 int attr, recurse;
2202 {
2203     int val = cfg_get_value(type, name, attr, recurse).intval;
2204
2205     if (debug & DEBUG_CONFIG_FLAG)
2206         report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
2207     return(val);
2208 }
2209
2210 const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2211
2212 const char *
2213 cfg_get_pvalue(type, name, attr, recurse)
2214 int type;
2215 const char *name;
2216 int attr, recurse;
2217 {
2218     char *p = cfg_get_value(type, name, attr, recurse).pval;
2219
2220     if (debug & DEBUG_CONFIG_FLAG)
2221         report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
2222                 p ? p : "NULL");
2223     return(p);
2224 }
2225
2226 /* Read the config file and do some basic sanity checking on
2227  * it. Return 1 if we find any errors.
2228  */
2229 int cfg_read_config TAC_ARGS((const char *cfile));
2230
2231 int
2232 cfg_read_config(cfile)
2233 const char *cfile;
2234 {
2235     sym_line = 1;
2236
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]);
2240         return (1);
2241     }
2242     if (parse_decls() || sym_error) {
2243         fclose(cf);
2244         return (1);
2245     }
2246
2247     if (0
2248      || enlist_entity_connect()
2249      || expr_sink_commit()
2250             /* circularity is allowed in the new fully-recursive algorithm */
2251      || (!algorithm_recursive && circularity_check())
2252         ) {
2253         fclose(cf);
2254         return (1);
2255     }
2256     if (!WHEN_EXPR_ROOT_EMPTY() || when_expr_dungeon) {
2257         report(LOG_ERR, "Some 'when' expression found still pushed on stack");
2258         fclose(cf);
2259         return (1);
2260     }
2261
2262     fclose(cf);
2263     return (0);
2264 }
2265
2266 /* return 1 if user exists, 0 otherwise
2267  */
2268 int cfg_user_exists TAC_ARGS((const char *username));
2269
2270 int
2271 cfg_user_exists(username)
2272 const char *username;
2273 {
2274     return (NULL != hash_lookup(usertable, username));
2275 }
2276
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
2279  */
2280 const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
2281
2282 const char *
2283 cfg_get_expires(username, recurse)
2284 const char *username;
2285 int recurse;
2286 {
2287     return (cfg_get_pvalue(S_user, username, S_expires, recurse));
2288 }
2289
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
2292  */
2293 const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
2294
2295 const char *
2296 cfg_get_timestamp(username, recurse)
2297 const char *username;
2298 int recurse;
2299 {
2300     return (cfg_get_pvalue(S_user, username, S_time, recurse));
2301 }
2302
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
2305  */
2306 const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
2307
2308 const char *
2309 cfg_get_login_secret(user, recurse)
2310 const char *user;
2311 int recurse;
2312 {
2313     return (cfg_get_pvalue(S_user, user, S_login, recurse));
2314 }
2315
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
2318  */
2319 int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
2320
2321 int
2322 cfg_get_user_nopasswd(user, recurse)
2323 const char *user;
2324 int recurse;
2325 {
2326     return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
2327 }
2328
2329 /* return user's secret. If none, try groups she is a member
2330  * on, and so on, recursively if recurse is non-zero
2331  */
2332 const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
2333
2334 const char *
2335 cfg_get_arap_secret(user, recurse)
2336 const char *user;
2337 int recurse;
2338 {
2339     return (cfg_get_pvalue(S_user, user, S_arap, recurse));
2340 }
2341
2342 const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
2343
2344 const char *
2345 cfg_get_chap_secret(user, recurse)
2346 const char *user;
2347 int recurse;
2348 {
2349     return (cfg_get_pvalue(S_user, user, S_chap, recurse));
2350 }
2351
2352 #ifdef MSCHAP
2353
2354 const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
2355
2356 const char *
2357 cfg_get_mschap_secret(user, recurse)
2358 const char *user;
2359 int recurse;
2360 {
2361     return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
2362 }
2363
2364 #endif /* MSCHAP */
2365
2366 const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
2367
2368 const char *
2369 cfg_get_pap_secret(user, recurse)
2370 const char *user;
2371 int recurse;
2372 {
2373     return (cfg_get_pvalue(S_user, user, S_pap, recurse));
2374 }
2375
2376 const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
2377
2378 const char *
2379 cfg_get_opap_secret(user, recurse)
2380 const char *user;
2381 int recurse;
2382 {
2383     return (cfg_get_pvalue(S_user, user, S_opap, recurse));
2384 }
2385
2386 /* return the global password for the user (or the group, etc.) */
2387
2388 const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
2389
2390 const char *
2391 cfg_get_global_secret(user, recurse)
2392 const char *user;
2393 int recurse;
2394 {
2395     return (cfg_get_pvalue(S_user, user, S_global, recurse));
2396 }
2397
2398 #ifdef USE_PAM
2399
2400 /* Return a pointer to a node representing a PAM Service name */
2401
2402 const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
2403
2404 const char *
2405 cfg_get_pam_service(user, recurse)
2406 const char *user;
2407 int recurse;
2408 {
2409     const char *cfg_passwd;
2410     const char *p;
2411
2412     cfg_passwd = cfg_get_pap_secret(user, recurse);
2413
2414     if (!cfg_passwd)
2415         cfg_passwd = cfg_get_global_secret(user, recurse);
2416
2417     if (!cfg_passwd && !cfg_user_exists(user)) {
2418         cfg_passwd = cfg_get_authen_default();
2419         switch (cfg_get_authen_default_method()) {
2420
2421         case (S_pam):
2422             if (debug & DEBUG_AUTHOR_FLAG)
2423                 report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
2424             return(cfg_passwd);
2425             break;
2426
2427         default:
2428             if (debug & DEBUG_AUTHOR_FLAG)
2429                 report(LOG_DEBUG, "I havent find any PAM Service!!");
2430             return(NULL);/* Haven't any PAM Service!! */
2431         }
2432     }
2433
2434     p = tac_find_substring("pam ", cfg_passwd);
2435
2436     if(p) {  /* We find PAM services */
2437         if (debug & DEBUG_AUTHOR_FLAG)
2438                 report(LOG_DEBUG, "I get PAM sevice:%s",p);
2439         return (p);
2440     }
2441
2442     if (debug & DEBUG_AUTHOR_FLAG)
2443         report(LOG_DEBUG, "No any PAM Sevice");
2444
2445     return(NULL);
2446 }
2447
2448 #endif /* For PAM */
2449
2450
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
2454    is N_svc.
2455 */
2456
2457 struct cfg_get_svc_node_param {
2458     int svctype;
2459     const char *protocol, *svcname;
2460     NODE *node;
2461     int retval;
2462 };
2463
2464 static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
2465
2466 static enum value_scan_func_result
2467 cfg_get_svc_node_func(entity, param /* func_data */)
2468 ENTITY *entity;
2469 struct cfg_get_svc_node_param *param;
2470 {
2471     NODE *svc;
2472     enum eval_result svc_default;
2473
2474     for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2475         if (svc->type != param->svctype)
2476             continue;
2477         if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
2478             continue;
2479         if (param->svctype == N_svc     && param->svcname  && !STREQ(svc->value1, param->svcname ))
2480             continue;
2481         if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
2482             continue;
2483
2484         if (debug & DEBUG_CONFIG_FLAG)
2485             report(LOG_DEBUG,
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 : "");
2490
2491         param->node = svc;
2492         param->retval = 1;
2493         return (VSFR_FOUND);
2494     }
2495
2496     /* look at 'default service' settings */
2497     svc_default = entity_svc_default(entity);
2498     switch (svc_default) {
2499
2500     case ER_TRUE:
2501     case ER_FALSE:
2502         if (debug & DEBUG_AUTHOR_FLAG)
2503             report(LOG_DEBUG,
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"));
2509
2510         param->retval = (svc_default == ER_TRUE);
2511         return (VSFR_FOUND);
2512
2513     default:    /* shouldn't happen */
2514     case ER_UNKNOWN:
2515         return (VSFR_CONTINUE);
2516     }
2517     /* NOTREACHED */
2518 }
2519
2520 int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
2521
2522 int
2523 cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
2524 const char *username;
2525 int svctype;
2526 const char *protocol;
2527 const char *svcname;
2528 int recurse;
2529 NODE **nodep;
2530 {
2531     struct cfg_get_svc_node_param param;
2532     enum value_scan_func_result vsfr;
2533
2534     param.svctype = svctype;
2535     param.protocol = protocol;
2536     param.svcname = svcname;
2537     param.node = NULL;
2538     param.retval = 0;
2539
2540     if (debug & DEBUG_CONFIG_FLAG)
2541         report(LOG_DEBUG,
2542                "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
2543                username,
2544                cfg_nodestring(svctype),
2545                protocol ? protocol : "",
2546                svcname ? svcname : "",
2547                recurse);
2548
2549     vsfr = value_scan(S_user, username, recurse,
2550                 (value_scan_func_t) cfg_get_svc_node_func, &param /* func_data */);
2551     if (nodep)
2552         *nodep = param.node;
2553
2554     if (vsfr == VSFR_FOUND)
2555         return (param.retval);
2556
2557     /* The service does not exist. Do the default */
2558     return (cfg_no_user_permitted() ? 1 : 0);
2559 }
2560
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 */
2563
2564 struct cfg_authorize_cmd_param {
2565     const char *cmd;
2566     const char *args;
2567     enum eval_result result;
2568 };
2569
2570 static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
2571
2572 static enum value_scan_func_result
2573 cfg_authorize_cmd_func(entity, param /* func_data */)
2574 ENTITY *entity;
2575 struct cfg_authorize_cmd_param *param;
2576 {
2577     NODE *svc;
2578
2579     for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2580         NODE *node;
2581
2582         if (svc->type != N_svc_cmd)
2583             continue;
2584         if (!STREQ(svc->value, param->cmd))
2585             continue;
2586         if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
2587             continue;
2588
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));
2592
2593         /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
2594
2595         for (node = svc->value1; node; node = node->next) {
2596             int match;
2597
2598             if (expr_eval(node->when) != ER_TRUE)               /* expensive */
2599                 continue;
2600
2601 #ifdef WITH_INCLUDED_REGEX
2602
2603             match = tac_regexec((tac_regexp *) node->value1, param->args);
2604
2605 #else /* WITH_INCLUDED_REGEX */
2606
2607             match = !regexec((const regex_t *) node->value1, param->args /* string */,
2608                     0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
2609
2610 #endif /* WITH_INCLUDED_REGEX */
2611
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 "));
2617             }
2618
2619             if (!match)
2620                 continue;
2621
2622             switch (node->type) {
2623             case N_permit:
2624                 if (debug & DEBUG_AUTHOR_FLAG) {
2625                     report(LOG_DEBUG, "%s %s permitted by line %d",
2626                            param->cmd, param->args, node->line);
2627                 }
2628                 param->result = ER_TRUE;
2629                 return (VSFR_FOUND);
2630                 break;
2631             case N_deny:
2632                 if (debug & DEBUG_AUTHOR_FLAG) {
2633                     report(LOG_DEBUG, "%s %s denied by line %d",
2634                            param->cmd, param->args, node->line);
2635                 }
2636                 param->result = ER_FALSE;
2637                 return (VSFR_FOUND);
2638                 break;
2639             default:
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);
2644             }
2645         }
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)",
2649                         param->cmd);
2650             param->result = ER_FALSE;   /* emulate last "deny .*" */
2651             return (VSFR_FOUND);
2652         }
2653     }
2654
2655     /* look at 'default service' settings */
2656     param->result = entity_svc_default(entity);
2657     switch (param->result) {
2658
2659     case ER_TRUE:
2660         if (debug & DEBUG_AUTHOR_FLAG)
2661             report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
2662         return (VSFR_FOUND);
2663
2664     case ER_FALSE:
2665
2666         if (debug & DEBUG_AUTHOR_FLAG)
2667             report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
2668         return (VSFR_FOUND);
2669
2670     default:    /* shouldn't happen */
2671     case ER_UNKNOWN:
2672         return (VSFR_CONTINUE);
2673     }
2674     /* NOTREACHED */
2675 }
2676
2677 enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
2678
2679 enum eval_result
2680 cfg_authorize_cmd(username, cmd, args)
2681 const char *username;
2682 const char *cmd;
2683 const char *args;
2684 {
2685     struct cfg_authorize_cmd_param param;
2686
2687     param.cmd = cmd;
2688     param.args = args;
2689     param.result = ER_UNKNOWN;  /* error */
2690
2691     if (debug & DEBUG_CONFIG_FLAG)
2692         report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
2693                username, cmd, args);
2694
2695     value_scan(S_user, username, TAC_PLUS_RECURSE,
2696                 (value_scan_func_t) cfg_authorize_cmd_func, &param /* func_data */);
2697
2698     if (param.result != ER_UNKNOWN)
2699         return (param.result);
2700
2701     /* The command does not exist. Do the default */
2702     return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
2703 }
2704
2705 /* Return an array of character strings representing configured AV
2706  * pairs, given a username and a service node.
2707  *
2708  * In the AV strings returned, manipulate the separator character to
2709  * indicate which args are optional and which are mandatory.
2710  *
2711  * Lastly, indicate what default permission was configured by setting
2712  * denyp */
2713
2714 char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
2715
2716 char **
2717 cfg_get_svc_attrs(svcnode, denyp)
2718 NODE *svcnode;
2719 int *denyp;
2720 {
2721     int i;
2722     NODE *node;
2723     char **args;
2724
2725     *denyp = 1;
2726
2727     if (!svcnode)
2728         return (NULL);
2729
2730     *denyp = (svcnode->dflt == S_deny);
2731
2732     i = 0;
2733     for (node = svcnode->value; node; node = node->next)
2734         i++;
2735
2736     args = (char **) tac_malloc(sizeof(char *) * (i + 1));
2737
2738     i = 0;
2739     for (node = svcnode->value; node; node = node->next) {
2740         char *arg;
2741         char *p;
2742
2743         if (expr_eval(node->when) != ER_TRUE)   /* expensive */
2744             continue;   /* ignore this node */
2745
2746         arg = tac_strdup(node->value);
2747         p = index(arg, '=');
2748         if (p && node->type == N_optarg)
2749             *p = '*';
2750         args[i++] = arg;
2751     }
2752     args[i] = NULL;
2753     return (args);
2754 }
2755
2756
2757 static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
2758
2759 static enum eval_result
2760 entity_svc_default(entity)
2761 ENTITY *entity;
2762 {
2763     switch (entity->svc_dflt) {
2764     case S_permit:
2765         return (ER_TRUE);
2766     case S_deny:
2767         return (ER_FALSE);
2768     case S_default:
2769     case 0:     /* not specified */
2770         return (ER_UNKNOWN);
2771     default:
2772         report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
2773         return (ER_UNKNOWN);
2774     }
2775 }
2776
2777 int cfg_no_user_permitted TAC_ARGS((void));
2778
2779 int
2780 cfg_no_user_permitted()
2781 {
2782     if (no_user_dflt == S_permit)
2783         return (1);
2784     return (0);
2785 }
2786
2787
2788 const char *cfg_get_authen_default TAC_ARGS((void));
2789
2790 const char *
2791 cfg_get_authen_default()
2792 {
2793     return (authen_default);
2794 }
2795
2796 int cfg_get_authen_default_method TAC_ARGS((void));
2797
2798 /* For describe authentication method(pam,file,db..etc) */
2799 int
2800 cfg_get_authen_default_method()
2801 {
2802    return (authen_default_method);
2803 }
2804
2805
2806 /* Host entity management:
2807  */
2808
2809 const char *cfg_get_host_key TAC_ARGS((const char *host));
2810
2811 /* For getting host key */
2812 const char *
2813 cfg_get_host_key(host)
2814 const char *host;
2815 {
2816     return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
2817 }
2818
2819 static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
2820
2821 static ENTITY *
2822 force_belong_entity(type, name)
2823 int type;
2824 const char *name;
2825 {
2826     ENTITY *entity = entity_lookup(type, name);
2827
2828     if (entity)
2829         eval_force_belong_entity(entity);
2830
2831     return (entity);
2832 }
2833
2834 /* assumed existing initialized "session.peer*" */
2835
2836 static ENTITY *request_peer_addr;
2837 static ENTITY *request_peer;
2838 static ENTITY *request_DEFAULT_group;
2839
2840 static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
2841
2842 static void
2843 enlist_request_peer(hostname, entityp)
2844 const char *hostname;
2845 ENTITY **entityp;
2846 {
2847     *entityp = NULL;
2848     if (!hostname)
2849         return;
2850
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 */);
2854 }
2855
2856 /* Try to build the following scenery:
2857  * 
2858  * host <session.peer_addr> [=ER_TRUE]
2859  *  |
2860  *  +-- group <DEFAULT_GROUPNAME>
2861  *
2862  * host <session.peer     > [=ER_TRUE]
2863  *  |
2864  *  +-- group <DEFAULT_GROUPNAME>
2865  */
2866
2867 void cfg_request_scan_begin TAC_ARGS((void));
2868
2869 void
2870 cfg_request_scan_begin()
2871 {
2872     request_scan_begin();
2873
2874     request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2875
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);
2879 }
2880
2881 /* Try to build the following scenery:
2882  *
2883  * ( user <identity->username> |  user <DEFAULT_USERNAME> ) [=ER_TRUE]
2884  *  |
2885  *  +-- host <session.peer_addr> [=ER_TRUE]
2886  *  |    |
2887  *  |    +- group <DEFAULT_GROUPNAME>
2888  *  |
2889  *  +-- host <session.peer     > [=ER_TRUE]
2890  *  |    |
2891  *  |    +-- group <DEFAULT_GROUPNAME>
2892  *  |
2893  *  +-- group <DEFAULT_GROUPNAME>
2894  */
2895
2896 void cfg_request_identity TAC_ARGS((const struct identity *identity));
2897
2898 void
2899 cfg_request_identity(identity)
2900 const struct identity *identity;
2901 {
2902     ENTITY *user_entity,*request_DEFAULT_group;
2903
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);
2907
2908     user_entity = force_belong_entity(S_user, identity->username);
2909     request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2910
2911     if (!user_entity)
2912         user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
2913
2914     request_scan_user_known = 1;
2915
2916     if (!user_entity)
2917         return;
2918
2919     if (request_peer_addr)
2920         virtual_enlist_entity_direct(request_peer_addr     /* parent */, user_entity /* child */);
2921     if (request_peer     )
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 */);
2925 }