📄 conffile.c
字号:
/* * conffile.c Read the radiusd.conf file. * * Yep I should learn to use lex & yacc, or at least * write a decent parser. I know how to do that, really :) * miquels@cistron.nl * * Version: $Id: conffile.c,v 1.199 2008/04/18 13:51:12 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006 The FreeRADIUS server project * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl> * Copyright 2000 Alan DeKok <aland@ox.org> */#include <freeradius-devel/ident.h>RCSID("$Id: conffile.c,v 1.199 2008/04/18 13:51:12 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/rad_assert.h>#ifdef HAVE_DIRENT_H#include <dirent.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#include <ctype.h>typedef enum conf_type { CONF_ITEM_INVALID = 0, CONF_ITEM_PAIR, CONF_ITEM_SECTION, CONF_ITEM_DATA} CONF_ITEM_TYPE;struct conf_item { struct conf_item *next; struct conf_part *parent; int lineno; const char *filename; CONF_ITEM_TYPE type;};struct conf_pair { CONF_ITEM item; const char *attr; const char *value; FR_TOKEN operator; FR_TOKEN value_type;};struct conf_part { CONF_ITEM item; const char *name1; const char *name2; struct conf_item *children; struct conf_item *tail; /* for speed */ CONF_SECTION *template; rbtree_t *pair_tree; /* and a partridge.. */ rbtree_t *section_tree; /* no jokes here */ rbtree_t *name2_tree; /* for sections of the same name2 */ rbtree_t *data_tree; void *base; int depth; const CONF_PARSER *variables;};/* * Internal data that is associated with a configuration section, * so that we don't have to track it separately. */struct conf_data { CONF_ITEM item; const char *name; int flag; void *data; /* user data */ void (*free)(void *); /* free user data function */};static int cf_data_add_internal(CONF_SECTION *cs, const char *name, void *data, void (*data_free)(void *), int flag);static void *cf_data_find_internal(CONF_SECTION *cs, const char *name, int flag);int cf_log_config = 1;int cf_log_modules = 1;/* * Isolate the scary casts in these tiny provably-safe functions */CONF_PAIR *cf_itemtopair(CONF_ITEM *ci){ if (ci == NULL) return NULL; rad_assert(ci->type == CONF_ITEM_PAIR); return (CONF_PAIR *)ci;}CONF_SECTION *cf_itemtosection(CONF_ITEM *ci){ if (ci == NULL) return NULL; rad_assert(ci->type == CONF_ITEM_SECTION); return (CONF_SECTION *)ci;}CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp){ if (cp == NULL) return NULL; return (CONF_ITEM *)cp;}CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs){ if (cs == NULL) return NULL; return (CONF_ITEM *)cs;}static CONF_DATA *cf_itemtodata(CONF_ITEM *ci){ if (ci == NULL) return NULL; rad_assert(ci->type == CONF_ITEM_DATA); return (CONF_DATA *)ci;}static CONF_ITEM *cf_datatoitem(CONF_DATA *cd){ if (cd == NULL) return NULL; return (CONF_ITEM *)cd;}/* * Create a new CONF_PAIR */static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value, FR_TOKEN operator, FR_TOKEN value_type, CONF_SECTION *parent){ char *p; size_t attr_len, value_len = 0; CONF_PAIR *cp; if (!attr) return NULL; attr_len = strlen(attr) + 1; if (value) value_len = strlen(value) + 1; p = rad_malloc(sizeof(*cp) + attr_len + value_len); cp = (CONF_PAIR *) p; memset(cp, 0, sizeof(*cp)); cp->item.type = CONF_ITEM_PAIR; cp->item.parent = parent; p += sizeof(*cp); memcpy(p, attr, attr_len); cp->attr = p; if (value) { p += attr_len; memcpy(p, value, value_len); cp->value = p; } cp->value_type = value_type; cp->operator = operator; return cp;}/* * Free a CONF_PAIR */void cf_pair_free(CONF_PAIR **cp){ if (!cp || !*cp) return; /* * attr && value are allocated contiguous with cp. */#ifndef NDEBUG memset(*cp, 0, sizeof(*cp));#endif free(*cp); *cp = NULL;}static void cf_data_free(CONF_DATA **cd){ if (!cd || !*cd) return; /* name is allocated contiguous with cd */ if (!(*cd)->free) { free((*cd)->data); } else { ((*cd)->free)((*cd)->data); }#ifndef NDEBUG memset(*cd, 0, sizeof(*cd));#endif free(*cd); *cd = NULL;}/* * rbtree callback function */static int pair_cmp(const void *a, const void *b){ const CONF_PAIR *one = a; const CONF_PAIR *two = b; return strcmp(one->attr, two->attr);}/* * rbtree callback function */static int section_cmp(const void *a, const void *b){ const CONF_SECTION *one = a; const CONF_SECTION *two = b; return strcmp(one->name1, two->name1);}/* * rbtree callback function */static int name2_cmp(const void *a, const void *b){ const CONF_SECTION *one = a; const CONF_SECTION *two = b; rad_assert(strcmp(one->name1, two->name1) == 0); if (!one->name2 && !two->name2) return 0; if (!one->name2) return -1; if (!two->name2) return +1; return strcmp(one->name2, two->name2);}/* * rbtree callback function */static int data_cmp(const void *a, const void *b){ int rcode; const CONF_DATA *one = a; const CONF_DATA *two = b; rcode = one->flag - two->flag; if (rcode != 0) return rcode; return strcmp(one->name, two->name);}/* * Free strings we've parsed into data structures. */void cf_section_parse_free(CONF_SECTION *cs, void *base){ int i; const CONF_PARSER *variables = cs->variables; /* * Don't automatically free the strings if we're being * called from a module. This is also for clients.c, * where client_free() expects to be able to free the * client structure. If we moved everything to key off * of the config files, we might solve some problems... */ if (!variables) return; /* * Free up dynamically allocated string pointers. */ for (i = 0; variables[i].name != NULL; i++) { char **p; if ((variables[i].type != PW_TYPE_STRING_PTR) && (variables[i].type != PW_TYPE_FILENAME)) { continue; } /* * No base struct offset, data must be the pointer. * If data doesn't exist, ignore the entry, there * must be something wrong. */ if (!base) { if (!variables[i].data) { continue; } p = (char **) variables[i].data;; } else if (variables[i].data) { p = (char **) variables[i].data;; } else { p = (char **) (((char *)base) + variables[i].offset); } free(*p); *p = NULL; }}/* * Free a CONF_SECTION */void cf_section_free(CONF_SECTION **cs){ CONF_ITEM *ci, *next; if (!cs || !*cs) return; cf_section_parse_free(*cs, (*cs)->base); for (ci = (*cs)->children; ci; ci = next) { next = ci->next; switch (ci->type) { case CONF_ITEM_PAIR: { CONF_PAIR *pair = cf_itemtopair(ci); cf_pair_free(&pair); } break; case CONF_ITEM_SECTION: { CONF_SECTION *section = cf_itemtosection(ci); cf_section_free(§ion); } break; case CONF_ITEM_DATA: { CONF_DATA *data = cf_itemtodata(ci); cf_data_free(&data); } break; default: /* should really be an error. */ break; } } /* * Name1 and name2 are allocated contiguous with * cs. */ if ((*cs)->pair_tree) rbtree_free((*cs)->pair_tree); if ((*cs)->section_tree) rbtree_free((*cs)->section_tree); if ((*cs)->name2_tree) rbtree_free((*cs)->name2_tree); if ((*cs)->data_tree) rbtree_free((*cs)->data_tree); /* * And free the section */#ifndef NDEBUG memset(*cs, 0, sizeof(*cs));#endif free(*cs); *cs = NULL;}/* * Allocate a CONF_SECTION */static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2, CONF_SECTION *parent){ size_t name1_len, name2_len = 0; char *p; CONF_SECTION *cs; if (!name1) return NULL; name1_len = strlen(name1) + 1; if (name2) name2_len = strlen(name2) + 1; p = rad_malloc(sizeof(*cs) + name1_len + name2_len); cs = (CONF_SECTION *) p; memset(cs, 0, sizeof(*cs)); cs->item.type = CONF_ITEM_SECTION; cs->item.parent = parent; p += sizeof(*cs); memcpy(p, name1, name1_len); cs->name1 = p; if (name2 && *name2) { p += name1_len; memcpy(p, name2, name2_len); cs->name2 = p; } cs->pair_tree = rbtree_create(pair_cmp, NULL, 0); if (!cs->pair_tree) { cf_section_free(&cs); return NULL; } /* * Don't create a data tree, it may not be needed. */ /* * Don't create the section tree here, it may not * be needed. */ if (parent) cs->depth = parent->depth + 1; return cs;}/* * Add an item to a configuration section. */static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci){ if (!cs->children) { rad_assert(cs->tail == NULL); cs->children = ci; } else { rad_assert(cs->tail != NULL); cs->tail->next = ci; } /* * Update the trees (and tail) for each item added. */ for (/* nothing */; ci != NULL; ci = ci->next) { cs->tail = ci; /* * For fast lookups, pair's and sections get * added to rbtree's. */ switch (ci->type) { case CONF_ITEM_PAIR: rbtree_insert(cs->pair_tree, ci); break; case CONF_ITEM_SECTION: { CONF_SECTION *cs_new = cf_itemtosection(ci); if (!cs->section_tree) { cs->section_tree = rbtree_create(section_cmp, NULL, 0); /* ignore any errors */ } if (cs->section_tree) { rbtree_insert(cs->section_tree, cs_new); } /* * Two names: find the named instance. */ { CONF_SECTION *old_cs; /* * Find the FIRST * CONF_SECTION having * the given name1, and * create a new tree * under it. */ old_cs = rbtree_finddata(cs->section_tree, cs_new); if (!old_cs) return; /* this is a bad error! */ if (!old_cs->name2_tree) { old_cs->name2_tree = rbtree_create(name2_cmp, NULL, 0); } if (old_cs->name2_tree) { rbtree_insert(old_cs->name2_tree, cs_new); } } /* had a name2 */ break; } /* was a section */ case CONF_ITEM_DATA: if (!cs->data_tree) { cs->data_tree = rbtree_create(data_cmp, NULL, 0); } if (cs->data_tree) { rbtree_insert(cs->data_tree, ci); } break; default: /* FIXME: assert & error! */ break; } /* switch over conf types */ } /* loop over ci */}CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs, CONF_SECTION *outercs, const char *ptr){ CONF_PAIR *cp; CONF_SECTION *next; const CONF_SECTION *cs = outercs; char name[8192]; char *p; strlcpy(name, ptr, sizeof(name)); p = name; /* * ".foo" means "foo from the current section" */ if (*p == '.') { p++; /* * ..foo means "foo from the section * enclosing this section" (etc.) */ while (*p == '.') { if (cs->item.parent) cs = cs->item.parent; p++; } /* * "foo.bar.baz" means "from the root" */ } else if (strchr(p, '.') != NULL) { cs = parentcs; } while (*p) { char *q, *r; r = strchr(p, '['); q = strchr(p, '.'); if (!r && !q) break; if (r && q > r) q = NULL; if (q && q < r) r = NULL; /* * Split off name2. */ if (r) { q = strchr(r + 1, ']'); if (!q) return NULL; /* parse error */ /* * Points to foo[bar]xx: parse error, * it should be foo[bar] or foo[bar].baz */ if (q[1] && q[1] != '.') goto no_such_item; *r = '\0'; *q = '\0'; next = cf_section_sub_find_name2(cs, p, r + 1); *r = '['; *q = ']'; /* * Points to a named instance of a section. */ if (!q[1]) { if (!next) goto no_such_item; return cf_sectiontoitem(next); } q++; /* ensure we skip the ']' and '.' */ } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -