/* * Copyright (c) 2000-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* * OpenFWTK project legacy API functions - configuration * * (C) Copyright 2000-2001 ArkanoiD * (C) Copyright 2000 Eberhard Mattes * */ #include #include #include #include #include #include #include #include "firewall.h" static char* moduleId ATTR_UNUSED = "$Id: cfg.c,v 1.18 2007/09/10 02:49:13 arkenoi Exp $"; static char pfile[MAXPATHLEN] = PERMFILE; extern void strtrm(char *); extern char* xstrdup(); extern void* xmalloc(); extern void* xrealloc(); extern size_t strlcat(char*,const char*,size_t); extern size_t strlcpy(char*,const char*,size_t); extern int enargv(char *,char **,int,char *,int); struct config_file { FILE *f; const char *name; long lineno; }; struct config_var { char *name; char *value; struct config_var *next; }; static struct config_var *config_vars = NULL; /* Return value: 0=ok, 1=EOF */ int read_config_line (struct config_file *cf, char *dst, size_t dst_size) { int first = 1; size_t i = 0; for (;;) { int c = getc (cf->f); if (c == EOF) { if (ferror (cf->f)) { syslog(LLEV,"%s: %s", cf->name, strerror(errno)); exit(1); } if (first) { errno = 0; /* EOF */ return 1; } syslog (LLEV,"%s: last line not terminated", cf->name); exit(1); } if (first) { cf->lineno += 1; first = 0; } if (c == '\n') { while (i > 0 && isspace ((unsigned char)dst[i-1])) --i; /* Note: comment lines are not to be continued. Really? */ if (i == 0 || dst[i-1] != '\\' || dst[0] == '#') { dst[i] = 0; return 0; } /* Read a continuation line */ --i; /* Overwrite the backslash */ cf->lineno += 1; } else if (i + 1 >= dst_size) { syslog (LLEV,"%s:%ld: line too long", cf->name, cf->lineno); exit(1); } else dst[i++] = (char)c; } } int cfg_setpfile(char *s) { if (strlen(s) >= sizeof(pfile)) { syslog(LLEV,"fwtksyserr: netperm-table %.100s does not fit path storage",s); return(1); } strlcpy(pfile,s,sizeof(pfile)); return(0); } static int process_var(char *line) { char *nam, *val; struct config_var *cvp, *entry; char tokbuf[MAX_STR]; char *av[MAX_ARG]; int ac; nam = xstrdup(line); if (!(val = strchr(nam,'='))) return(1); *(val++) = '\0'; strtrm(nam); /* We use the first arg only; the purpose of whole ugly thing * is just to make sure quotes and stuff processing is exactly * similar to one we have elsewhere. */ if ((ac = enargv(val,av, sizeof(av) / sizeof(char *), tokbuf,sizeof(tokbuf))) != 1 ) return(1); entry = (struct config_var*) xmalloc(sizeof(struct config_var)); entry->name = xstrdup(nam); entry->value = xstrdup(av[0]); entry->next = NULL; if (config_vars) { for (cvp = config_vars; cvp->next; cvp = cvp->next) ; cvp->next = entry; } else config_vars = entry; free(nam); return(0); } static char* get_var(const char* var) { struct config_var *cvp; if (*var != '$') { syslog(LLEV,"fwtksyserr: internal logic error in macro processing"); exit(1); } if (config_vars) { for (cvp = config_vars; cvp; cvp = cvp->next) { if (!strcmp(var+1, cvp->name)) return(cvp->value); } } syslog(LLEV,"fwtkcfgerr: macro %.128s not found", var); exit(1); } static int expand_vars(int ac, char **av, int avsiz, char *tobuf, int bsiz) { char *newbuf = xmalloc(bsiz); char *op; char *oav[MAX_ARG]; int len, icnt, ocnt = 0; int recursion_needed = 0; op = newbuf; bzero(newbuf, bsiz); bzero(oav, sizeof(oav)); for (icnt = 0; icnt < ac; icnt++) { if(av[icnt][0] != '$') { if (op + (len = strlen(av[icnt])) >= newbuf + bsiz) return(-1); memcpy(op, av[icnt], len); oav[ocnt] = op; *(op += len) = '\0'; op++; ocnt++; if (ocnt >= MAX_ARG) { syslog(LLEV,"fwtksyserr: macro reference too complicated"); exit(1); } } else { char ttokbuf[MAX_STR]; char *tav[MAX_ARG]; int tac, ticnt; if ((tac = enargv(get_var(av[icnt]),tav, sizeof(tav) / sizeof(char *), ttokbuf,sizeof(ttokbuf))) < 0) { } for (ticnt = 0; ticnt < tac; ticnt++) { recursion_needed |= (tav[ticnt][0] == '$'); if (op + (len = strlen(tav[ticnt])) >= newbuf + bsiz) return(-1); memcpy(op, tav[ticnt], len); oav[ocnt] = op; *(op += len) = '\0'; op++; ocnt++; if (ocnt >= MAX_ARG) { syslog(LLEV,"fwtksyserr: macro reference too complicated"); exit(1); } } } } memcpy(tobuf, newbuf, bsiz); memcpy(av, oav, sizeof(oav)); if (recursion_needed) return(expand_vars(ocnt,av,sizeof(oav) / sizeof(char *), tobuf, bsiz)); else return(ocnt); } Cfg* cfg_append(char *cfile,Cfg *chainstart,char *app) { Cfg *newcfg; Cfg *entry; char buf[MAX_CFG_ENTRY]; struct config_file cfs; cfs.lineno = 0; cfs.name = strdup(cfile); if (!(cfs.f=fopen(cfile,"r"))) { syslog(LLEV,"fwtksyserr: cannot open netperm-table file %.512s: %.64s", cfile, strerror(errno)); exit(1); } newcfg = chainstart; if ((chainstart != (Cfg*) -1) && chainstart) { while (newcfg->next) newcfg = newcfg->next; } else chainstart = NULL; while (!read_config_line(&cfs,buf,sizeof(buf))) { char *p; char *parms; if (buf[0] == '#') continue; for (p = buf; isspace(*p); p++) ; if (!*p) continue; if (!strncmp(p,"include",7)) { /* * Check if include statement is empty */ if (!*(p+=7)) { syslog(LLEV,"fwtkcfgerr: %.200s line %ld malformed",cfile,cfs.lineno); continue; } /* * Check it is not "include" but something else * fall through, it may be a valid tag */ if (isspace(*p++)) { while (isspace(*p)) p++; /* * Do include */ chainstart = cfg_append(p, chainstart, app); continue; } } if (!(p = strchr(buf,':')) ) { if (process_var(buf)) syslog(LLEV,"fwtkcfgerr: %.200s line %ld malformed",cfile,cfs.lineno); continue; } *p++ = '\0'; parms = p; /* who cares what tags are there for empty record? */ if (!*parms) { syslog(LLEV,"fwtkcfgerr: %.200s line %ld has no parameters",cfile,cfs.lineno); continue; } p = strtok(buf,","); do { char tok[sizeof(buf)]; strncpy(tok, p, sizeof(tok)); strtrm(tok); if (!strcasecmp(tok,app) || !strcmp(tok,"*")) break; } while ((p = strtok(NULL,","))); strtrm(p); if (!p) continue; if (!process_var(parms)) continue; entry = (Cfg *)xmalloc(sizeof(Cfg)); p = strtok(parms," \t\n"); entry->flags = 0; if (!strncmp(p,"permit-",7)) { entry->flags |= PERM_ALLOW; entry->op = xstrdup(p+7); } else if (!strncmp(p,"deny-",5)) { entry->flags |= PERM_DENY; entry->op = xstrdup(p+5); } else entry->op = xstrdup(p); entry->argc = 0; entry->argv = (char **) xmalloc(sizeof(char *)); entry->argv[0] = NULL ; if ((p=strtok(NULL,"\n"))) { char tokbuf[MAX_CFG_ENTRY]; char *av[MAX_ARG]; int ac; if ((ac = enargv(p,av,sizeof(av) / sizeof(char *),tokbuf,sizeof(tokbuf))) < 0) { syslog(LLEV,"fwtkcfgerr: %.512s line %d too long or misquoted",cfile,(int)cfs.lineno); exit(1); } if ((ac = expand_vars(ac,av,sizeof(av) / sizeof(char *),tokbuf,sizeof(tokbuf))) < 0) { syslog(LLEV,"fwtkcfgerr: %.512s line %d buffer overrun on macro processing",cfile,(int)cfs.lineno); exit(1); } for (entry->argc = 0; entry->argc argc++) { entry->argv[(entry->argc)] = xstrdup(av[entry->argc]); entry->argv = (char **) xrealloc(entry->argv,(entry->argc+2)*sizeof(char *)); entry->argv[entry->argc+1] = NULL; } } entry->ln = cfs.lineno; entry->next = NULL; if (!chainstart) chainstart = entry; else newcfg->next = entry; newcfg = entry; errno = 0; } if (errno) { syslog(LLEV,"fwtksyserr: error reading configuration file %.100s (%.50s)",cfile, strerror(errno)); exit(1); } return(chainstart ? chainstart : (Cfg*)-1 ); } Cfg* cfg_read(char *app) { return(cfg_append(pfile,(Cfg*)-1,app)); } Cfg* cfg_get(char *fac,Cfg *cp) { static Cfg* nextcf; if (!cp && !(cp = nextcf)) return(NULL); while (cp && strcasecmp(fac,cp->op)) cp = cp->next; nextcf = cp ? cp->next : NULL; return(cp); } void cfg_free(Cfg *cp) { Cfg *next; while (cp) { next = cp->next; while (*cp->argv) free(*((cp->argv)++)); free(cp->op); free(cp); cp = next; } }