6eaef534f58e7df2ac72197b279f19090c3f99a0
[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 #include "tac_plus.h"
21 #include <stdio.h>
22 #include <errno.h>
23 #include "regexp.h"
24
25 /*
26    <config>         := <decl>*
27
28    <decl>           := <top_level_decl> | <user_decl>
29
30    <top_level_decl> := <authen_default> |
31                        accounting file = <string>
32                        default authorization = permit |
33                        key = <string>
34
35    <authen_default> := default authentication = file <filename> 
36 #if defined(DB)
37                     | db <string> )
38 #endif
39    
40 <permission>     := permit | deny
41
42    <filename>       := <string>
43
44    <password>       := <string>
45
46    <user_decl>      := user = <string> {
47                         [ default service = [ permit | deny ] ]
48                         <user_attr>*
49                         <svc>*
50                    }
51
52    <password_spec>  := file <filename> | 
53                        skey | 
54                        cleartext <password> |
55                        des <password> |
56
57 #ifdef USE_PAM          
58                        pam <pam_service> |
59 #endif          
60 #if defined(DB)         
61                         db <string>
62 #endif
63                        nopassword
64
65    <user_attr>      :=   name     = <string> |
66                          login    = <password_spec> |
67                          member   = <string> |
68                          expires  = <string> |
69                          arap     = cleartext <string> |
70                          chap     = cleartext <string> |
71 #ifdef MSCHAP
72                          ms-chap  = cleartext <string> |
73 #endif
74                          pap      = cleartext <string> |
75                          pap      = des <string> |
76 #ifdef USE_PAM  
77                          pap      = pam <pam_service> |
78 #endif          
79                          opap     = cleartext <string> |
80                          global   = cleartext <string> |
81                          msg      = <string>
82                          before authorization = <string> |
83                          after authorization = <string>
84
85    <svc>            := <svc_auth> | <cmd_auth>
86
87    <cmd_auth>       := cmd = <string> {
88                         <cmd-match>*
89                     }
90
91    <cmd-match>      := <permission> <string>
92
93    <svc_auth>       := service = ( exec | arap | slip | ppp protocol = <string> {
94                         [ default attribute = permit ]
95                         <attr_value_pair>*
96                     }
97
98    <attr_value_pair> := [ optional ] <string> = <string>
99
100 */
101
102 static char sym_buf[MAX_INPUT_LINE_LEN];        /* parse buffer */
103 static int sym_pos=0;           /* current place in sym_buf */
104 static int sym_ch;              /* current parse character */
105 static int sym_code;            /* parser output */
106 static int sym_line = 1;        /* current line number for parsing */
107 static FILE *cf = NULL;         /* config file pointer */
108 static int sym_error = 0;       /* a parsing error has occurred */
109 static int no_user_dflt = 0;    /* default if user doesn't exist */
110 static char *authen_default = NULL;     /* top level authentication default */
111 static int authen_default_method = 0; /*For method check */
112 static char *nopasswd_str = "nopassword";
113
114 /* A host definition structure. Currently unused, but when we start
115    configuring host-specific information e.g. per-host keys, this is
116    where it should be kept.
117
118    The first 2 fields (name and hash) are used by the hash table
119    routines to hash this structure into a table.  Do not (re)move them */
120
121 struct host {
122     char *name;                 /* host name */
123     void *hash;                 /* hash table next pointer */
124     int line;                   /* line number defined on */
125     char *key;                  /* host spesific key */
126     char *type;                 /* host type         */
127 };
128
129 /* A user or group definition
130
131    The first 2 fields (name and hash) are used by the hash table
132    routines to hash this structure into a table.  Move them at your
133    peril */
134
135 struct user {
136     char *name;                 /* username */
137     void *hash;                 /* hash table next pointer */
138     int line;                   /* line number defined on */
139     long flags;                 /* flags field */
140
141 #define FLAG_ISUSER  1          /* this structure represents a user */
142 #define FLAG_ISGROUP 2          /* this structure represents a group */
143 #define FLAG_SEEN    4          /* for circular definition detection */
144
145     char *full_name;            /* users full name */
146     char *login;                /* Login password */
147     int nopasswd;               /* user requires no password */
148     char *global;               /* password to use if none set */
149     char *member;               /* group we are a member of */
150     char *expires;              /* expiration date */
151     char *arap;                 /* our arap secret */
152     char *pap;                  /* our pap secret */
153     char *opap;                 /* our outbound pap secret */
154     char *chap;                 /* our chap secret */
155 #ifdef MSCHAP
156     char *mschap;               /* our mschap secret */
157 #endif /* MSCHAP */
158     char *msg;                  /* a message for this user */
159     char *before_author;        /* command to run before authorization */
160     char *after_author;         /* command to run after authorization */
161     int svc_dflt;               /* default authorization behaviour for svc or
162                                  * cmd */
163     NODE *svcs;                 /* pointer to svc nodes */
164 #ifdef MAXSESS
165     int maxsess;                /* Max sessions/user */
166 #endif /* MAXSESS */
167     char *time;         /* Timestamp  */
168 };
169
170 typedef struct host HOST;
171 typedef struct user USER;
172
173 /* Only the first 2 fields (name and hash) are used by the hash table
174    routines to hashh structures into a table.
175 */
176
177 union hash {
178     struct user u;
179     struct host h;
180 };
181
182 typedef union hash HASH;
183
184 void *grouptable[HASH_TAB_SIZE];/* Table of group declarations */
185 void *usertable[HASH_TAB_SIZE]; /* Table of user declarations */
186 void *hosttable[HASH_TAB_SIZE]; /* Table of host declarations */
187
188
189 static void
190  sym_get();
191
192
193 #ifdef __STDC__
194 #include <stdarg.h>             /* ANSI C, variable length args */
195 static void
196 parse_error(char *fmt,...)
197 #else
198 #include <varargs.h>            /* has 'vararg' definitions */
199 /* VARARGS2 */
200 static void
201 parse_error(fmt, va_alist)
202 char *fmt;
203
204 va_dcl                          /* no terminating semi-colon */
205 #endif
206 {
207     char msg[256];              /* temporary string */
208     va_list ap;
209
210 #ifdef __STDC__
211     va_start(ap, fmt);
212 #else
213     va_start(ap);
214 #endif
215     vsprintf(msg, fmt, ap);
216     va_end(ap);
217
218     report(LOG_ERR, "%s", msg);
219     fprintf(stderr, "Error: %s\n", msg);
220     tac_exit(1);
221 }
222
223 char *
224 cfg_nodestring(type)
225     int type;
226 {
227     switch (type) {
228     default:
229         return ("unknown node type");
230     case N_arg:
231         return ("N_arg");
232     case N_optarg:
233         return ("N_optarg");
234     case N_svc:
235         return ("N_svc");
236     case N_svc_exec:
237         return ("N_svc_exec");
238     case N_svc_slip:
239         return ("N_svc_slip");
240     case N_svc_ppp:
241         return ("N_svc_ppp");
242     case N_svc_arap:
243         return ("N_svc_arap");
244     case N_svc_cmd:
245         return ("N_svc_cmd");
246     case N_permit:
247         return ("N_permit");
248     case N_deny:
249         return ("N_deny");
250     }
251 }
252
253 static void
254 free_attrs(node)
255 NODE *node;
256 {
257     NODE *next;
258
259     while (node) {
260         switch (node->type) {
261         case N_optarg:
262         case N_arg:
263             if (debug & DEBUG_CLEAN_FLAG)
264                 report(LOG_DEBUG, "free_cmd_match %s %s",
265                        cfg_nodestring(node->type),
266                        node->value);
267             break;
268         default:
269             report(LOG_ERR, "Illegal node type %s for free_attrs", 
270                    cfg_nodestring(node->type));
271             return;
272         }
273
274         free(node->value);
275         next = node->next;
276         free(node);
277         node = next;
278     }
279 }
280
281 static void
282 free_cmd_matches(node)
283 NODE *node;
284 {
285     NODE *next;
286
287     while (node) {
288         if (debug & DEBUG_CLEAN_FLAG)
289             report(LOG_DEBUG, "free_cmd_match %s %s",
290                    cfg_nodestring(node->type),
291                    node->value);
292
293         free(node->value);      /* text */
294         free(node->value1);     /* regexp compiled text */
295         next = node->next;
296         free(node);
297         node = next;
298     }
299 }
300
301 static void
302 free_svcs(node)
303 NODE *node;
304 {
305     NODE *next;
306
307     while (node) {
308
309         switch (node->type) {
310         case N_svc_cmd:
311             if (debug & DEBUG_CLEAN_FLAG)
312                 report(LOG_DEBUG, "free %s %s",
313                        cfg_nodestring(node->type), node->value);
314             free(node->value);  /* cmd name */
315             free_cmd_matches(node->value1);
316             next = node->next;
317             free(node);
318             node = next;
319             continue;
320
321         case N_svc:
322         case N_svc_ppp:
323             free(node->value1);
324             /* FALL-THROUGH */
325         case N_svc_exec:
326         case N_svc_arap:
327         case N_svc_slip:
328             if (debug & DEBUG_CLEAN_FLAG)
329                 report(LOG_DEBUG, "free %s", cfg_nodestring(node->type));
330             free_attrs(node->value);
331             next = node->next;
332             free(node);
333             node = next;
334             continue;
335
336         default:
337             report(LOG_ERR, "Illegal node type %d for free_svcs", node->type);
338             return;
339         }
340     }
341 }
342
343 static void
344 free_userstruct(user)
345 USER *user;
346 {
347     if (debug & DEBUG_CLEAN_FLAG)
348         report(LOG_DEBUG, "free %s %s",
349                (user->flags & FLAG_ISUSER) ? "user" : "group",
350                user->name);
351
352     if (user->name)
353         free(user->name);
354     if (user->full_name)
355         free(user->full_name);
356     if (user->login)
357         free(user->login);
358     if (user->member)
359         free(user->member);
360     if (user->expires)
361         free(user->expires);
362     if (user->time)
363         free(user->time);
364     if (user->arap)
365         free(user->arap);
366     if (user->chap)
367         free(user->chap);
368 #ifdef MSCHAP
369     if (user->mschap)
370         free(user->mschap);
371 #endif /* MSCHAP */
372     if (user->pap)
373         free(user->pap);
374     if (user->opap)
375         free(user->opap);
376     if (user->global)
377         free(user->global);
378     if (user->msg)
379         free(user->msg);
380     if (user->before_author)
381         free(user->before_author);
382     if (user->after_author)
383         free(user->after_author);
384     free_svcs(user->svcs);
385 }
386
387 static void
388 free_hoststruct(host)
389 HOST *host;
390 {
391     if (debug & DEBUG_CLEAN_FLAG)
392         report(LOG_DEBUG, "free %s",
393                 host->name);
394
395     if (host->name)
396         free(host->name);
397     
398     if (host->key)
399         free(host->key);
400     
401     if (host->type)
402         free(host->type);
403 }
404
405 /*
406  * Exported routines
407  */
408
409 /* Free all allocated structures preparatory to re-reading the config file */
410 void
411 cfg_clean_config()
412 {
413     int i;
414     USER *entry, *next;
415     HOST *host_entry,*hn;
416
417     if (authen_default) {
418         free(authen_default);
419         authen_default = NULL;
420     }
421    
422    if (authen_default_method) {
423         authen_default_method = 0;
424     }
425
426     if (session.key) {
427         free(session.key);
428         session.key = NULL;
429     }
430
431     if (session.acctfile) {
432         free(session.acctfile);
433         session.acctfile = NULL;
434     }
435     
436     if (session.db_acct) {
437         free(session.db_acct);
438         session.db_acct = NULL;
439     }
440
441     /* clean the hosttable */
442     for (i = 0; i < HASH_TAB_SIZE; i++) {
443         host_entry = (HOST *) hosttable[i];
444         while (host_entry) {
445             hn = host_entry->hash;
446             free_hoststruct(host_entry);
447             free(host_entry);
448             host_entry = hn;
449         }
450         hosttable[i] = NULL;
451     }
452
453     /* the grouptable */
454     for (i = 0; i < HASH_TAB_SIZE; i++) {
455         entry = (USER *) grouptable[i];
456         while (entry) {
457             next = entry->hash;
458             free_userstruct(entry);
459             free(entry);
460             entry = next;
461         }
462         grouptable[i] = NULL;
463     }
464
465     /* the usertable */
466     for (i = 0; i < HASH_TAB_SIZE; i++) {
467         entry = (USER *) usertable[i];
468         while (entry) {
469             next = entry->hash;
470             free_userstruct(entry);
471             free(entry);
472             entry = next;
473         }
474         usertable[i] = NULL;
475     }
476 }
477
478 static int
479 parse_permission()
480 {
481     int symbol = sym_code;
482
483     if (sym_code != S_permit && sym_code != S_deny) {
484         parse_error("expecting permit or deny but found '%s' on line %d",
485                     sym_buf, sym_line);
486         return (0);
487     }
488     sym_get();
489
490     return (symbol);
491 }
492
493 static int
494 parse(symbol)
495 int symbol;
496
497 {
498     if (sym_code != symbol) {
499         parse_error("expecting '%s' but found '%s' on line %d",
500                     (symbol == S_string ? "string" : codestring(symbol)),
501                     sym_buf, sym_line);
502         return (1);
503     }
504     sym_get();
505     return (0);
506 }
507
508 static int
509 parse_opt_svc_default()
510 {
511     if (sym_code != S_default) {
512         return (0);
513     }
514
515     parse(S_default);
516     parse(S_svc);
517     parse(S_separator);
518     if (sym_code == S_permit) {
519         parse(S_permit);
520         return (S_permit);
521     }
522     parse(S_deny);
523     return (S_deny);
524 }
525
526 static int
527 parse_opt_attr_default()
528 {
529     if (sym_code != S_default)
530         return (S_deny);
531
532     parse(S_default);
533     parse(S_attr);
534     parse(S_separator);
535     parse(S_permit);
536     return (S_permit);
537 }
538
539 static int parse_user();
540 static int parse_host();
541
542 static void
543  rch();
544
545 /*
546    Parse lines in the config file, creating data structures
547    Return 1 on error, otherwise 0 */
548
549 static int
550 parse_decls()
551 {
552     no_user_dflt = 0; /* default if user doesn't exist */
553
554     sym_code = 0;
555     rch();
556
557     bzero(grouptable, sizeof(grouptable));
558     bzero(usertable, sizeof(usertable));
559     bzero(hosttable, sizeof(hosttable)); 
560
561     sym_get();
562
563     /* Top level of parser */
564     while (1) {
565
566         switch (sym_code) {
567         case S_eof:
568             return (0);
569
570         case S_accounting:
571             sym_get();
572             parse(S_file);
573             parse(S_separator);
574             if (session.acctfile) 
575                 free(session.acctfile);
576             session.acctfile = tac_strdup(sym_buf);
577             sym_get();
578             continue;
579
580 #ifdef DB       
581         case S_db_accounting:
582             sym_get();
583             parse(S_separator);
584             if (session.db_acct) 
585                 free(session.db_acct);
586             session.db_acct = tac_strdup(sym_buf);
587             sym_get();
588             continue;
589 #endif
590
591         case S_default:
592             sym_get();
593             switch (sym_code) {
594             default:
595                 parse_error(
596                 "Expecting default authorization/authentication on lines %d",
597                             sym_line);
598                 return (1);
599
600             case S_authentication:
601                 if (authen_default) {
602                     parse_error(
603                     "Multiply defined authentication default on line %d",
604                                 sym_line);
605                     return (1);
606                 }
607                 parse(S_authentication);
608                 parse(S_separator);
609
610                 switch(sym_code) {
611                 
612                 case S_file:
613 #ifdef DB
614                 case S_db:
615 #endif
616 #ifdef USE_LDAP
617                 case S_ldap;
618 #endif
619 #ifdef USE_PAM
620                 case S_pam:
621 #endif
622                 authen_default_method = sym_code;
623                 break;
624
625                 default:
626                 parse_error("expecting default_method keyword after 'default authentication = ' on line %d",sym_line);
627                 return (1);
628                 }
629                 sym_get();
630
631                 authen_default = tac_strdup(sym_buf);
632                 sym_get();
633                 continue;
634
635             case S_authorization:
636                 parse(S_authorization);
637                 parse(S_separator);
638                 parse(S_permit);
639                 no_user_dflt = S_permit;
640                 report(LOG_INFO, 
641                        "default authorization = permit is now deprecated. Please use user = DEFAULT instead");
642                 continue;
643             }
644
645         case S_key:
646             /* Process a key declaration. */
647             sym_get();
648             parse(S_separator);
649             if (session.key) {
650                 parse_error("multiply defined key on lines %d and %d",
651                             session.keyline, sym_line);
652                 return (1);
653             }
654             session.key = tac_strdup(sym_buf);
655             session.keyline = sym_line;
656             sym_get();
657             continue;
658         
659         case S_host:
660             parse_host();
661             continue;
662         
663         case S_user:
664         case S_group:
665             parse_user();
666             continue;
667
668             /* case S_host: parse_host(); continue; */
669
670         default:
671             parse_error("Unrecognised token %s on line %d", sym_buf, sym_line);
672             return (1);
673         }
674     }
675 }
676
677 static NODE *parse_svcs();
678
679 /* Assign a value to a field. Issue an error message and return 1 if
680    it's already been assigned. This is a macro because I was sick of
681    repeating the same code fragment over and over */
682
683 #define ASSIGN(field) \
684 sym_get(); parse(S_separator); if (field) { \
685         parse_error("Duplicate value for %s %s and %s on line %d", \
686                     codestring(sym_code), field, sym_buf, sym_line); \
687         tac_exit(1); \
688     } \
689     field = tac_strdup(sym_buf);
690
691 static int
692 parse_host()
693 {
694     HOST *h;
695     HOST *host = (HOST *) tac_malloc(sizeof(HOST));
696     int save_sym;
697     char buf[MAX_INPUT_LINE_LEN];
698
699     bzero(host, sizeof(HOST));
700
701     sym_get();
702     parse(S_separator);
703     host->name = tac_strdup(sym_buf);
704     host->line = sym_line;
705     
706     h = hash_add_entry(hosttable, (void *) host);
707     
708     if (h) {
709         parse_error("multiply defined %s on lines %d and %d",
710                     host->name, h->line, sym_line);
711         return (1);
712     }
713
714     sym_get();
715     parse(S_openbra);
716     
717     while (1) {
718         switch (sym_code) {
719         case S_eof:
720             return (0);
721         case S_key:
722             ASSIGN(host->key);
723             sym_get();
724             continue;
725         case S_type:
726             ASSIGN(host->type);
727             sym_get();
728             continue;
729         
730         case S_closebra:
731             parse(S_closebra);
732             return (0);
733
734         default:
735             parse_error("Unrecognised keyword %s for host %s on line %d",
736                         sym_buf, host->name,sym_line);
737
738             return (0);
739         }
740     } /* while */
741 } /* finish parse_host */
742
743
744 static int
745 parse_user()
746 {
747     USER *n;
748     int isuser;
749     USER *user = (USER *) tac_malloc(sizeof(USER));
750     int save_sym;
751     char **fieldp;
752     char buf[MAX_INPUT_LINE_LEN];
753
754     bzero(user, sizeof(USER));
755
756     isuser = (sym_code == S_user);
757
758     sym_get();
759     parse(S_separator);
760     user->name = tac_strdup(sym_buf);
761     user->line = sym_line;
762
763     if (isuser) {
764         user->flags |= FLAG_ISUSER;
765         n = hash_add_entry(usertable, (void *) user);
766     } else {
767         user->flags |= FLAG_ISGROUP;
768         n = hash_add_entry(grouptable, (void *) user);
769     }
770
771     if (n) {
772         parse_error("multiply defined %s %s on lines %d and %d",
773                     isuser ? "user" : "group",
774                     user->name, n->line, sym_line);
775         return (1);
776     }
777     sym_get();
778     parse(S_openbra);
779
780     /* Is the default deny for svcs or cmds to be overridden? */
781     user->svc_dflt = parse_opt_svc_default();
782
783     while (1) {
784         switch (sym_code) {
785         case S_eof:
786             return (0);
787         
788         case S_time:
789            ASSIGN(user->time);
790            sym_get(); 
791            continue;
792
793         case S_before:
794             sym_get();
795             parse(S_authorization);
796             if (user->before_author)
797                 free(user->before_author);
798             user->before_author = tac_strdup(sym_buf);
799             sym_get();
800             continue;
801
802         case S_after:
803             sym_get();
804             parse(S_authorization);
805             if (user->after_author)
806                 free(user->after_author);
807             user->after_author = tac_strdup(sym_buf);
808             sym_get();
809             continue;
810
811         case S_svc:
812         case S_cmd:
813             
814             if (user->svcs) {   
815                 /* 
816                  * Already parsed some services/commands. Thanks to Gabor Kiss
817                  * who found this bug.
818                  */
819                 NODE *p;
820                 for (p=user->svcs; p->next; p=p->next) 
821                     /* NULL STMT */;
822                 p->next = parse_svcs();
823             } else {
824                 user->svcs = parse_svcs();
825             }
826             continue;
827
828         case S_login:
829             if (user->login) {
830                 parse_error("Duplicate value for %s %s and %s on line %d",
831                             codestring(sym_code), user->login,
832                             sym_buf, sym_line);
833                 tac_exit(1);
834             }
835             sym_get();
836             parse(S_separator);
837             switch(sym_code) {
838
839             case S_skey:
840                 user->login = tac_strdup(sym_buf);
841                 break;
842
843             case S_nopasswd:
844                 /* set to dummy string, so that we detect a duplicate
845                  * password definition attempt
846                  */
847                 user->login = tac_strdup(nopasswd_str);
848                 user->nopasswd = 1;
849                 break;
850                 
851             case S_file:
852             case S_cleartext:
853             case S_des:
854 #ifdef USE_PAM  
855             case S_pam: 
856 #endif /* USE_PAM */            
857 #ifdef DB
858             case S_db:
859 #endif /* USE DB */
860                 sprintf(buf, "%s ", sym_buf);
861                 sym_get();
862                 strcat(buf, sym_buf);
863                 user->login = tac_strdup(buf);
864                 break;
865         
866             default:
867 #ifdef USE_PAM
868                 parse_error(
869  "expecting 'file', 'cleartext', 'pam'.'nopassword', 'skey', or 'des' keyword after 'login =' on line %d",
870                             sym_line);
871 #else   
872                 parse_error(
873  "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", 
874                             sym_line);
875 #endif /* USE_PAM */                    
876             }
877             sym_get();
878             continue;
879
880         case S_pap:
881             if (user->pap) {
882                 parse_error("Duplicate value for %s %s and %s on line %d",
883                             codestring(sym_code), user->pap,
884                             sym_buf, sym_line);
885                 tac_exit(1);
886             }
887             sym_get();
888             parse(S_separator);
889             switch(sym_code) {
890
891             case S_cleartext:
892             case S_des:
893 #ifdef USE_PAM  
894             case S_pam:
895 #endif /*USE_PAM */                     
896                 sprintf(buf, "%s ", sym_buf);
897                 sym_get();
898                 strcat(buf, sym_buf);
899                 user->pap = tac_strdup(buf);
900                 break;  
901
902                 sprintf(buf, "%s ", sym_buf);
903                 user->pap = tac_strdup(buf);
904                 break;
905
906             default:
907 #ifdef USE_PAM
908                 parse_error(
909  "expecting 'cleartext', 'pam', or 'des' keyword after 'pap =' on line %d",
910  sym_line);
911 #else
912                 parse_error(
913  "expecting 'cleartext', or 'des' keyword after 'pap =' on line %d", 
914  sym_line);
915 #endif /*USE_PAM */
916             }
917             sym_get();
918             continue;
919
920         case S_name:
921             ASSIGN(user->full_name);
922             sym_get();
923             continue;
924
925         case S_member:
926             ASSIGN(user->member);
927             sym_get();
928             continue;
929         
930
931         case S_expires:
932             ASSIGN(user->expires);
933             sym_get();
934             continue;
935         
936         case S_message:
937             ASSIGN(user->msg);
938             sym_get();
939             continue;
940
941         case S_arap:
942         case S_chap:
943 #ifdef MSCHAP
944         case S_mschap:
945 #endif /* MSCHAP */
946         case S_opap:
947         case S_global:
948             save_sym = sym_code;
949             sym_get(); 
950             parse(S_separator); 
951             sprintf(buf, "%s ", sym_buf);
952             parse(S_cleartext);
953             strcat(buf, sym_buf);
954
955             if (save_sym == S_arap)
956                 fieldp = &user->arap;
957             if (save_sym == S_chap)
958                 fieldp = &user->chap;
959 #ifdef MSCHAP
960             if (save_sym == S_mschap)
961                 fieldp = &user->mschap;
962 #endif /* MSCHAP */
963             if (save_sym == S_pap)
964                 fieldp = &user->pap;
965             if (save_sym == S_opap)
966                 fieldp = &user->opap;
967             if (save_sym == S_global)
968                 fieldp = &user->global;
969
970             if (*fieldp) {
971                 parse_error("Duplicate value for %s %s and %s on line %d",
972                             codestring(save_sym), *fieldp, sym_buf, sym_line);
973                 tac_exit(1);
974             }
975             *fieldp = tac_strdup(buf);
976             sym_get();
977             continue;
978
979         case S_closebra:
980             parse(S_closebra);
981             return (0);
982
983 #ifdef MAXSESS
984         case S_maxsess:
985             sym_get(); 
986             parse(S_separator);
987             if (sscanf(sym_buf, "%d", &user->maxsess) != 1) {
988                 parse_error("expecting integer, found '%s' on line %d",
989                     sym_buf, sym_line);
990             }
991             sym_get();
992             continue;
993 #endif /* MAXSESS */
994  
995         default:
996             if (STREQ(sym_buf, "password")) {
997                 fprintf(stderr,
998                         "\npassword = <string> is obsolete. Use login = des <string>\n");
999             }
1000             parse_error("Unrecognised keyword %s for user on line %d",
1001                         sym_buf, sym_line);
1002
1003             return (0);
1004         }
1005     }
1006 }
1007
1008 static NODE *parse_attrs();
1009 static NODE *parse_cmd_matches();
1010
1011 static NODE *
1012 parse_svcs()
1013 {
1014     NODE *result;
1015
1016     switch (sym_code) {
1017     default:
1018         return (NULL);
1019     case S_svc:
1020     case S_cmd:
1021         break;
1022     }
1023
1024     result = (NODE *) tac_malloc(sizeof(NODE));
1025
1026     bzero(result, sizeof(NODE));
1027     result->line = sym_line;
1028
1029     /* cmd declaration */
1030     if (sym_code == S_cmd) {
1031         parse(S_cmd);
1032         parse(S_separator);
1033         result->value = tac_strdup(sym_buf);
1034
1035         sym_get();
1036         parse(S_openbra);
1037
1038         result->value1 = parse_cmd_matches();
1039         result->type = N_svc_cmd;
1040
1041         parse(S_closebra);
1042         result->next = parse_svcs();
1043         return (result);
1044     }
1045
1046     /* svc declaration */
1047     parse(S_svc);
1048     parse(S_separator);
1049     switch (sym_code) {
1050     default:
1051         parse_error("expecting service type but found %s on line %d",
1052                     sym_buf, sym_line);
1053         return (NULL);
1054
1055     case S_string:
1056         result->type = N_svc;
1057         /* should perhaps check that this is an allowable service name */
1058         result->value1 = tac_strdup(sym_buf);
1059         break;
1060     case S_exec:
1061         result->type = N_svc_exec;
1062         break;
1063     case S_arap:
1064         result->type = N_svc_arap;
1065         break;
1066     case S_slip:
1067         result->type = N_svc_slip;
1068         break;
1069     case S_ppp:
1070         result->type = N_svc_ppp;
1071         parse(S_ppp);
1072         parse(S_protocol);
1073         parse(S_separator);
1074         /* Should perhaps check that this is a known PPP protocol name */
1075         result->value1 = tac_strdup(sym_buf);
1076         break;
1077     }
1078     sym_get();
1079     parse(S_openbra);
1080     result->dflt = parse_opt_attr_default();
1081     result->value = parse_attrs();
1082     parse(S_closebra);
1083     result->next = parse_svcs();
1084     return (result);
1085 }
1086
1087 /*  <cmd-match>  := <permission> <string> */
1088
1089 static NODE *
1090 parse_cmd_matches()
1091 {
1092     NODE *result;
1093
1094     if (sym_code != S_permit && sym_code != S_deny) {
1095         return (NULL);
1096     }
1097     result = (NODE *) tac_malloc(sizeof(NODE));
1098
1099     bzero(result, sizeof(NODE));
1100     result->line = sym_line;
1101
1102     result->type = (parse_permission() == S_permit) ? N_permit : N_deny;
1103     result->value = tac_strdup(sym_buf);
1104
1105     result->value1 = (void *) regcomp(result->value);
1106     if (!result->value1) {
1107         report(LOG_ERR, "in regular expression %s on line %d",
1108                sym_buf, sym_line);
1109         tac_exit(1);
1110     }
1111     sym_get();
1112
1113     result->next = parse_cmd_matches();
1114
1115     return (result);
1116 }
1117
1118 static NODE *
1119 parse_attrs()
1120 {
1121     NODE *result;
1122     char buf[MAX_INPUT_LINE_LEN];
1123     int optional = 0;
1124
1125     if (sym_code == S_closebra) {
1126         return (NULL);
1127     }
1128     result = (NODE *) tac_malloc(sizeof(NODE));
1129
1130     bzero(result, sizeof(NODE));
1131     result->line = sym_line;
1132
1133     if (sym_code == S_optional) {
1134         optional++;
1135         sym_get();
1136     }
1137     result->type = optional ? N_optarg : N_arg;
1138
1139     strcpy(buf, sym_buf);
1140     parse(S_string);
1141     strcat(buf, sym_buf);
1142     parse(S_separator);
1143     strcat(buf, sym_buf);
1144     parse(S_string);
1145
1146     result->value = tac_strdup(buf);
1147     result->next = parse_attrs();
1148     return (result);
1149 }
1150
1151
1152 static void
1153  getsym();
1154
1155 static void
1156 sym_get()
1157 {
1158     getsym();
1159
1160     if (debug & DEBUG_PARSE_FLAG) {
1161         report(LOG_DEBUG, "line=%d sym=%s code=%d buf='%s'",
1162                sym_line, codestring(sym_code), sym_code, sym_buf);
1163     }
1164 }
1165
1166 static char *
1167 sym_buf_add(c)
1168 char c;
1169 {
1170     if (sym_pos >= MAX_INPUT_LINE_LEN) {
1171         sym_buf[MAX_INPUT_LINE_LEN-1] = '\0';
1172         if (debug & DEBUG_PARSE_FLAG) {
1173             report(LOG_DEBUG, "line too long: line=%d sym=%s code=%d buf='%s'",
1174                    sym_line, codestring(sym_code), sym_code, sym_buf);
1175         }
1176         return(NULL);
1177     }
1178
1179     sym_buf[sym_pos++] = c;
1180     return(sym_buf);
1181 }
1182     
1183 static void
1184 getsym()
1185 {
1186
1187 next:
1188     switch (sym_ch) {
1189
1190     case EOF:
1191         sym_code = S_eof;
1192         return;
1193
1194     case '\n':
1195         sym_line++;
1196         rch();
1197         goto next;
1198
1199     case '\t':
1200     case ' ':
1201         while (sym_ch == ' ' || sym_ch == '\t')
1202             rch();
1203         goto next;
1204
1205     case '=':
1206         strcpy(sym_buf, "=");
1207         sym_code = S_separator;
1208         rch();
1209         return;
1210
1211     case '{':
1212         strcpy(sym_buf, "{");
1213         sym_code = S_openbra;
1214         rch();
1215         return;
1216
1217     case '}':
1218         strcpy(sym_buf, "}");
1219         sym_code = S_closebra;
1220         rch();
1221         return;
1222
1223     case '#':
1224         while ((sym_ch != '\n') && (sym_ch != EOF))
1225             rch();
1226         goto next;
1227
1228     case '"':
1229         rch();
1230         sym_pos = 0;
1231         while (1) {
1232
1233             if (sym_ch == '"') {
1234                 break;
1235             }
1236
1237             /* backslash-double-quote is supported inside strings */
1238             /* also allow \n */
1239             if (sym_ch == '\\') {
1240                 rch();
1241                 switch (sym_ch) {
1242                 case 'n':
1243                     /* preserve the slash for \n */
1244                     if (!sym_buf_add('\\')) {
1245                         sym_code = S_unknown;
1246                         rch();
1247                         return;
1248                     }
1249                     
1250                     /* fall through */
1251                 case '"':
1252                     if (!sym_buf_add(sym_ch)) {
1253                         sym_code = S_unknown;
1254                         rch();
1255                         return;
1256                     }
1257                     rch();
1258                     continue;
1259                 default:
1260                     sym_code = S_unknown;
1261                     rch();
1262                     return;
1263                 }
1264             }
1265             if (!sym_buf_add(sym_ch)) {
1266                 sym_code = S_unknown;
1267                 rch();
1268                 return;
1269             }
1270             rch();
1271         }
1272         rch();
1273
1274         if (!sym_buf_add('\0')) {
1275             sym_code = S_unknown;
1276             rch();
1277             return;
1278         }
1279         sym_code = S_string;
1280         return;
1281
1282     default:
1283         sym_pos = 0;
1284         while (sym_ch != '\t' && sym_ch != ' ' && sym_ch != '='
1285                && sym_ch != '\n') {
1286
1287             if (!sym_buf_add(sym_ch)) {
1288                 sym_code = S_unknown;
1289                 rch();
1290                 return;
1291             }
1292             rch();
1293         }
1294
1295         if (!sym_buf_add('\0')) {
1296             sym_code = S_unknown;
1297             rch();
1298             return;
1299         }
1300         sym_code = keycode(sym_buf);
1301         if (sym_code == S_unknown)
1302             sym_code = S_string;
1303         return;
1304     }
1305 }
1306
1307 static void
1308 rch()
1309 {
1310     if (sym_error) {
1311         sym_ch = EOF;
1312         return;
1313     }
1314     sym_ch = getc(cf);
1315
1316     if (parse_only && sym_ch != EOF)
1317         fprintf(stderr, "%c", sym_ch);
1318 }
1319
1320
1321 /* For a user or group, find the value of a field. Does not recurse. */
1322 VALUE
1323 get_value(user, field)
1324 USER *user;
1325 int field;
1326 {
1327     VALUE v;
1328
1329     v.intval = 0;
1330
1331     if (!user) {
1332         parse_error("get_value: illegal user");
1333         return (v);
1334     }
1335     switch (field) {
1336
1337     case S_name:
1338         v.pval = user->name;
1339         break;
1340
1341     case S_login:
1342         v.pval = user->login;
1343         break;
1344
1345     case S_global:
1346         v.pval = user->global;
1347         break;
1348
1349     case S_member:
1350         v.pval = user->member;
1351         break;
1352
1353     case S_expires:
1354         v.pval = user->expires;
1355         break;
1356
1357     case S_arap:
1358         v.pval = user->arap;
1359         break;
1360
1361     case S_chap:
1362         v.pval = user->chap;
1363         break;
1364
1365 #ifdef MSCHAP
1366     case S_mschap:
1367         v.pval = user->mschap;
1368         break;
1369 #endif /* MSCHAP */
1370
1371     case S_pap:
1372         v.pval = user->pap;
1373         break;
1374
1375     case S_opap:
1376         v.pval = user->opap;
1377         break;
1378
1379     case S_message:
1380         v.pval = user->msg;
1381         break;
1382
1383     case S_svc:
1384         v.pval = user->svcs;
1385         break;
1386
1387     case S_before:
1388         v.pval = user->before_author;
1389         break;
1390
1391     case S_after:
1392         v.pval = user->after_author;
1393         break;
1394
1395     case S_svc_dflt:
1396         v.intval = user->svc_dflt;
1397         break;
1398
1399 #ifdef MAXSESS
1400     case S_maxsess:
1401         v.intval = user->maxsess;
1402         break;
1403 #endif 
1404
1405     case S_nopasswd:
1406         v.intval = user->nopasswd;
1407         break;
1408         
1409     case S_time:
1410         v.pval = user->time;
1411         break;
1412
1413     default:
1414         report(LOG_ERR, "get_value: unknown field %d", field);
1415         break;
1416     }
1417     return (v);
1418 }
1419
1420 /* For host , find value of field. Doesn't recursive */
1421 VALUE
1422 get_hvalue(host, field)
1423 HOST *host;
1424 int field;
1425 {
1426     VALUE v;
1427     v.intval = 0;
1428     if(!host) {
1429         parse_error("get_hvalue: illegal host");
1430         return (v);
1431     }
1432     switch (field) {
1433         case S_name:
1434         v.pval = host->name;
1435         break;
1436         
1437         case S_key:
1438         v.pval = host->key;
1439         break;
1440         
1441         default:
1442         report(LOG_ERR, "get_value: unknown field %d", field);
1443         break;
1444     }
1445     return (v);
1446 }
1447
1448
1449 /* For each user, check she doesn't circularly reference a
1450    group. Return 1 if it does */
1451 static int
1452 circularity_check()
1453 {
1454     USER *user, *entry, *group;
1455     USER **users = (USER **) hash_get_entries(usertable);
1456     USER **groups = (USER **) hash_get_entries(grouptable);
1457     USER **p, **q;
1458
1459     /* users */
1460     for (p = users; *p; p++) {
1461         user = *p;
1462
1463         if (debug & DEBUG_PARSE_FLAG)
1464             report(LOG_DEBUG, "circularity_check: user=%s", user->name);
1465
1466         /* Initialise all groups "seen" flags to zero */
1467         for (q = groups; *q; q++) {
1468             group = *q;
1469             group->flags &= ~FLAG_SEEN;
1470         }
1471
1472         entry = user;
1473
1474         while (entry) {
1475             /* check groups we are a member of */
1476             char *groupname = entry->member;
1477
1478             if (debug & DEBUG_PARSE_FLAG)
1479                 report(LOG_DEBUG, "\tmember of group %s",
1480                        groupname ? groupname : "<none>");
1481
1482
1483             /* if not a member of any groups, go on to next user */
1484             if (!groupname)
1485                 break;
1486
1487             group = (USER *) hash_lookup(grouptable, groupname);
1488             if (!group) {
1489                 report(LOG_ERR, "%s=%s, group %s does not exist",
1490                        (entry->flags & FLAG_ISUSER) ? "user" : "group",
1491                        entry->name, groupname);
1492                 free(users);
1493                 free(groups);
1494                 return (1);
1495             }
1496             if (group->flags & FLAG_SEEN) {
1497                 report(LOG_ERR, "recursively defined groups");
1498
1499                 /* print all seen "groups" */
1500                 for (q = groups; *q; q++) {
1501                     group = *q;
1502                     if (group->flags & FLAG_SEEN)
1503                         report(LOG_ERR, "%s", group->name);
1504                 }
1505                 free(users);
1506                 free(groups);
1507                 return (1);
1508             }
1509             group->flags |= FLAG_SEEN;  /* mark group as seen */
1510             entry = group;
1511         }
1512     }
1513     free(users);
1514     free(groups);
1515     return (0);
1516 }
1517
1518
1519 /* Return a value for a group or user (isuser says if
1520    this name is a group or a user name).
1521
1522    If no value exists, and recurse is true, also check groups we are a
1523    member of, recursively.
1524
1525    Returns void * because it can return a string or a node pointer
1526    (should really return a union pointer).
1527 */
1528 static VALUE
1529 cfg_get_value(name, isuser, attr, recurse)
1530 char *name;
1531 int isuser, attr, recurse;
1532 {
1533     USER *user, *group;
1534     VALUE value;
1535
1536     value.pval = NULL;
1537
1538     if (debug & DEBUG_CONFIG_FLAG)
1539         report(LOG_DEBUG, "cfg_get_value: name=%s isuser=%d attr=%s rec=%d",
1540                name, isuser, codestring(attr), recurse);
1541
1542     /* find the user/group entry */
1543
1544     user = (USER *) hash_lookup(isuser ? usertable : grouptable, name);
1545
1546     if (!user) {
1547         if (debug & DEBUG_CONFIG_FLAG)
1548             report(LOG_DEBUG, "cfg_get_value: no user/group named %s", name);
1549         return (value);
1550     }
1551
1552     /* found the entry. Lookup value from attr=value */
1553     value = get_value(user, attr);
1554
1555     if (value.pval || !recurse) {
1556         return (value);
1557     }
1558     /* no value. Check containing group */
1559     if (user->member)
1560         group = (USER *) hash_lookup(grouptable, user->member);
1561     else
1562         group = NULL;
1563
1564     while (group) {
1565         if (debug & DEBUG_CONFIG_FLAG)
1566             report(LOG_DEBUG, "cfg_get_value: recurse group = %s",
1567                    group->name);
1568
1569         value = get_value(group, attr);
1570
1571         if (value.pval) {
1572             return (value);
1573         }
1574         /* still nothing. Check containing group and so on */
1575
1576         if (group->member)
1577             group = (USER *) hash_lookup(grouptable, group->member);
1578         else
1579             group = NULL;
1580     }
1581
1582     /* no value for this user or her containing groups */
1583     value.pval = NULL;
1584     return (value);
1585 }
1586
1587
1588 /* Wrappers for cfg_get_value */
1589 int
1590 cfg_get_intvalue(name, isuser, attr, recurse)
1591 char *name;
1592 int isuser, attr, recurse;
1593 {
1594     int val = cfg_get_value(name, isuser, attr, recurse).intval;
1595
1596     if (debug & DEBUG_CONFIG_FLAG)
1597         report(LOG_DEBUG, "cfg_get_intvalue: returns %d", val);
1598     return(val);
1599 }
1600
1601 char *
1602 cfg_get_pvalue(name, isuser, attr, recurse)
1603 char *name;
1604 int isuser, attr, recurse;
1605 {
1606     char *p = cfg_get_value(name, isuser, attr, recurse).pval;
1607
1608     if (debug & DEBUG_CONFIG_FLAG)
1609         report(LOG_DEBUG, "cfg_get_pvalue: returns %s", 
1610                p ? p : "NULL");
1611     return(p);
1612 }
1613
1614 /* For getting host values */
1615 static VALUE
1616 cfg_get_hvalue(name, attr)
1617 char *name;
1618 int attr;
1619 {
1620     HOST *host;
1621     VALUE value;
1622
1623     value.pval = NULL;
1624     if (debug & DEBUG_CONFIG_FLAG)
1625         report(LOG_DEBUG, "cfg_get_hvalue: name=%s attr=%s ",
1626                name, codestring(attr));
1627     
1628     /* find the host entry in hash table */
1629
1630     host = (HOST *) hash_lookup( hosttable, name);
1631
1632     if (!host) {
1633         if (debug & DEBUG_CONFIG_FLAG)
1634             report(LOG_DEBUG, "cfg_get_hvalue: no host named %s", name);
1635         return (value);
1636     }
1637
1638     /* found the entry. Lookup value from attr=value */
1639     value = get_hvalue(host, attr);
1640
1641     if (value.pval) {
1642         return (value);
1643     }
1644     /* No any value for this host */    
1645     value.pval = NULL;
1646     return (value);
1647 }
1648
1649 /* Wrappers for cfg_get_hvalue */
1650 char *
1651 cfg_get_phvalue(name, attr)
1652 char *name;
1653 int attr;
1654 {
1655     char *p = cfg_get_hvalue(name, attr).pval;
1656
1657     if (debug & DEBUG_CONFIG_FLAG)
1658         report(LOG_DEBUG, "cfg_get_phvalue: returns %s", 
1659                p ? p : "NULL");
1660     return(p);
1661 }
1662
1663 /*
1664    Read the config file and do some basic sanity checking on
1665    it. Return 1 if we find any errors. */
1666
1667 cfg_read_config(cfile)
1668 char *cfile;
1669 {
1670     sym_line = 1;
1671
1672     if ((cf = fopen(cfile, "r")) == NULL) {
1673         report(LOG_ERR, "read_config: fopen() error for file %s %s, exiting",
1674                cfile, sys_errlist[errno]);
1675         return (1);
1676     }
1677     if (parse_decls() || sym_error) {
1678         fclose(cf);
1679         return (1);
1680     }
1681
1682     if (circularity_check()) {
1683         fclose(cf);
1684         return (1);
1685     }
1686
1687     fclose(cf);
1688     return (0);
1689 }
1690
1691 /* return 1 if user exists, 0 otherwise */
1692 int
1693 cfg_user_exists(username)
1694 char *username;
1695 {
1696     USER *user = (USER *) hash_lookup(usertable, username);
1697
1698     return (user != NULL);
1699 }
1700
1701 /* return expiry string of user. If none, try groups she is a member
1702    on, and so on, recursively if recurse is non-zero */
1703 char *
1704 cfg_get_expires(username, recurse)
1705 char *username;
1706
1707 {
1708     return (cfg_get_pvalue(username, TAC_IS_USER, S_expires, recurse));
1709 }
1710
1711 /* return time string of user. If none, try groups she is a member
1712    on, and so on, recursively if recurse is non-zero */
1713 char *
1714 cfg_get_timestamp(username, recurse)
1715 char *username;
1716 {
1717     return (cfg_get_pvalue(username, TAC_IS_USER, S_time, recurse));
1718 }
1719
1720
1721 /* return password string of user. If none, try groups she is a member
1722    on, and so on, recursively if recurse is non-zero */
1723 char *
1724 cfg_get_login_secret(user, recurse)
1725 char *user;
1726
1727 {
1728     return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse));
1729 }
1730
1731 /* return value of the nopasswd field. If none, try groups she is a member
1732    on, and so on, recursively if recurse is non-zero */
1733 int
1734 cfg_get_user_nopasswd(user, recurse)
1735     char *user;
1736 {
1737     return (cfg_get_intvalue(user, TAC_IS_USER, S_nopasswd, recurse));
1738 }
1739
1740 /* return user's secret. If none, try groups she is a member
1741    on, and so on, recursively if recurse is non-zero */
1742 char *
1743 cfg_get_arap_secret(user, recurse)
1744 char *user;
1745
1746 {
1747     return (cfg_get_pvalue(user, TAC_IS_USER, S_arap, recurse));
1748 }
1749
1750 char *
1751 cfg_get_chap_secret(user, recurse)
1752 char *user;
1753
1754 {
1755     return (cfg_get_pvalue(user, TAC_IS_USER, S_chap, recurse));
1756 }
1757
1758 #ifdef MSCHAP
1759 char *
1760 cfg_get_mschap_secret(user, recurse)
1761 char *user;
1762
1763 {
1764     return (cfg_get_pvalue(user, TAC_IS_USER, S_mschap, recurse));
1765 }
1766 #endif /* MSCHAP */
1767
1768 char *
1769 cfg_get_pap_secret(user, recurse)
1770 char *user;
1771 {
1772     return (cfg_get_pvalue(user, TAC_IS_USER, S_pap, recurse));
1773 }
1774
1775 char *
1776 cfg_get_opap_secret(user, recurse)
1777 char *user;
1778 {
1779     return (cfg_get_pvalue(user, TAC_IS_USER, S_opap, recurse));
1780 }
1781
1782 /* return the global password for the user (or the group, etc.) */
1783
1784 char *
1785 cfg_get_global_secret(user, recurse)
1786 char *user;
1787
1788 {
1789     return (cfg_get_pvalue(user, TAC_IS_USER, S_global, recurse));
1790 }
1791
1792 #ifdef USE_PAM
1793 /* Return a pointer to a node representing a PAM Service name */
1794 char *
1795 cfg_get_pam_service(user,recurse)
1796 char *user;
1797
1798 {
1799  char *cfg_passwd;
1800  char *p;   
1801
1802 cfg_passwd = cfg_get_pap_secret(user, recurse);
1803  
1804 if (!cfg_passwd) {
1805                 cfg_passwd = cfg_get_global_secret(user, recurse);
1806 }
1807  
1808 if (!cfg_passwd && !cfg_user_exists(user)) {
1809         cfg_passwd = cfg_get_authen_default();
1810         switch (cfg_get_authen_default_method()) {
1811                 case (S_pam): 
1812                         if (debug & DEBUG_AUTHOR_FLAG)
1813                         report(LOG_DEBUG, "Get Default PAM Service :%s",cfg_passwd);
1814                         return(cfg_passwd);
1815                         break;
1816                 default:
1817                         if (debug & DEBUG_AUTHOR_FLAG)
1818                         report(LOG_DEBUG, "I havent find any PAM Service!!");
1819                         return(NULL);/* Haven't any PAM Service!! */
1820         }
1821 }
1822
1823 p=tac_find_substring("pam ", cfg_passwd);
1824
1825 if(p) {  /* We find PAM services */
1826         if (debug & DEBUG_AUTHOR_FLAG)
1827                 report(LOG_DEBUG, "I get PAM sevice:%s",p);
1828 return (p);
1829 }
1830
1831 if (debug & DEBUG_AUTHOR_FLAG)
1832         report(LOG_DEBUG, "No any PAM Sevice");
1833
1834 return(NULL);
1835 }
1836
1837 #endif /* For PAM */
1838         
1839
1840
1841 /* Return a pointer to a node representing a given service
1842    authorization, taking care of recursion issues correctly. Protocol
1843    is only read if the type is N_svc_ppp. svcname is only read if type
1844    is N_svc.
1845 */
1846
1847 NODE *
1848 cfg_get_svc_node(username, type, protocol, svcname, recurse)
1849 char *username;
1850 int type;
1851 char *protocol, *svcname;
1852 int recurse;
1853 {
1854     USER *user, *group;
1855     NODE *svc;
1856
1857     if (debug & DEBUG_CONFIG_FLAG)
1858         report(LOG_DEBUG, 
1859                "cfg_get_svc_node: username=%s %s proto=%s svcname=%s rec=%d",
1860                username, 
1861                cfg_nodestring(type), 
1862                protocol ? protocol : "", 
1863                svcname ? svcname : "", 
1864                recurse);
1865
1866     /* find the user/group entry */
1867     user = (USER *) hash_lookup(usertable, username);
1868
1869     if (!user) {
1870         if (debug & DEBUG_CONFIG_FLAG)
1871             report(LOG_DEBUG, "cfg_get_svc_node: no user named %s", username);
1872         return (NULL);
1873     }
1874
1875     /* found the user entry. Find svc node */
1876     for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
1877
1878         if (svc->type != type) 
1879             continue;
1880
1881         if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
1882             continue;
1883         }
1884
1885         if (type == N_svc && !STREQ(svc->value1, svcname)) {
1886             continue;
1887         }
1888
1889         if (debug & DEBUG_CONFIG_FLAG)
1890             report(LOG_DEBUG, 
1891                    "cfg_get_svc_node: found %s proto=%s svcname=%s",
1892                    cfg_nodestring(type), 
1893                    protocol ? protocol : "", 
1894                    svcname ? svcname : "");
1895
1896         return(svc);
1897     }
1898
1899     if (!recurse) {
1900         if (debug & DEBUG_CONFIG_FLAG)
1901             report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
1902         return (NULL);
1903     }
1904
1905     /* no matching node. Check containing group */
1906     if (user->member)
1907         group = (USER *) hash_lookup(grouptable, user->member);
1908     else
1909         group = NULL;
1910
1911     while (group) {
1912         if (debug & DEBUG_CONFIG_FLAG)
1913             report(LOG_DEBUG, "cfg_get_svc_node: recurse group = %s",
1914                    group->name);
1915
1916         for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
1917
1918             if (svc->type != type) 
1919                 continue;
1920
1921             if (type == N_svc_ppp && !STREQ(svc->value1, protocol)) {
1922                 continue;
1923             }
1924
1925             if (type == N_svc && !STREQ(svc->value1, svcname)) {
1926                 continue;
1927             }
1928
1929             if (debug & DEBUG_CONFIG_FLAG)
1930                 report(LOG_DEBUG, 
1931                        "cfg_get_svc_node: found %s proto=%s svcname=%s",
1932                        cfg_nodestring(type), 
1933                        protocol ? protocol : "", 
1934                        svcname ? svcname : "");
1935
1936             return(svc);
1937         }
1938
1939         /* still nothing. Check containing group and so on */
1940
1941         if (group->member)
1942             group = (USER *) hash_lookup(grouptable, group->member);
1943         else
1944             group = NULL;
1945     }
1946
1947     if (debug & DEBUG_CONFIG_FLAG)
1948         report(LOG_DEBUG, "cfg_get_svc_node: returns NULL");
1949
1950     /* no matching svc node for this user or her containing groups */
1951     return (NULL);
1952 }
1953
1954 /* Return a pointer to the node representing a set of command regexp
1955    matches for a user and command, handling recursion issues correctly */
1956 NODE *
1957 cfg_get_cmd_node(name, cmdname, recurse)
1958 char *name, *cmdname;
1959 int recurse;
1960
1961 {
1962     USER *user, *group;
1963     NODE *svc;
1964
1965     if (debug & DEBUG_CONFIG_FLAG)
1966         report(LOG_DEBUG, "cfg_get_cmd_node: name=%s cmdname=%s rec=%d",
1967                name, cmdname, recurse);
1968
1969     /* find the user/group entry */
1970     user = (USER *) hash_lookup(usertable, name);
1971
1972     if (!user) {
1973         if (debug & DEBUG_CONFIG_FLAG)
1974             report(LOG_DEBUG, "cfg_get_cmd_node: no user named %s", name);
1975         return (NULL);
1976     }
1977     /* found the user entry. Find svc node */
1978     svc = (NODE *) get_value(user, S_svc).pval;
1979
1980     while (svc) {
1981         if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
1982             if (debug & DEBUG_CONFIG_FLAG)
1983                 report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s %s node",
1984                        cmdname, cfg_nodestring(svc->type));
1985             return (svc);
1986         }
1987         svc = svc->next;
1988     }
1989
1990     if (!recurse) {
1991         if (debug & DEBUG_CONFIG_FLAG)
1992             report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
1993         return (NULL);
1994     }
1995     /* no matching node. Check containing group */
1996     if (user->member)
1997         group = (USER *) hash_lookup(grouptable, user->member);
1998     else
1999         group = NULL;
2000
2001     while (group) {
2002         if (debug & DEBUG_CONFIG_FLAG)
2003             report(LOG_DEBUG, "cfg_get_cmd_node: recurse group = %s",
2004                    group->name);
2005
2006         svc = get_value(group, S_svc).pval;
2007
2008         while (svc) {
2009             if (svc->type == N_svc_cmd && STREQ(svc->value, cmdname)) {
2010                 if (debug & DEBUG_CONFIG_FLAG)
2011                     report(LOG_DEBUG, "cfg_get_cmd_node: found cmd %s node %s",
2012                            cmdname, cfg_nodestring(svc->type));
2013                 return (svc);
2014             }
2015             svc = svc->next;
2016         }
2017
2018         /* still nothing. Check containing group and so on */
2019
2020         if (group->member)
2021             group = (USER *) hash_lookup(grouptable, group->member);
2022         else
2023             group = NULL;
2024     }
2025
2026     if (debug & DEBUG_CONFIG_FLAG)
2027         report(LOG_DEBUG, "cfg_get_cmd_node: returns NULL");
2028
2029     /* no matching cmd node for this user or her containing groups */
2030     return (NULL);
2031 }
2032
2033 /* Return an array of character strings representing configured AV
2034  * pairs, given a username and a service node. 
2035  *
2036  * In the AV strings returned, manipulate the separator character to
2037  * indicate which args are optional and which are mandatory.
2038  *
2039  * Lastly, indicate what default permission was configured by setting
2040  * denyp */
2041
2042 char **
2043 cfg_get_svc_attrs(svcnode, denyp)
2044 NODE *svcnode;
2045 int *denyp;
2046 {
2047     int i;
2048     NODE *node;
2049     char **args;
2050
2051     *denyp = 1;
2052
2053     if (!svcnode)
2054         return (NULL);
2055
2056     *denyp = (svcnode->dflt == S_deny);
2057
2058     i = 0;
2059     for (node = svcnode->value; node; node = node->next)
2060         i++;
2061
2062     args = (char **) tac_malloc(sizeof(char *) * (i + 1));
2063
2064     i = 0;
2065     for (node = svcnode->value; node; node = node->next) {
2066         char *arg = tac_strdup(node->value);
2067         char *p = index(arg, '=');
2068
2069         if (p && node->type == N_optarg)
2070             *p = '*';
2071         args[i++] = arg;
2072     }
2073     args[i] = NULL;
2074     return (args);
2075 }
2076
2077
2078 int
2079 cfg_user_svc_default_is_permit(user)
2080 char *user;
2081
2082 {
2083     int permit = cfg_get_intvalue(user, TAC_IS_USER, S_svc_dflt,
2084                                TAC_PLUS_RECURSE);
2085
2086     switch (permit) {
2087     default:                    /* default is deny */
2088     case S_deny:
2089         return (0);
2090     case S_permit:
2091         return (1);
2092     }
2093 }
2094
2095 int
2096 cfg_no_user_permitted()
2097 {
2098     if (no_user_dflt == S_permit)
2099         return (1);
2100     return (0);
2101 }
2102
2103
2104 char *
2105 cfg_get_authen_default()
2106 {
2107     return (authen_default);
2108 }
2109
2110 /* For describe authentication method(pam,file,db..etc) */
2111 int 
2112 cfg_get_authen_default_method()
2113 {
2114    return (authen_default_method);
2115 }
2116
2117
2118 /* Return 1 if this user has any ppp services configured. Used for
2119    authorizing ppp/lcp requests */
2120 int
2121 cfg_ppp_is_configured(username, recurse)
2122     char *username;
2123     int recurse;
2124 {
2125     USER *user, *group;
2126     NODE *svc;
2127
2128     if (debug & DEBUG_CONFIG_FLAG)
2129         report(LOG_DEBUG, "cfg_ppp_is_configured: username=%s rec=%d",
2130                username, recurse);
2131
2132     /* find the user/group entry */
2133     user = (USER *) hash_lookup(usertable, username);
2134
2135     if (!user) {
2136         if (debug & DEBUG_CONFIG_FLAG)
2137             report(LOG_DEBUG, "cfg_ppp_is_configured: no user named %s", 
2138                    username);
2139         return (0);
2140     }
2141
2142     /* found the user entry. Find svc node */
2143     for(svc = (NODE *) get_value(user, S_svc).pval; svc; svc = svc->next) {
2144
2145         if (svc->type != N_svc_ppp) 
2146             continue;
2147
2148         if (debug & DEBUG_CONFIG_FLAG)
2149             report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
2150                    svc->value1);
2151         
2152         return(1);
2153     }
2154
2155     if (!recurse) {
2156         if (debug & DEBUG_CONFIG_FLAG)
2157             report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
2158         return (0);
2159     }
2160
2161     /* no matching node. Check containing group */
2162     if (user->member)
2163         group = (USER *) hash_lookup(grouptable, user->member);
2164     else
2165         group = NULL;
2166
2167     while (group) {
2168         if (debug & DEBUG_CONFIG_FLAG)
2169             report(LOG_DEBUG, "cfg_ppp_is_configured: recurse group = %s",
2170                    group->name);
2171
2172         for(svc = (NODE *) get_value(group, S_svc).pval; svc; svc = svc->next) {
2173
2174             if (svc->type != N_svc_ppp)
2175                 continue;
2176
2177             if (debug & DEBUG_CONFIG_FLAG)
2178                 report(LOG_DEBUG, "cfg_ppp_is_configured: found svc ppp %s node",
2179                        svc->value1);
2180         
2181             return(1);
2182         }
2183
2184         /* still nothing. Check containing group and so on */
2185
2186         if (group->member)
2187             group = (USER *) hash_lookup(grouptable, group->member);
2188         else
2189             group = NULL;
2190     }
2191
2192     if (debug & DEBUG_CONFIG_FLAG)
2193         report(LOG_DEBUG, "cfg_ppp_is_configured: returns 0");
2194
2195     /* no PPP svc nodes for this user or her containing groups */
2196     return (0);
2197 }
2198
2199 /* For getting host key */
2200 char *
2201 cfg_get_host_key(host)
2202 char *host;
2203 {
2204     return (cfg_get_phvalue(host, S_key));
2205 }
2206