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