Initial "gts1" commit.
[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
848 static void when_expr_root_init TAC_ARGS((void));
849
850 static void
851 when_expr_root_init()
852 {
853     free_expr(when_expr_root);
854     when_expr_root = new_expr(S_and);
855 }
856
857 static struct expr *parse_expr_node TAC_ARGS((int single_item));
858
859 static struct expr *
860 parse_expr_node(single_item)
861 int single_item;
862 {
863     struct expr *expr_root = NULL;
864     struct expr **succ_exprp = &expr_root;
865     struct expr *expr;
866
867     while (1) {
868         switch (sym_code) {
869
870         case S_not:
871             expr = (struct expr *) tac_malloc(sizeof(struct expr));
872             expr->line = sym_line;
873             *succ_exprp = expr;
874             expr->next = NULL;
875             succ_exprp = &expr->next;
876             expr->type = S_not;
877             sym_get();
878             expr->u.not.child = parse_expr_node(1 /* single_item */);
879             if (!expr->u.not.child) {
880                 free_expr(expr_root);
881                 return (NULL);
882             }
883             break;
884
885         case S_user:
886         case S_host:
887         case S_group:
888             expr = (struct expr *) tac_malloc(sizeof(struct expr));
889             expr->line = sym_line;
890             *succ_exprp = expr;
891             expr->next = NULL;
892             succ_exprp = &expr->next;
893             expr->type = sym_code;
894             sym_get();
895             expr->u.entity.name = tac_strdup(sym_buf);
896             sym_get();
897             expr->u.entity.entity = NULL;       /* not known yet */
898             break;
899
900         case S_openparen:
901             sym_get();
902             expr = parse_expr_node(0 /* single_item */);
903             *succ_exprp = expr;
904             parse(S_closeparen);
905
906             if (expr->next) {
907                 report(LOG_ERR, "Illegal filled next field of parsed parenthesed expr");
908                 free_expr(expr_root);
909                 return (NULL);
910             }
911             succ_exprp = &expr->next;
912             break;
913
914         default:
915             parse_error("expecting 'not', 'user', 'host', 'group' or '(' but found '%s' on line %d",
916                     sym_buf, sym_line);
917             free_expr(expr_root);
918             return (NULL);
919         }
920
921         if (single_item)                /* used by 'not' operator with high precedence */
922             return (expr_root);
923
924         switch (sym_code) {
925
926         case S_and:
927         case S_or:
928             if (expr_root->type == (sym_code==S_and ? S_or : S_and)) {
929                 parse_error("ambiguous use of 'and' together with 'or', parentheses required on line %d",
930                         sym_line);
931                 free_expr(expr_root);
932                 return (NULL);
933             }
934             if (expr_root->type != sym_code) {
935                 expr = (struct expr *) tac_malloc(sizeof(struct expr));
936                 expr->line = sym_line;
937                 expr->next = NULL;
938                 expr->type = sym_code;
939                 expr->u.and_or.child_first = expr_root;
940                 expr_root = expr;
941             }
942             sym_get();
943             continue;
944         }
945
946         return(expr_root);
947     }
948 }
949
950 static struct expr *parse_when_decl TAC_ARGS((void));
951
952 static struct expr *
953 parse_when_decl()
954 {
955     parse(S_when);
956     if (!algorithm_recursive) {
957         parse_error("'when' conditionals supported only if set top level 'authorization = recursive', on line %d",
958                     sym_line);
959         return (NULL);
960     }
961     parse(S_separator);
962     return (parse_expr_node(0 /* single_item */));
963 }
964
965 static int push_parsed_when_decl TAC_ARGS((void));
966
967 static int
968 push_parsed_when_decl()
969 {
970     struct expr *new_expr;
971
972     new_expr = parse_when_decl();
973     if (!new_expr)
974         return (1);
975     if (new_expr->next) {
976         report(LOG_ERR, "Illegal filled next field of parsed expr");
977         free_expr(new_expr);
978         return (1);
979     }
980     new_expr->next = when_expr_root->u.and_or.child_first;
981     when_expr_root->u.and_or.child_first = new_expr;
982     when_expr_root->line = new_expr->line;
983     return (0);
984 }
985
986 static int pop_when_decl TAC_ARGS((void));
987
988 static int
989 pop_when_decl()
990 {
991     struct expr *first_expr;
992
993     first_expr = when_expr_root->u.and_or.child_first;
994     if (!first_expr) {
995         report(LOG_ERR, "No expr in stack and pop_when_decl() called");
996         return (1);
997     }
998     when_expr_root->u.and_or.child_first = first_expr->next;
999     free_expr(first_expr);
1000     return (0);
1001 }
1002
1003 static struct expr *copy_current_when_decl TAC_ARGS((void));
1004
1005 static struct expr *
1006 copy_current_when_decl()
1007 {
1008     return (dupl_expr(when_expr_root));
1009 }
1010
1011 ENTITY *entity_lookup TAC_ARGS((int type, const char *name));
1012
1013 ENTITY *
1014 entity_lookup(type, name)
1015 int type;
1016 const char *name;
1017 {
1018     return (hash_lookup(entity_type_to_hashtable(type), name));
1019 }
1020
1021 static int enlist_entity_connect TAC_ARGS((void));
1022
1023 static int
1024 enlist_entity_connect()
1025 {
1026     struct enlist_entity_item *item;
1027     ENTITY *parent_entity, *child_entity;
1028
1029     while ((item=enlist_entity_list)) {
1030
1031         parent_entity = entity_lookup(item->parent_type, item->parent);
1032         if (!parent_entity) {
1033             parse_error("Entity %s %s not defined, referenced as parent on line %d",
1034                     entity_type_to_string(item->parent_type), item->parent, item->line);
1035             return (1);
1036         }
1037         child_entity = entity_lookup(item-> child_type, item-> child);
1038         if (!child_entity) {
1039             child_entity = new_entity(item->child_type, item->child, item->line);
1040             if (!child_entity)
1041                 return (1);             /* 'hash_add_entry()' conflict */
1042             item->child = NULL;         /* don't free string ref'ed from 'child_entity'! */
1043         }
1044
1045         enlist_entity_direct(parent_entity, child_entity, item->when);
1046
1047         enlist_entity_list = item->next;
1048         item->when = NULL;
1049         free_enlist_entity_item(item);
1050         free(item);
1051     }
1052     enlist_entity_list_tailp = &enlist_entity_list;
1053     return (0);
1054 }
1055
1056 static void enlist_entity TAC_ARGS((int parent_type, const char *parent, int child_type, const char *child));
1057
1058 static void
1059 enlist_entity(parent_type, parent, child_type, child)
1060 int parent_type;
1061 const char *parent;
1062 int child_type;
1063 const char *child;
1064 {
1065     struct enlist_entity_item *item =
1066                 (struct enlist_entity_item *) tac_malloc(sizeof(struct enlist_entity_item));
1067
1068     item->next = NULL;
1069     *enlist_entity_list_tailp = item;
1070     enlist_entity_list_tailp = &item->next;
1071
1072     item->parent_type = parent_type;
1073     item->parent = tac_strdup(parent);
1074     item-> child_type =  child_type;
1075     item->child = tac_strdup(child);
1076     item->when = copy_current_when_decl();
1077     item->line = sym_line;
1078 }
1079
1080 static int parse_entity_spec TAC_ARGS((void));
1081
1082 /* returns 0 for error, otherwise S_user, S_host or S_group; sym_buf filled */
1083 static int
1084 parse_entity_spec()
1085 {
1086     int retval;
1087
1088     if (sym_code != S_user
1089      && sym_code != S_host
1090      && sym_code != S_group
1091         ) {
1092         parse_error("Expecting 'user', 'host' or ' group' as entity specification, found %s on line %d",
1093                     sym_buf, sym_line);
1094         return (0);
1095     }
1096
1097     retval = sym_code;
1098     sym_get();
1099
1100     return (retval);
1101 }
1102
1103 static int parse_conditional_block_item TAC_ARGS((ENTITY *entity));
1104
1105 static int
1106 parse_conditional_block_item(entity)
1107 ENTITY *entity;
1108 {
1109     switch (sym_code) {
1110     case S_eof:
1111         return (1);
1112
1113     /* case S_closebra: not needed, handled by our caller parse_conditional_block() */
1114
1115     default:
1116         parse_error("Unrecognised keyword %s for entity on line %d",
1117                     sym_buf, sym_line);
1118         return (1);
1119
1120     case S_member:
1121         sym_get();
1122         parse(S_separator);
1123         enlist_entity(S_group, sym_buf, entity->type, entity->name);
1124         sym_get();
1125         break;
1126
1127     case S_enlist: {
1128         int parsed_entity_type;
1129
1130         if (entity->type != S_group) {
1131             parse_error("'enlist' keyword allowed only in 'group' section on line %d",
1132                         sym_line);
1133             return (1);
1134         }
1135         sym_get();
1136         parse(S_separator);
1137         parsed_entity_type = parse_entity_spec();
1138         if (!parsed_entity_type)
1139             return (1);
1140         enlist_entity(entity->type, entity->name, parsed_entity_type, sym_buf);
1141         sym_get();
1142         break;
1143         }
1144
1145     case S_svc:
1146     case S_cmd:
1147
1148         if (entity->svcs) {
1149             /*
1150              * Already parsed some services/commands. Thanks to Gabor Kiss
1151              * who found this bug.
1152              */
1153             NODE *p;
1154             for (p=entity->svcs; p->next; p=p->next)
1155                 /* NULL STMT */;
1156             p->next = parse_svcs();
1157         } else {
1158             entity->svcs = parse_svcs();
1159         }
1160         break;
1161
1162     case S_when:
1163         if (parse_conditional_block(entity))
1164             return (1);
1165         break;
1166     }
1167
1168     return (0);
1169 }
1170
1171 static int parse_conditional_block TAC_ARGS((ENTITY *entity));
1172
1173 static int
1174 parse_conditional_block(entity)
1175 ENTITY *entity;
1176 {
1177     int retval = -1 /* GCC paranoia */;
1178
1179     if (push_parsed_when_decl())
1180         return (1);
1181     parse(S_openbra);
1182
1183     while (1) {
1184         if (sym_code == S_closebra) {
1185             sym_get();
1186             retval = 0;         /* success */
1187             break;
1188         }
1189
1190         if (parse_conditional_block_item(entity)) {
1191             retval = 1;         /* failure */
1192             break;
1193         }
1194     }
1195
1196     if (pop_when_decl())
1197         return (1);
1198
1199     return (retval);
1200 }
1201
1202 /* passed 'name' WILL be directly stored to returned ENTITY, don't touch it! */
1203
1204 static ENTITY *new_entity TAC_ARGS((int type, char *name, int line));
1205
1206 static ENTITY *
1207 new_entity(type, name, line)
1208 int type;
1209 char *name;
1210 int line;
1211 {
1212     ENTITY *entity = (ENTITY *) tac_malloc(sizeof(ENTITY));
1213     ENTITY *hash_conflict;
1214
1215     bzero(entity, sizeof(ENTITY));
1216     tac_list_init(&entity->to_parent_membership_list);
1217     tac_list_init(&entity->to_child_membership_list );
1218     entity->to_child_membership_num = 0;
1219     scan_init_entity(entity);
1220
1221     entity->type = type;
1222     entity->name = name;
1223     entity->line = line;
1224
1225     hash_conflict = hash_add_entry(entity_type_to_hashtable(type), (void *) entity);
1226     if (hash_conflict) {
1227         parse_error("multiply defined %s %s on lines %d and %d",
1228                     entity_type_to_string(type),
1229                     entity->name, hash_conflict->line, sym_line);
1230         free (entity);
1231         return (NULL);
1232     }
1233
1234     return (entity);
1235 }
1236
1237 static int parse_entity TAC_ARGS((int entity_type));
1238
1239 static int
1240 parse_entity(entity_type)
1241 int entity_type;
1242 {
1243     ENTITY *entity;
1244     int save_sym;
1245     char **fieldp = NULL /* GCC paranoia */;
1246     char buf[MAX_INPUT_LINE_LEN];
1247
1248     sym_get();
1249     parse(S_separator);
1250
1251     entity = new_entity(entity_type, tac_strdup(sym_buf) /* name */, sym_line /* line */);
1252     if (!entity)
1253         return (1);             /* 'hash_add_entry()' conflict, 'tac_strdup(sym_buf)' leaked! */
1254
1255     sym_get();
1256     parse(S_openbra);
1257
1258     /* Is the default deny for svcs or cmds to be overridden? */
1259     entity->svc_dflt = parse_opt_svc_default();
1260
1261     while (1) {
1262         if (entity_type != S_user)
1263             switch (sym_code) {
1264             case S_key:
1265                 ASSIGN(entity->key);
1266                 sym_get();
1267                 continue;
1268             }
1269
1270         switch (sym_code) {
1271         case S_eof:
1272             return (0);
1273
1274         case S_time:
1275            ASSIGN(entity->time);
1276            sym_get();
1277            continue;
1278
1279         case S_before:
1280             sym_get();
1281             parse(S_authorization);
1282             if (entity->before_author)
1283                 free(entity->before_author);
1284             entity->before_author = tac_strdup(sym_buf);
1285             sym_get();
1286             continue;
1287
1288         case S_after:
1289             sym_get();
1290             parse(S_authorization);
1291             if (entity->after_author)
1292                 free(entity->after_author);
1293             entity->after_author = tac_strdup(sym_buf);
1294             sym_get();
1295             continue;
1296
1297         case S_login:
1298             if (entity->login) {
1299                 parse_error("Duplicate value for %s %s and %s on line %d",
1300                             codestring(sym_code), entity->login,
1301                             sym_buf, sym_line);
1302                 tac_exit(1);
1303             }
1304             sym_get();
1305             parse(S_separator);
1306             switch(sym_code) {
1307
1308             case S_skey:
1309                 entity->login = tac_strdup(sym_buf);
1310                 break;
1311
1312             case S_nopasswd:
1313                 /* set to dummy string, so that we detect a duplicate
1314                  * password definition attempt
1315                  */
1316                 entity->login = tac_strdup(nopasswd_str);
1317                 entity->nopasswd = 1;
1318                 break;
1319
1320             case S_file:
1321             case S_cleartext:
1322             case S_des:
1323 #ifdef USE_PAM
1324             case S_pam:
1325 #endif /* USE_PAM */
1326 #ifdef DB
1327             case S_db:
1328 #endif /* USE DB */
1329                 sprintf(buf, "%s ", sym_buf);
1330                 sym_get();
1331                 strcat(buf, sym_buf);
1332                 entity->login = tac_strdup(buf);
1333                 break;
1334
1335             default:
1336 #ifdef USE_PAM
1337                 parse_error(
1338  "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1339                             sym_line);
1340 #else
1341                 parse_error(
1342  "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
1343                             sym_line);
1344 #endif /* USE_PAM */
1345             }
1346             sym_get();
1347             continue;
1348
1349         case S_pap:
1350             if (entity->pap) {
1351                 parse_error("Duplicate value for %s %s and %s on line %d",
1352                             codestring(sym_code), entity->pap,
1353                             sym_buf, sym_line);
1354                 tac_exit(1);
1355             }
1356             sym_get();
1357             parse(S_separator);
1358             switch(sym_code) {
1359
1360             case S_cleartext:
1361             case S_des:
1362 #ifdef USE_PAM
1363             case S_pam:
1364 #endif /*USE_PAM */
1365                 sprintf(buf, "%s ", sym_buf);
1366                 sym_get();
1367                 strcat(buf, sym_buf);
1368                 entity->pap = tac_strdup(buf);
1369                 break;
1370
1371                 sprintf(buf, "%s ", sym_buf);
1372                 entity->pap = tac_strdup(buf);
1373                 break;
1374
1375             default:
1376 #ifdef USE_PAM
1377                 parse_error(
1378  "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d",
1379  sym_line);
1380 #else
1381                 parse_error(
1382  "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d",
1383  sym_line);
1384 #endif /*USE_PAM */
1385             }
1386             sym_get();
1387             continue;
1388
1389         case S_name:
1390             ASSIGN(entity->full_name);
1391             sym_get();
1392             continue;
1393
1394         case S_expires:
1395             ASSIGN(entity->expires);
1396             sym_get();
1397             continue;
1398
1399         case S_message:
1400             ASSIGN(entity->msg);
1401             sym_get();
1402             continue;
1403
1404         case S_arap:
1405         case S_chap:
1406 #ifdef MSCHAP
1407         case S_mschap:
1408 #endif /* MSCHAP */
1409         case S_opap:
1410         case S_global:
1411             save_sym = sym_code;
1412             sym_get();
1413             parse(S_separator);
1414             sprintf(buf, "%s ", sym_buf);
1415             parse(S_cleartext);
1416             strcat(buf, sym_buf);
1417
1418             switch (save_sym) {
1419             case S_arap:
1420                 fieldp = &entity->arap;
1421                 break;
1422             case S_chap:
1423                 fieldp = &entity->chap;
1424                 break;
1425 #ifdef MSCHAP
1426             case S_mschap:
1427                 fieldp = &entity->mschap;
1428                 break;
1429 #endif /* MSCHAP */
1430             case S_pap:
1431                 fieldp = &entity->pap;
1432                 break;
1433             case S_opap:
1434                 fieldp = &entity->opap;
1435                 break;
1436             case S_global:
1437                 fieldp = &entity->global;
1438                 break;
1439             default:
1440                 report(LOG_ERR, "INTERNAL: fieldp not recognized (on line %d)",
1441                         sym_line);
1442                 continue;
1443             }
1444
1445             if (*fieldp) {
1446                 parse_error("Duplicate value for %s %s and %s on line %d",
1447                             codestring(save_sym), *fieldp, sym_buf, sym_line);
1448                 tac_exit(1);
1449             }
1450             *fieldp = tac_strdup(buf);
1451             sym_get();
1452             continue;
1453
1454         case S_closebra:
1455             parse(S_closebra);
1456             return (0);
1457
1458 #ifdef MAXSESS
1459         case S_maxsess:
1460             sym_get();
1461             parse(S_separator);
1462             if (sscanf(sym_buf, "%d", &entity->maxsess) != 1) {
1463                 parse_error("expecting integer, found '%s' on line %d",
1464                     sym_buf, sym_line);
1465             }
1466             sym_get();
1467             continue;
1468 #endif /* MAXSESS */
1469
1470         default:
1471             if (STREQ(sym_buf, "password")) {
1472                 fprintf(stderr,
1473                         "\npassword = <string> is obsolete. Use login = des <string>\n");
1474             }
1475
1476             if (parse_conditional_block_item(entity))
1477                 return (0);             /* error message already printed */
1478         }
1479     }
1480 }
1481
1482 static NODE *parse_svcs TAC_ARGS((void));
1483
1484 static NODE *
1485 parse_svcs()
1486 {
1487     NODE *result;
1488
1489     switch (sym_code) {
1490     default:
1491         return (NULL);
1492     case S_svc:
1493     case S_cmd:
1494         break;
1495     }
1496
1497     result = (NODE *) tac_malloc(sizeof(NODE));
1498
1499     bzero(result, sizeof(NODE));
1500     result->line = sym_line;
1501
1502     /* cmd declaration */
1503     if (sym_code == S_cmd) {
1504         parse(S_cmd);
1505         parse(S_separator);
1506         result->value = tac_strdup(sym_buf);
1507
1508         sym_get();
1509         parse(S_openbra);
1510
1511         result->value1 = parse_cmd_matches();
1512         result->type = N_svc_cmd;
1513         result->when = copy_current_when_decl();
1514         expr_sink_register(result->when);
1515
1516         parse(S_closebra);
1517
1518         result->next = parse_svcs();
1519         return (result);
1520     }
1521
1522     /* svc declaration */
1523     parse(S_svc);
1524     parse(S_separator);
1525     switch (sym_code) {
1526     default:
1527         parse_error("expecting service type but found %s on line %d",
1528                     sym_buf, sym_line);
1529         return (NULL);
1530
1531     case S_string:
1532         result->type = N_svc;
1533         /* should perhaps check that this is an allowable service name */
1534         result->value1 = tac_strdup(sym_buf);
1535         break;
1536     case S_exec:
1537         result->type = N_svc_exec;
1538         break;
1539     case S_arap:
1540         result->type = N_svc_arap;
1541         break;
1542     case S_slip:
1543         result->type = N_svc_slip;
1544         break;
1545     case S_ppp:
1546         result->type = N_svc_ppp;
1547         parse(S_ppp);
1548         parse(S_protocol);
1549         parse(S_separator);
1550         /* Should perhaps check that this is a known PPP protocol name */
1551         result->value1 = tac_strdup(sym_buf);
1552         break;
1553     }
1554     sym_get();
1555     parse(S_openbra);
1556
1557     result->dflt = parse_opt_attr_default();
1558     result->value = parse_attrs();
1559     result->when = copy_current_when_decl();
1560     expr_sink_register(result->when);
1561
1562     parse(S_closebra);
1563
1564     result->next = parse_svcs();
1565     return (result);
1566 }
1567
1568 /*  <cmd_match>  := <permission> <string> */
1569
1570 static NODE *parse_cmd_matches TAC_ARGS((void));
1571
1572 static NODE *
1573 parse_cmd_matches()
1574 {
1575     NODE *retval = NULL, **succp = &retval;
1576     NODE *result;
1577
1578     for (;;) {
1579         switch (sym_code) {
1580         default:
1581             return (retval);
1582
1583         case S_when:
1584             if (push_parsed_when_decl())
1585                 tac_exit(1);            /* no error return possibility */
1586             parse(S_openbra);
1587             result = parse_cmd_matches();
1588             parse(S_closebra);
1589             if (pop_when_decl())
1590                 tac_exit(1);            /* no error return possibility */
1591             break;
1592
1593         case S_permit:
1594         case S_deny:
1595
1596             result = (NODE *) tac_malloc(sizeof(NODE));
1597
1598             bzero(result, sizeof(NODE));
1599             result->line = sym_line;
1600
1601             result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
1602             result->value = tac_strdup(sym_buf);
1603
1604 #ifdef WITH_INCLUDED_REGEX
1605
1606             result->value1 = (void *) tac_regcomp(result->value);
1607
1608 #else /* WITH_INCLUDED_REGEX */
1609
1610             result->value1 = tac_malloc(sizeof(regex_t));
1611             if (regcomp(result->value1, result->value /* regex */, REG_NOSUB /* cflags */)) {
1612                 free(result->value1);
1613                 result->value1 = NULL;
1614             }
1615
1616 #endif /* WITH_INCLUDED_REGEX */
1617
1618             if (!result->value1) {
1619                 report(LOG_ERR, "in regular expression %s on line %d",
1620                        sym_buf, sym_line);
1621                 tac_exit(1);
1622             }
1623             sym_get();
1624
1625             result->when = copy_current_when_decl();
1626             expr_sink_register(result->when);
1627
1628             result->next = NULL;
1629         }
1630         *succp = result;
1631         while (result->next)
1632             result = result->next;      /* skip parsed chain from parse_cmd_matches() */
1633         succp = &result->next;
1634     }
1635     /* NOTREACHED */
1636 }
1637
1638 static NODE *parse_attrs TAC_ARGS((void));
1639
1640 static NODE *
1641 parse_attrs()
1642 {
1643     NODE *retval = NULL, **succp = &retval;
1644     NODE *result;
1645     char buf[MAX_INPUT_LINE_LEN];
1646     int optional;
1647
1648     for (;;) {
1649         optional = 0;
1650
1651         switch (sym_code) {
1652         case S_closebra:
1653             return (retval);
1654
1655         case S_when:
1656             if (push_parsed_when_decl())
1657                 tac_exit(1);            /* no error return possibility */
1658             parse(S_openbra);
1659             result = parse_attrs();
1660             parse(S_closebra);
1661             if (pop_when_decl())
1662                 tac_exit(1);            /* no error return possibility */
1663             break;
1664
1665         case S_optional:
1666             optional = 1;
1667             sym_get();
1668             /* FALLTHRU */
1669         default:
1670             result = (NODE *) tac_malloc(sizeof(NODE));
1671
1672             bzero(result, sizeof(NODE));
1673             result->line = sym_line;
1674
1675             result->type = optional ? N_optarg : N_arg;
1676
1677             strcpy(buf, sym_buf);
1678             parse(S_string);
1679             strcat(buf, sym_buf);
1680             parse(S_separator);
1681             strcat(buf, sym_buf);
1682             parse(S_string);
1683
1684             result->value = tac_strdup(buf);
1685
1686             result->when = copy_current_when_decl();
1687             expr_sink_register(result->when);
1688
1689             result->next = NULL;
1690         }
1691         *succp = result;
1692         while (result->next)
1693             result = result->next;      /* skip parsed chain from parse_attrs() */
1694         succp = &result->next;
1695     }
1696     /* NOTREACHED */
1697 }
1698
1699
1700 static void sym_get TAC_ARGS((void));
1701
1702 static void
1703 sym_get()
1704 {
1705     getsym();
1706
1707     if (debug & DEBUG_PARSE_FLAG) {
1708         report(LOG_DEBUG, "line=%d sym=%s code=%d buf='%s'",
1709                sym_line, codestring(sym_code), sym_code, sym_buf);
1710     }
1711 }
1712
1713 static char *sym_buf_add TAC_ARGS((int c));
1714
1715 static char *
1716 sym_buf_add(c)
1717 int c;                          /* promoted "char" type */
1718 {
1719     if (sym_pos >= MAX_INPUT_LINE_LEN) {
1720         sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
1721         if (debug & DEBUG_PARSE_FLAG) {
1722             report(LOG_DEBUG, "line too long: line=%d sym=%s code=%d buf='%s'",
1723                    sym_line, codestring(sym_code), sym_code, sym_buf);
1724         }
1725         return(NULL);
1726     }
1727
1728     sym_buf[sym_pos++] = c;
1729     return(sym_buf);
1730 }
1731
1732 static void getsym TAC_ARGS((void));
1733
1734 static void
1735 getsym()
1736 {
1737
1738 next:
1739     switch (sym_ch) {
1740
1741     case EOF:
1742         sym_code = S_eof;
1743         return;
1744
1745     case '\n':
1746         sym_line++;
1747         rch();
1748         goto next;
1749
1750     case '\t':
1751     case ' ':
1752         while (sym_ch == ' ' || sym_ch == '\t')
1753             rch();
1754         goto next;
1755
1756     case '=':
1757         strcpy(sym_buf, "=");
1758         sym_code = S_separator;
1759         rch();
1760         return;
1761
1762     case '{':
1763         strcpy(sym_buf, "{");
1764         sym_code = S_openbra;
1765         rch();
1766         return;
1767
1768     case '}':
1769         strcpy(sym_buf, "}");
1770         sym_code = S_closebra;
1771         rch();
1772         return;
1773
1774     case '(':
1775         strcpy(sym_buf, "(");
1776         sym_code = S_openparen;
1777         rch();
1778         return;
1779
1780     case ')':
1781         strcpy(sym_buf, ")");
1782         sym_code = S_closeparen;
1783         rch();
1784         return;
1785
1786     case '#':
1787         while ((sym_ch != '\n') && (sym_ch != EOF))
1788             rch();
1789         goto next;
1790
1791     case '"':
1792         rch();
1793         sym_pos = 0;
1794         while (1) {
1795
1796             if (sym_ch == '"') {
1797                 break;
1798             }
1799
1800             /* backslash-double-quote is supported inside strings */
1801             /* also allow \n */
1802             if (sym_ch == '\\') {
1803                 rch();
1804                 switch (sym_ch) {
1805                 case 'n':
1806                     /* preserve the slash for \n */
1807                     if (!sym_buf_add('\\')) {
1808                         sym_code = S_unknown;
1809                         rch();
1810                         return;
1811                     }
1812
1813                     /* fall through */
1814                 case '"':
1815                     if (!sym_buf_add(sym_ch)) {
1816                         sym_code = S_unknown;
1817                         rch();
1818                         return;
1819                     }
1820                     rch();
1821                     continue;
1822                 default:
1823                     sym_code = S_unknown;
1824                     rch();
1825                     return;
1826                 }
1827             }
1828             if (!sym_buf_add(sym_ch)) {
1829                 sym_code = S_unknown;
1830                 rch();
1831                 return;
1832             }
1833             rch();
1834         }
1835         rch();
1836
1837         if (!sym_buf_add('\0')) {
1838             sym_code = S_unknown;
1839             rch();
1840             return;
1841         }
1842         sym_code = S_string;
1843         return;
1844
1845     default:
1846         sym_pos = 0;
1847         while (sym_ch != '\t' && sym_ch != ' ' && sym_ch != '='
1848                && sym_ch != '\n') {
1849
1850             if (!sym_buf_add(sym_ch)) {
1851                 sym_code = S_unknown;
1852                 rch();
1853                 return;
1854             }
1855             rch();
1856         }
1857
1858         if (!sym_buf_add('\0')) {
1859             sym_code = S_unknown;
1860             rch();
1861             return;
1862         }
1863         sym_code = keycode(sym_buf);
1864         if (sym_code == S_unknown)
1865             sym_code = S_string;
1866         return;
1867     }
1868 }
1869
1870 static void rch TAC_ARGS((void));
1871
1872 static void
1873 rch()
1874 {
1875     if (sym_error) {
1876         sym_ch = EOF;
1877         return;
1878     }
1879     sym_ch = getc(cf);
1880
1881     if (parse_only && sym_ch != EOF)
1882         fprintf(stderr, "%c", sym_ch);
1883 }
1884
1885
1886 static VALUE get_value TAC_ARGS((ENTITY *entity, int field));
1887
1888 /* Find the value of a field. Does not recurse. */
1889 static VALUE
1890 get_value(entity, field)
1891 ENTITY *entity;
1892 int field;
1893 {
1894     VALUE v;
1895
1896     v.pval = NULL;      /* do both just for sure... */
1897     v.intval = 0;
1898
1899     if (!entity) {
1900         parse_error("get_value: illegal entity");
1901         return (v);
1902     }
1903     switch (field) {
1904
1905     case S_name:
1906         v.pval = entity->name;
1907         break;
1908
1909     case S_login:
1910         v.pval = entity->login;
1911         break;
1912
1913     case S_global:
1914         v.pval = entity->global;
1915         break;
1916
1917     case S_expires:
1918         v.pval = entity->expires;
1919         break;
1920
1921     case S_arap:
1922         v.pval = entity->arap;
1923         break;
1924
1925     case S_chap:
1926         v.pval = entity->chap;
1927         break;
1928
1929 #ifdef MSCHAP
1930     case S_mschap:
1931         v.pval = entity->mschap;
1932         break;
1933 #endif /* MSCHAP */
1934
1935     case S_pap:
1936         v.pval = entity->pap;
1937         break;
1938
1939     case S_opap:
1940         v.pval = entity->opap;
1941         break;
1942
1943     case S_message:
1944         v.pval = entity->msg;
1945         break;
1946
1947     case S_svc:
1948         v.pval = entity->svcs;
1949         break;
1950
1951     case S_before:
1952         v.pval = entity->before_author;
1953         break;
1954
1955     case S_after:
1956         v.pval = entity->after_author;
1957         break;
1958
1959     case S_svc_dflt:
1960         v.intval = entity->svc_dflt;
1961         break;
1962
1963 #ifdef MAXSESS
1964     case S_maxsess:
1965         v.intval = entity->maxsess;
1966         break;
1967 #endif
1968
1969     case S_nopasswd:
1970         v.intval = entity->nopasswd;
1971         break;
1972
1973     case S_time:
1974         v.pval = entity->time;
1975         break;
1976
1977     case S_key:
1978         if (entity->type == S_user) {
1979             report(LOG_ERR, "get_value: S_key field not supported in %s %s",
1980                         entity_type_to_string(entity->type), entity->name);
1981             v.pval = NULL;
1982             return(v);
1983         }
1984         v.pval = entity->key;
1985         break;
1986
1987     default:
1988         report(LOG_ERR, "get_value: unknown field %d", field);
1989         break;
1990     }
1991     return (v);
1992 }
1993
1994
1995 /* Internal graph scanning routines */
1996
1997 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));
1998
1999 static enum value_scan_func_result
2000 value_scan(type, name, recurse, func, func_data)
2001 int type;
2002 const char *name;
2003 int recurse;
2004 value_scan_func_t func;
2005 void *func_data;
2006 {
2007     ENTITY *entity;
2008
2009     if (debug & DEBUG_CONFIG_FLAG)
2010         report(LOG_DEBUG, "value_scan: find %s %s, recurse=%d",
2011                 entity_type_to_string(type), name, recurse);
2012
2013     entity = entity_lookup(type, name);
2014     if (!entity) {
2015         if (debug & DEBUG_CONFIG_FLAG)
2016             report(LOG_DEBUG, "value_scan: no %s named %s",
2017                     entity_type_to_string(type), name);
2018         return (VSFR_CONTINUE);
2019     }
2020
2021     return (value_scan_entity(entity, recurse, func, func_data));
2022 }
2023
2024 /* For each user, check she doesn't circularly reference a
2025    group. Return 1 if it does */
2026
2027 static int circularity_check_failed;
2028
2029 static void circularity_check_fail TAC_ARGS((struct membership *membership));
2030
2031 static void
2032 circularity_check_fail(membership)
2033 struct membership *membership;
2034 {
2035     ENTITY *entity;
2036
2037     circularity_check_failed = 1;
2038
2039     report(LOG_ERR, "recursively defined groups:");
2040     while (membership) {
2041         entity = MEMBERSHIP_TO_CHILD_ENTITY(membership);
2042         report(LOG_ERR, "%s %s",
2043                 entity_type_to_string(entity->type), entity->name);
2044         membership = value_scan_backward(entity);
2045     }
2046 }
2047
2048 static enum value_scan_func_result circularity_check_func TAC_ARGS((ENTITY *entity, void *func_data));
2049
2050 static enum value_scan_func_result
2051 circularity_check_func(entity, func_data /* unused */)
2052 ENTITY *entity;
2053 void *func_data;
2054 {
2055     /* only useful to speedup case of failure */
2056     if (circularity_check_failed)
2057         return (VSFR_FOUND);
2058
2059     return (VSFR_CONTINUE);
2060 }
2061
2062 static int circularity_check TAC_ARGS((void));
2063
2064 static int
2065 circularity_check()
2066 {
2067     ENTITY *entity;
2068     ENTITY **users_base = (ENTITY **) hash_get_entries(usertable);
2069     ENTITY **users;
2070
2071     /* users */
2072     for (users = users_base; *users; users++) {
2073         entity = *users;
2074
2075         if (debug & DEBUG_PARSE_FLAG)
2076             report(LOG_DEBUG, "circularity_check: user=%s", entity->name);
2077
2078         circularity_check_failed = 0;
2079         value_scan_forward_seen_hook = circularity_check_fail;
2080         value_scan_entity(entity, TAC_PLUS_RECURSE,
2081                 (value_scan_func_t) circularity_check_func, NULL /* func_data-unused */);
2082         value_scan_forward_seen_hook = NULL;
2083         if (circularity_check_failed)
2084             break;
2085     }
2086     free(users_base);
2087     return (circularity_check_failed);
2088 }
2089
2090
2091 /* Return a value for a group or user (isuser says if
2092    this name is a group or a user name).
2093
2094    If no value exists, and recurse is true, also check groups we are a
2095    member of, recursively.
2096
2097    Returns void * because it can return a string or a node pointer
2098    (should really return a union pointer).
2099 */
2100
2101 static VALUE cfg_get_value_VALUE;       /* private */
2102
2103 static enum value_scan_func_result cfg_get_value_func TAC_ARGS((ENTITY *entity, int *attrp));
2104
2105 static enum value_scan_func_result
2106 cfg_get_value_func(entity,attrp /* func_data */)
2107 ENTITY *entity;
2108 int *attrp;
2109 {
2110     /* found the entry. Lookup value from attr=value */
2111     cfg_get_value_VALUE = get_value(entity, *attrp);
2112     if (cfg_get_value_VALUE.pval)
2113         return (VSFR_FOUND);
2114
2115     return (VSFR_CONTINUE);
2116 }
2117
2118 static VALUE cfg_get_value TAC_ARGS((int type, const char *name, int attr, int recurse));
2119
2120 static VALUE
2121 cfg_get_value(type, name, attr, recurse)
2122 int type;
2123 const char *name;
2124 int attr, recurse;
2125 {
2126     if (debug & DEBUG_CONFIG_FLAG)
2127         report(LOG_DEBUG, "cfg_get_value: type=%s name=%s attr=%s recurse=%d",
2128                entity_type_to_string(type), name, codestring(attr), recurse);
2129
2130     cfg_get_value_VALUE.pval = NULL;
2131     value_scan(type, name, recurse,
2132                 (value_scan_func_t) cfg_get_value_func, &attr /* func_data */);
2133     return (cfg_get_value_VALUE);
2134 }
2135
2136
2137 /* Wrappers for cfg_get_value:
2138  */
2139
2140 int cfg_get_intvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2141
2142 int
2143 cfg_get_intvalue(type, name, attr, recurse)
2144 int type;
2145 const char *name;
2146 int attr, recurse;
2147 {
2148     int val = cfg_get_value(type, name, attr, recurse).intval;
2149
2150     if (debug & DEBUG_CONFIG_FLAG)
2151         report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
2152     return(val);
2153 }
2154
2155 const char *cfg_get_pvalue TAC_ARGS((int type, const char *name, int attr, int recurse));
2156
2157 const char *
2158 cfg_get_pvalue(type, name, attr, recurse)
2159 int type;
2160 const char *name;
2161 int attr, recurse;
2162 {
2163     char *p = cfg_get_value(type, name, attr, recurse).pval;
2164
2165     if (debug & DEBUG_CONFIG_FLAG)
2166         report(LOG_DEBUG, "cfg_get_pvalue: returns %s",
2167                 p ? p : "NULL");
2168     return(p);
2169 }
2170
2171 /* Read the config file and do some basic sanity checking on
2172  * it. Return 1 if we find any errors.
2173  */
2174 int cfg_read_config TAC_ARGS((const char *cfile));
2175
2176 int
2177 cfg_read_config(cfile)
2178 const char *cfile;
2179 {
2180     sym_line = 1;
2181
2182     if ((cf = fopen(cfile, "r")) == NULL) {
2183         report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting",
2184                cfile, sys_errlist[errno]);
2185         return (1);
2186     }
2187     if (parse_decls() || sym_error) {
2188         fclose(cf);
2189         return (1);
2190     }
2191
2192     if (0
2193      || enlist_entity_connect()
2194      || expr_sink_commit()
2195             /* circularity is allowed in the new fully-recursive algorithm */
2196      || (!algorithm_recursive && circularity_check())
2197         ) {
2198         fclose(cf);
2199         return (1);
2200     }
2201     if (!when_expr_root || when_expr_root->type!=S_and || when_expr_root->u.and_or.child_first) {
2202         report(LOG_ERR, "Some 'when' expression found still pushed on stack");
2203         fclose(cf);
2204         return (1);
2205     }
2206
2207     fclose(cf);
2208     return (0);
2209 }
2210
2211 /* return 1 if user exists, 0 otherwise
2212  */
2213 int cfg_user_exists TAC_ARGS((const char *username));
2214
2215 int
2216 cfg_user_exists(username)
2217 const char *username;
2218 {
2219     return (NULL != hash_lookup(usertable, username));
2220 }
2221
2222 /* return expiry string of user. If none, try groups she is a member
2223  * on, and so on, recursively if recurse is non-zero
2224  */
2225 const char *cfg_get_expires TAC_ARGS((const char *username, int recurse));
2226
2227 const char *
2228 cfg_get_expires(username, recurse)
2229 const char *username;
2230 int recurse;
2231 {
2232     return (cfg_get_pvalue(S_user, username, S_expires, recurse));
2233 }
2234
2235 /* return time string of user. If none, try groups she is a member
2236  * on, and so on, recursively if recurse is non-zero
2237  */
2238 const char *cfg_get_timestamp TAC_ARGS((const char *username, int recurse));
2239
2240 const char *
2241 cfg_get_timestamp(username, recurse)
2242 const char *username;
2243 int recurse;
2244 {
2245     return (cfg_get_pvalue(S_user, username, S_time, recurse));
2246 }
2247
2248 /* return password string of user. If none, try groups she is a member
2249  * on, and so on, recursively if recurse is non-zero
2250  */
2251 const char *cfg_get_login_secret TAC_ARGS((const char *user, int recurse));
2252
2253 const char *
2254 cfg_get_login_secret(user, recurse)
2255 const char *user;
2256 int recurse;
2257 {
2258     return (cfg_get_pvalue(S_user, user, S_login, recurse));
2259 }
2260
2261 /* return value of the nopasswd field. If none, try groups she is a member
2262  * on, and so on, recursively if recurse is non-zero
2263  */
2264 int cfg_get_user_nopasswd TAC_ARGS((const char *user, int recurse));
2265
2266 int
2267 cfg_get_user_nopasswd(user, recurse)
2268 const char *user;
2269 int recurse;
2270 {
2271     return (cfg_get_intvalue(S_user, user, S_nopasswd, recurse));
2272 }
2273
2274 /* return user's secret. If none, try groups she is a member
2275  * on, and so on, recursively if recurse is non-zero
2276  */
2277 const char *cfg_get_arap_secret TAC_ARGS((const char *user, int recurse));
2278
2279 const char *
2280 cfg_get_arap_secret(user, recurse)
2281 const char *user;
2282 int recurse;
2283 {
2284     return (cfg_get_pvalue(S_user, user, S_arap, recurse));
2285 }
2286
2287 const char *cfg_get_chap_secret TAC_ARGS((const char *user, int recurse));
2288
2289 const char *
2290 cfg_get_chap_secret(user, recurse)
2291 const char *user;
2292 int recurse;
2293 {
2294     return (cfg_get_pvalue(S_user, user, S_chap, recurse));
2295 }
2296
2297 #ifdef MSCHAP
2298
2299 const char *cfg_get_mschap_secret TAC_ARGS((const char *user, int recurse));
2300
2301 const char *
2302 cfg_get_mschap_secret(user, recurse)
2303 const char *user;
2304 int recurse;
2305 {
2306     return (cfg_get_pvalue(S_user, user, S_mschap, recurse));
2307 }
2308
2309 #endif /* MSCHAP */
2310
2311 const char *cfg_get_pap_secret TAC_ARGS((const char *user, int recurse));
2312
2313 const char *
2314 cfg_get_pap_secret(user, recurse)
2315 const char *user;
2316 int recurse;
2317 {
2318     return (cfg_get_pvalue(S_user, user, S_pap, recurse));
2319 }
2320
2321 const char *cfg_get_opap_secret TAC_ARGS((const char *user, int recurse));
2322
2323 const char *
2324 cfg_get_opap_secret(user, recurse)
2325 const char *user;
2326 int recurse;
2327 {
2328     return (cfg_get_pvalue(S_user, user, S_opap, recurse));
2329 }
2330
2331 /* return the global password for the user (or the group, etc.) */
2332
2333 const char *cfg_get_global_secret TAC_ARGS((const char *user, int recurse));
2334
2335 const char *
2336 cfg_get_global_secret(user, recurse)
2337 const char *user;
2338 int recurse;
2339 {
2340     return (cfg_get_pvalue(S_user, user, S_global, recurse));
2341 }
2342
2343 #ifdef USE_PAM
2344
2345 /* Return a pointer to a node representing a PAM Service name */
2346
2347 const char *cfg_get_pam_service TAC_ARGS((const char *user, int recurse));
2348
2349 const char *
2350 cfg_get_pam_service(user, recurse)
2351 const char *user;
2352 int recurse;
2353 {
2354     const char *cfg_passwd;
2355     const char *p;
2356
2357     cfg_passwd = cfg_get_pap_secret(user, recurse);
2358
2359     if (!cfg_passwd)
2360         cfg_passwd = cfg_get_global_secret(user, recurse);
2361
2362     if (!cfg_passwd && !cfg_user_exists(user)) {
2363         cfg_passwd = cfg_get_authen_default();
2364         switch (cfg_get_authen_default_method()) {
2365
2366         case (S_pam):
2367             if (debug & DEBUG_AUTHOR_FLAG)
2368                 report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
2369             return(cfg_passwd);
2370             break;
2371
2372         default:
2373             if (debug & DEBUG_AUTHOR_FLAG)
2374                 report(LOG_DEBUG, "I havent find any PAM Service!!");
2375             return(NULL);/* Haven't any PAM Service!! */
2376         }
2377     }
2378
2379     p = tac_find_substring("pam ", cfg_passwd);
2380
2381     if(p) {  /* We find PAM services */
2382         if (debug & DEBUG_AUTHOR_FLAG)
2383                 report(LOG_DEBUG, "I get PAM sevice:%s",p);
2384         return (p);
2385     }
2386
2387     if (debug & DEBUG_AUTHOR_FLAG)
2388         report(LOG_DEBUG, "No any PAM Sevice");
2389
2390     return(NULL);
2391 }
2392
2393 #endif /* For PAM */
2394
2395
2396 /* Return a pointer to a node representing a given service
2397    authorization, taking care of recursion issues correctly. Protocol
2398    is only read if the svctype is N_svc_ppp. svcname is only read if type
2399    is N_svc.
2400 */
2401
2402 struct cfg_get_svc_node_param {
2403     int svctype;
2404     const char *protocol, *svcname;
2405     NODE *node;
2406     int retval;
2407 };
2408
2409 static enum value_scan_func_result cfg_get_svc_node_func TAC_ARGS((ENTITY *entity, struct cfg_get_svc_node_param *param));
2410
2411 static enum value_scan_func_result
2412 cfg_get_svc_node_func(entity, param /* func_data */)
2413 ENTITY *entity;
2414 struct cfg_get_svc_node_param *param;
2415 {
2416     NODE *svc;
2417     enum eval_result svc_default;
2418
2419     for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2420         if (svc->type != param->svctype)
2421             continue;
2422         if (param->svctype == N_svc_ppp && param->protocol && !STREQ(svc->value1, param->protocol))
2423             continue;
2424         if (param->svctype == N_svc     && param->svcname  && !STREQ(svc->value1, param->svcname ))
2425             continue;
2426         if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
2427             continue;
2428
2429         if (debug & DEBUG_CONFIG_FLAG)
2430             report(LOG_DEBUG,
2431                    "cfg_get_svc_node: found %s proto=%s svcname=%s",
2432                    cfg_nodestring(param->svctype),
2433                    param->protocol ? param->protocol : "",
2434                    param->svcname ? param->svcname : "");
2435
2436         param->node = svc;
2437         param->retval = 1;
2438         return (VSFR_FOUND);
2439     }
2440
2441     /* look at 'default service' settings */
2442     svc_default = entity_svc_default(entity);
2443     switch (svc_default) {
2444
2445     case ER_TRUE:
2446     case ER_FALSE:
2447         if (debug & DEBUG_AUTHOR_FLAG)
2448             report(LOG_DEBUG,
2449            "cfg_get_svc_node: svc=%s protocol=%s svcname=%s forced %s by default service",
2450                    cfg_nodestring(param->svctype),
2451                    param->protocol ? param->protocol : "",
2452                    param->svcname ? param->svcname : "",
2453                    (svc_default == ER_TRUE ? "permit" : "deny"));
2454
2455         param->retval = (svc_default == ER_TRUE);
2456         return (VSFR_FOUND);
2457
2458     default:    /* shouldn't happen */
2459     case ER_UNKNOWN:
2460         return (VSFR_CONTINUE);
2461     }
2462     /* NOTREACHED */
2463 }
2464
2465 int cfg_get_svc_node TAC_ARGS((const char *username, int svctype, const char *protocol, const char *svcname, int recurse, NODE **nodep));
2466
2467 int
2468 cfg_get_svc_node(username, svctype, protocol, svcname, recurse, nodep)
2469 const char *username;
2470 int svctype;
2471 const char *protocol;
2472 const char *svcname;
2473 int recurse;
2474 NODE **nodep;
2475 {
2476     struct cfg_get_svc_node_param param;
2477     enum value_scan_func_result vsfr;
2478
2479     param.svctype = svctype;
2480     param.protocol = protocol;
2481     param.svcname = svcname;
2482     param.node = NULL;
2483     param.retval = 0;
2484
2485     if (debug & DEBUG_CONFIG_FLAG)
2486         report(LOG_DEBUG,
2487                "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
2488                username,
2489                cfg_nodestring(svctype),
2490                protocol ? protocol : "",
2491                svcname ? svcname : "",
2492                recurse);
2493
2494     vsfr = value_scan(S_user, username, recurse,
2495                 (value_scan_func_t) cfg_get_svc_node_func, &param /* func_data */);
2496     if (nodep)
2497         *nodep = param.node;
2498
2499     if (vsfr == VSFR_FOUND)
2500         return (param.retval);
2501
2502     /* The service does not exist. Do the default */
2503     return (cfg_no_user_permitted() ? 1 : 0);
2504 }
2505
2506 /* Return a pointer to the node representing a set of command tac_regexp
2507    matches for a user and command, handling recursion issues correctly */
2508
2509 struct cfg_authorize_cmd_param {
2510     const char *cmd;
2511     const char *args;
2512     enum eval_result result;
2513 };
2514
2515 static enum value_scan_func_result cfg_authorize_cmd_func TAC_ARGS((ENTITY *entity, struct cfg_authorize_cmd_param *param));
2516
2517 static enum value_scan_func_result
2518 cfg_authorize_cmd_func(entity, param /* func_data */)
2519 ENTITY *entity;
2520 struct cfg_authorize_cmd_param *param;
2521 {
2522     NODE *svc;
2523
2524     for (svc = (NODE *) get_value(entity, S_svc).pval; svc; svc = svc->next) {
2525         NODE *node;
2526
2527         if (svc->type != N_svc_cmd)
2528             continue;
2529         if (!STREQ(svc->value, param->cmd))
2530             continue;
2531         if (expr_eval(svc->when) != ER_TRUE)    /* expensive */
2532             continue;
2533
2534         if (debug & DEBUG_CONFIG_FLAG)
2535             report(LOG_DEBUG, "cfg_authorize_cmd: found cmd %s %s node",
2536                    param->cmd, cfg_nodestring(svc->type));
2537
2538         /* we have 'cmd <openbra>' point, now traverse through its 'permit'/'deny' pairs: */
2539
2540         for (node = svc->value1; node; node = node->next) {
2541             int match;
2542
2543             if (expr_eval(node->when) != ER_TRUE)               /* expensive */
2544                 continue;
2545
2546 #ifdef WITH_INCLUDED_REGEX
2547
2548             match = tac_regexec((tac_regexp *) node->value1, param->args);
2549
2550 #else /* WITH_INCLUDED_REGEX */
2551
2552             match = !regexec((const regex_t *) node->value1, param->args /* string */,
2553                     0 /* nmatch */, NULL /* pmatch */, 0 /* eflags */);
2554
2555 #endif /* WITH_INCLUDED_REGEX */
2556
2557             if (debug & DEBUG_AUTHOR_FLAG) {
2558                 report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
2559                        node->line, param->cmd,
2560                        node->type == N_permit ? "permit" : "deny",
2561                        (const char *) node->value, param->args, (match ? "" : "no "));
2562             }
2563
2564             if (!match)
2565                 continue;
2566
2567             switch (node->type) {
2568             case N_permit:
2569                 if (debug & DEBUG_AUTHOR_FLAG) {
2570                     report(LOG_DEBUG, "%s %s permitted by line %d",
2571                            param->cmd, param->args, node->line);
2572                 }
2573                 param->result = ER_TRUE;
2574                 return (VSFR_FOUND);
2575                 break;
2576             case N_deny:
2577                 if (debug & DEBUG_AUTHOR_FLAG) {
2578                     report(LOG_DEBUG, "%s %s denied by line %d",
2579                            param->cmd, param->args, node->line);
2580                 }
2581                 param->result = ER_FALSE;
2582                 return (VSFR_FOUND);
2583                 break;
2584             default:
2585                 report(LOG_ERR, "INTERNAL: illegal configuration node: %s: %s %s",
2586                        session.peer, param->cmd, param->args);
2587                 param->result = ER_UNKNOWN;     /* error */
2588                 return (VSFR_FOUND);
2589             }
2590         }
2591         if (!algorithm_recursive) {     /* compatibility mode: */
2592             if (debug & DEBUG_AUTHOR_FLAG)
2593                 report(LOG_DEBUG, "cmd %s exists, but no args match, denied (as no 'authorization = recursive' found)",
2594                         param->cmd);
2595             param->result = ER_FALSE;   /* emulate last "deny .*" */
2596             return (VSFR_FOUND);
2597         }
2598     }
2599
2600     /* look at 'default service' settings */
2601     param->result = entity_svc_default(entity);
2602     switch (param->result) {
2603
2604     case ER_TRUE:
2605         if (debug & DEBUG_AUTHOR_FLAG)
2606             report(LOG_DEBUG, "cmd %s does not exist, permitted by default", param->cmd);
2607         return (VSFR_FOUND);
2608
2609     case ER_FALSE:
2610
2611         if (debug & DEBUG_AUTHOR_FLAG)
2612             report(LOG_DEBUG, "cmd %s does not exist, denied by default", param->cmd);
2613         return (VSFR_FOUND);
2614
2615     default:    /* shouldn't happen */
2616     case ER_UNKNOWN:
2617         return (VSFR_CONTINUE);
2618     }
2619     /* NOTREACHED */
2620 }
2621
2622 enum eval_result cfg_authorize_cmd TAC_ARGS((const char *username, const char *cmd, const char *args));
2623
2624 enum eval_result
2625 cfg_authorize_cmd(username, cmd, args)
2626 const char *username;
2627 const char *cmd;
2628 const char *args;
2629 {
2630     struct cfg_authorize_cmd_param param;
2631
2632     param.cmd = cmd;
2633     param.args = args;
2634     param.result = ER_UNKNOWN;  /* error */
2635
2636     if (debug & DEBUG_CONFIG_FLAG)
2637         report(LOG_DEBUG, "cfg_authorize_cmd: name=%s cmdname=%s args=%s",
2638                username, cmd, args);
2639
2640     value_scan(S_user, username, TAC_PLUS_RECURSE,
2641                 (value_scan_func_t) cfg_authorize_cmd_func, &param /* func_data */);
2642
2643     if (param.result != ER_UNKNOWN)
2644         return (param.result);
2645
2646     /* The command does not exist. Do the default */
2647     return (cfg_no_user_permitted() ? ER_TRUE : ER_FALSE);
2648 }
2649
2650 /* Return an array of character strings representing configured AV
2651  * pairs, given a username and a service node.
2652  *
2653  * In the AV strings returned, manipulate the separator character to
2654  * indicate which args are optional and which are mandatory.
2655  *
2656  * Lastly, indicate what default permission was configured by setting
2657  * denyp */
2658
2659 char **cfg_get_svc_attrs TAC_ARGS((NODE *svcnode, int *denyp));
2660
2661 char **
2662 cfg_get_svc_attrs(svcnode, denyp)
2663 NODE *svcnode;
2664 int *denyp;
2665 {
2666     int i;
2667     NODE *node;
2668     char **args;
2669
2670     *denyp = 1;
2671
2672     if (!svcnode)
2673         return (NULL);
2674
2675     *denyp = (svcnode->dflt == S_deny);
2676
2677     i = 0;
2678     for (node = svcnode->value; node; node = node->next)
2679         i++;
2680
2681     args = (char **) tac_malloc(sizeof(char *) * (i + 1));
2682
2683     i = 0;
2684     for (node = svcnode->value; node; node = node->next) {
2685         char *arg;
2686         char *p;
2687
2688         if (expr_eval(node->when) != ER_TRUE)   /* expensive */
2689             continue;   /* ignore this node */
2690
2691         arg = tac_strdup(node->value);
2692         p = index(arg, '=');
2693         if (p && node->type == N_optarg)
2694             *p = '*';
2695         args[i++] = arg;
2696     }
2697     args[i] = NULL;
2698     return (args);
2699 }
2700
2701
2702 static enum eval_result entity_svc_default TAC_ARGS((ENTITY *entity));
2703
2704 static enum eval_result
2705 entity_svc_default(entity)
2706 ENTITY *entity;
2707 {
2708     switch (entity->svc_dflt) {
2709     case S_permit:
2710         return (ER_TRUE);
2711     case S_deny:
2712         return (ER_FALSE);
2713     case S_default:
2714     case 0:     /* not specified */
2715         return (ER_UNKNOWN);
2716     default:
2717         report(LOG_ERR, "INTERNAL: invalid entity svc_dflt (%d)", entity->svc_dflt);
2718         return (ER_UNKNOWN);
2719     }
2720 }
2721
2722 int cfg_no_user_permitted TAC_ARGS((void));
2723
2724 int
2725 cfg_no_user_permitted()
2726 {
2727     if (no_user_dflt == S_permit)
2728         return (1);
2729     return (0);
2730 }
2731
2732
2733 const char *cfg_get_authen_default TAC_ARGS((void));
2734
2735 const char *
2736 cfg_get_authen_default()
2737 {
2738     return (authen_default);
2739 }
2740
2741 int cfg_get_authen_default_method TAC_ARGS((void));
2742
2743 /* For describe authentication method(pam,file,db..etc) */
2744 int
2745 cfg_get_authen_default_method()
2746 {
2747    return (authen_default_method);
2748 }
2749
2750
2751 /* Host entity management:
2752  */
2753
2754 const char *cfg_get_host_key TAC_ARGS((const char *host));
2755
2756 /* For getting host key */
2757 const char *
2758 cfg_get_host_key(host)
2759 const char *host;
2760 {
2761     return (cfg_get_pvalue(S_host, host, S_key, algorithm_recursive /* recurse */));
2762 }
2763
2764 static ENTITY *force_belong_entity TAC_ARGS((int type, const char *name));
2765
2766 static ENTITY *
2767 force_belong_entity(type, name)
2768 int type;
2769 const char *name;
2770 {
2771     ENTITY *entity = entity_lookup(type, name);
2772
2773     if (entity)
2774         eval_force_belong_entity(entity);
2775
2776     return (entity);
2777 }
2778
2779 /* assumed existing initialized "session.peer*" */
2780
2781 static ENTITY *request_peer_addr;
2782 static ENTITY *request_peer;
2783 static ENTITY *request_DEFAULT_group;
2784
2785 static void enlist_request_peer TAC_ARGS((const char *hostname, ENTITY **entityp));
2786
2787 static void
2788 enlist_request_peer(hostname, entityp)
2789 const char *hostname;
2790 ENTITY **entityp;
2791 {
2792     *entityp = NULL;
2793     if (!hostname)
2794         return;
2795
2796     *entityp = force_belong_entity(S_host, hostname);
2797     if (*entityp && request_DEFAULT_group)
2798         virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, *entityp /* child */);
2799 }
2800
2801 /* Try to build the following scenery:
2802  * 
2803  * host <session.peer_addr> [=ER_TRUE]
2804  *  |
2805  *  +-- group <DEFAULT_GROUPNAME>
2806  *
2807  * host <session.peer     > [=ER_TRUE]
2808  *  |
2809  *  +-- group <DEFAULT_GROUPNAME>
2810  */
2811
2812 void cfg_request_scan_begin TAC_ARGS((void));
2813
2814 void
2815 cfg_request_scan_begin()
2816 {
2817     request_scan_begin();
2818
2819     request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2820
2821     if (session.peer_addr != session.peer)
2822         enlist_request_peer(session.peer_addr, &request_peer_addr);
2823     enlist_request_peer(session.peer, &request_peer);
2824 }
2825
2826 /* Try to build the following scenery:
2827  *
2828  * ( user <identity->username> |  user <DEFAULT_USERNAME> ) [=ER_TRUE]
2829  *  |
2830  *  +-- host <session.peer_addr> [=ER_TRUE]
2831  *  |    |
2832  *  |    +- group <DEFAULT_GROUPNAME>
2833  *  |
2834  *  +-- host <session.peer     > [=ER_TRUE]
2835  *  |    |
2836  *  |    +-- group <DEFAULT_GROUPNAME>
2837  *  |
2838  *  +-- group <DEFAULT_GROUPNAME>
2839  */
2840
2841 void cfg_request_identity TAC_ARGS((const struct identity *identity));
2842
2843 void
2844 cfg_request_identity(identity)
2845 const struct identity *identity;
2846 {
2847     ENTITY *user_entity = force_belong_entity(S_user, identity->username);
2848     ENTITY *request_DEFAULT_group = entity_lookup(S_group, DEFAULT_GROUPNAME);
2849
2850     if (!user_entity)
2851         user_entity = force_belong_entity(S_user, DEFAULT_USERNAME);
2852
2853     request_scan_user_known = 1;
2854
2855     if (!user_entity)
2856         return;
2857
2858     if (request_peer_addr)
2859         virtual_enlist_entity_direct(request_peer_addr     /* parent */, user_entity /* child */);
2860     if (request_peer     )
2861         virtual_enlist_entity_direct(request_peer          /* parent */, user_entity /* child */);
2862     if (request_DEFAULT_group)
2863         virtual_enlist_entity_direct(request_DEFAULT_group /* parent */, user_entity /* child */);
2864 }