📄 dict.c
字号:
/* * dict.c Routines to read the dictionary file. * * Version: $Id: dict.c,v 1.50.2.3 2004/09/10 15:06:44 aland Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Copyright 2000 The FreeRADIUS server project */static const char rcsid[] = "$Id: dict.c,v 1.50.2.3 2004/09/10 15:06:44 aland Exp $";#include "autoconf.h"#include <stdlib.h>#include <ctype.h>#include <string.h>#ifdef HAVE_MALLOC_H#include <malloc.h>#endif#include "libradius.h"#include "missing.h"/* * There are very few vendors, and they're looked up only when we * read the dictionaries. So it's OK to have a singly linked * list here. */static DICT_VENDOR *dictionary_vendors = NULL;static rbtree_t *attributes_byname = NULL;static rbtree_t *attributes_byvalue = NULL;static rbtree_t *values_byvalue = NULL;static rbtree_t *values_byname = NULL;typedef struct value_fixup_t { char attrstr[40]; DICT_VALUE *dval; struct value_fixup_t *next;} value_fixup_t;/* * So VALUEs in the dictionary can have forward references. */static value_fixup_t *value_fixup = NULL;static const LRAD_NAME_NUMBER type_table[] = { { "string", PW_TYPE_STRING }, { "integer", PW_TYPE_INTEGER }, { "ipaddr", PW_TYPE_IPADDR }, { "date", PW_TYPE_DATE }, { "abinary", PW_TYPE_ABINARY }, { "octets", PW_TYPE_OCTETS }, { "ifid", PW_TYPE_IFID }, { "ipv6addr", PW_TYPE_IPV6ADDR }, { "ipv6prefix", PW_TYPE_IPV6PREFIX }, { NULL, 0 }};/* * Quick pointers to the base 0..255 attributes. * * These attributes are referenced a LOT, especially during * decoding of the on-the-wire packets. It's useful to keep a * cache of their dictionary entries, so looking them up is * O(1), instead of O(log(N)). (N==number of dictionary entries...) */static DICT_ATTR *base_attributes[256];/* * Free the dictionary_attributes and dictionary_values lists. */void dict_free(void){ DICT_VENDOR *dvend, *enext; memset(base_attributes, 0, sizeof(base_attributes)); for (dvend = dictionary_vendors; dvend; dvend = enext) { enext = dvend->next; free(dvend); } dictionary_vendors = NULL; /* * Free the tree of attributes by name and value. */ rbtree_free(attributes_byname); rbtree_free(attributes_byvalue); attributes_byname = NULL; attributes_byvalue = NULL; rbtree_free(values_byname); rbtree_free(values_byvalue); values_byname = NULL; values_byvalue = NULL;}/* * Add vendor to the list. */int dict_addvendor(const char *name, int value){ DICT_VENDOR *vval; if (value >= (1 << 16)) { librad_log("dict_addvendor: Cannot handle vendor ID larger than 65535"); return -1; } if (strlen(name) > (sizeof(vval->name) -1)) { librad_log("dict_addvendor: vendor name too long"); return -1; } if ((vval =(DICT_VENDOR *)malloc(sizeof(DICT_VENDOR))) == NULL) { librad_log("dict_addvendor: out of memory"); return -1; } strcpy(vval->name, name); vval->vendorpec = value; /* Insert at front. */ vval->next = dictionary_vendors; dictionary_vendors = vval; return 0;}/* * Add an attribute to the dictionary. */int dict_addattr(const char *name, int vendor, int type, int value, ATTR_FLAGS flags){ static int max_attr = 0; DICT_ATTR *attr; if (strlen(name) > (sizeof(attr->name) -1)) { librad_log("dict_addattr: attribute name too long"); return -1; } /* * If the value is '-1', that means use a pre-existing * one (if it already exists). If one does NOT already exist, * then create a new attribute, with a non-conflicting value, * and use that. */ if (value == -1) { attr = dict_attrbyname(name); if (attr != NULL) { return 0; /* exists, don't add it again */ } value = ++max_attr; } else if (vendor == 0) { /* * Update 'max_attr' */ if (value > max_attr) { max_attr = value; } } if (value >= 65536) { librad_log("dict_addattr: ATTRIBUTE has invalid number."); return -1; } /* * Create a new attribute for the list */ if ((attr = (DICT_ATTR *)malloc(sizeof(DICT_ATTR))) == NULL) { librad_log("dict_addattr: out of memory"); return -1; } strcpy(attr->name, name); attr->attr = value; attr->type = type; attr->flags = flags; if (vendor) attr->attr |= (vendor << 16); /* * Insert the attribute, only if it's not a duplicate. */ if (rbtree_insert(attributes_byname, attr) == 0) { DICT_ATTR *a; /* * If the attribute has identical number, then * ignore the duplicate. */ a = rbtree_finddata(attributes_byname, attr); if (a && (strcasecmp(a->name, attr->name) == 0)) { if (a->attr != attr->attr) { librad_log("dict_addattr: Duplicate attribute name %s", name); return -1; } /* * Same name, same attr, maybe the * flags and/or type is different. * Let the new value over-ride the * old one. */ } } if ((attr->attr >= 0) && (attr->attr < 256)) { /* * If it's an on-the-wire base attribute, * then keep a quick reference to it, for speed. */ base_attributes[attr->attr] = attr; } /* * Insert the SAME pointer (not free'd when this tree is * deleted), into another tree. * * If the newly inserted entry is a duplicate of an existing * entry, then the old entry is tossed, and the new one * replaces it. This behaviour is configured in the * rbtree_create() function. * * We want this behaviour because we want OLD names for * the attributes to be read from the configuration * files, but when we're printing them, (and looking up * by value) we want to use the NEW name. */ rbtree_insert(attributes_byvalue, attr); return 0;}/* * Add a value for an attribute to the dictionary. */int dict_addvalue(const char *namestr, char *attrstr, int value){ DICT_ATTR *dattr; DICT_VALUE *dval; if (strlen(namestr) > (sizeof(dval->name) -1)) { librad_log("dict_addvalue: value name too long"); return -1; } if ((dval = (DICT_VALUE *)malloc(sizeof(DICT_VALUE))) == NULL) { librad_log("dict_addvalue: out of memory"); return -1; } memset(dval, 0, sizeof(*dval)); strcpy(dval->name, namestr); dval->value = value; /* * Remember which attribute is associated with this * value, if possible. */ dattr = dict_attrbyname(attrstr); if (dattr) { dval->attr = dattr->attr; } else { value_fixup_t *fixup; fixup = (value_fixup_t *) malloc(sizeof(*fixup)); if (!fixup) { librad_log("dict_addvalue: out of memory"); return -1; } memset(fixup, 0, sizeof(*fixup)); strNcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr)); fixup->dval = dval; /* * Insert to the head of the list. */ fixup->next = value_fixup; value_fixup = fixup; return 0; } /* * Add the value into the dictionary. */ if (rbtree_insert(values_byname, dval) == 0) { if (dattr) { DICT_VALUE *dup; /* * Suppress duplicates with the same * name and value. There are lots in * dictionary.ascend. */ dup = dict_valbyname(dattr->attr, namestr); if (dup && (dup->value == dval->value)) { free(dval); return 0; } } librad_log("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr); return -1; } rbtree_insert(values_byvalue, dval); return 0;}/* * Process the ATTRIBUTE command */static int process_attribute(const char* fn, const int line, const int block_vendor, const char* data){ int vendor; char namestr[256]; char valstr[256]; char typestr[256]; char optstr[256]; int value; int type; char *s, *c; ATTR_FLAGS flags; vendor = 0; optstr[0] = 0; if(sscanf(data, "%s%s%s%s", namestr, valstr, typestr, optstr) < 3) { librad_log("dict_init: %s[%d]: invalid ATTRIBUTE line", fn, line); return -1; } /* * Validate all entries */ if (!isdigit((int) *valstr)) { librad_log("dict_init: %s[%d]: invalid value", fn, line); return -1; } if (valstr[0] != '0') value = atoi(valstr); else sscanf(valstr, "%i", &value); /* * find the type of the attribute. */ type = lrad_str2int(type_table, typestr, -1); if (type < 0) { librad_log("dict_init: %s[%d]: invalid type \"%s\"", fn, line, typestr); return -1; } /* * Ignore comments */ if (optstr[0] == '#') optstr[0] = '\0'; /* * Only look up the vendor if the string * is non-empty. */ memset(&flags, 0, sizeof(flags)); s = strtok(optstr, ","); while(s) { if (strcmp(s, "has_tag") == 0 || strcmp(s, "has_tag=1") == 0) { /* Boolean flag, means this is a tagged attribute */ flags.has_tag = 1; } else if (strncmp(s, "len+=", 5) == 0 || strncmp(s, "len-=", 5) == 0) { /* Length difference, to accomodate braindead NASes & their vendors */ flags.len_disp = strtol(s + 5, &c, 0); if (*c) { librad_log("dict_init: %s[%d] invalid option %s", fn, line, s); return -1; } if (s[3] == '-') { flags.len_disp = -flags.len_disp; } } else if (strncmp(s, "encrypt=", 8) == 0) { /* Encryption method, defaults to 0 (none). Currently valid is just type 2, Tunnel-Password style, which can only be applied to strings. */ flags.encrypt = strtol(s + 8, &c, 0); if (*c) { librad_log( "dict_init: %s[%d] invalid option %s", fn, line, s); return -1; } } else { /* Must be a vendor 'flag'... */ if (strncmp(s, "vendor=", 5) == 0) { /* New format */ s += 5; } vendor = dict_vendorbyname(s); if (!vendor) { librad_log( "dict_init: %s[%d]: unknown vendor %s", fn, line, optstr); return -1; } if (block_vendor && optstr[0] && (block_vendor != vendor)) { librad_log("dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block", fn, line, optstr); return -1; } } s = strtok(NULL, ","); } if (block_vendor) vendor = block_vendor; if (dict_addattr(namestr, vendor, type, value, flags) < 0) { librad_log("dict_init: %s[%d]: %s", fn, line, librad_errstr); return -1; } return 0;}/* * Process the VALUE command */static int process_value(const char* fn, const int line, const char* data){ char namestr[256]; char valstr[256]; char attrstr[256]; int value; if (sscanf(data, "%s%s%s", attrstr, namestr, valstr) != 3) { librad_log("dict_init: %s[%d]: invalid VALUE line", fn, line); return -1; } /* * For Compatibility, skip "Server-Config" */ if (strcasecmp(attrstr, "Server-Config") == 0) return 0; /* * Validate all entries */ if (!isdigit((int) *valstr)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -