⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dict.c

📁 新的radius程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * dict.c	Routines to read the dictionary file. * * Version:	$Id: dict.c,v 1.50.2.4.2.18 2007/04/07 21:41:38 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000  The FreeRADIUS server project */static const char rcsid[] = "$Id: dict.c,v 1.50.2.4.2.18 2007/04/07 21:41:38 aland Exp $";#include	"autoconf.h"#include	<stdlib.h>#include	<ctype.h>#include	<string.h>#ifdef HAVE_MALLOC_H#include	<malloc.h>#endif#ifdef HAVE_SYS_STAT_H#include	<sys/stat.h>#endif#include	<unistd.h>#include	"missing.h"#include	"libradius.h"#define DICT_VALUE_MAX_NAME_LEN (128)#define DICT_VENDOR_MAX_NAME_LEN (128)static lrad_hash_table_t *vendors_byname = NULL;static lrad_hash_table_t *vendors_byvalue = NULL;static lrad_hash_table_t *attributes_byname = NULL;static lrad_hash_table_t *attributes_byvalue = NULL;static lrad_hash_table_t *values_byvalue = NULL;static lrad_hash_table_t *values_byname = NULL;/* *	For faster HUP's, we cache the stat information for *	files we've $INCLUDEd */typedef struct dict_stat_t {	struct dict_stat_t *next;	char	   	   *name;	time_t		   mtime;} dict_stat_t;static char *stat_root_dir = NULL;static char *stat_root_file = NULL;static dict_stat_t *stat_head = NULL;static dict_stat_t *stat_tail = 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 }};/* *	Create the hash of the name. * *	We copy the hash function here because it's substantially faster. */#define FNV_MAGIC_INIT (0x811c9dc5)#define FNV_MAGIC_PRIME (0x01000193)static uint32_t dict_hashname(const char *name){	uint32_t hash = FNV_MAGIC_INIT;	const char *p;	for (p = name; *p != '\0'; p++) {		int c = *(const unsigned char *) p;		if (isalpha(c)) c = tolower(c);		hash *= FNV_MAGIC_PRIME;		hash ^= (uint32_t ) (c & 0xff);	}		return hash;}/* *	Hash callback functions. */static uint32_t dict_attr_name_hash(const void *data){	return dict_hashname(((const DICT_ATTR *)data)->name);}static int dict_attr_name_cmp(const void *one, const void *two){	const DICT_ATTR *a = one;	const DICT_ATTR *b = two;	return strcasecmp(a->name, b->name);}static uint32_t dict_attr_value_hash(const void *data){	return lrad_hash(&((const DICT_ATTR *)data)->attr,			 sizeof(((const DICT_ATTR *)data)->attr));}static int dict_attr_value_cmp(const void *one, const void *two){	const DICT_ATTR *a = one;	const DICT_ATTR *b = two;	return a->attr - b->attr;}static uint32_t dict_vendor_name_hash(const void *data){	return dict_hashname(((const DICT_VENDOR *)data)->name);}static int dict_vendor_name_cmp(const void *one, const void *two){	const DICT_VENDOR *a = one;	const DICT_VENDOR *b = two;	return strcasecmp(a->name, b->name);}static uint32_t dict_vendor_value_hash(const void *data){	return lrad_hash(&(((const DICT_VENDOR *)data)->vendorpec),			 sizeof(((const DICT_VENDOR *)data)->vendorpec));}static int dict_vendor_value_cmp(const void *one, const void *two){	const DICT_VENDOR *a = one;	const DICT_VENDOR *b = two;	return a->vendorpec - b->vendorpec;}static uint32_t dict_value_name_hash(const void *data){	uint32_t hash;	const DICT_VALUE *dval = data;	hash = dict_hashname(dval->name);	return lrad_hash_update(&dval->attr, sizeof(dval->attr), hash);}static int dict_value_name_cmp(const void *one, const void *two){	int rcode;	const DICT_VALUE *a = one;	const DICT_VALUE *b = two;	rcode = a->attr - b->attr;	if (rcode != 0) return rcode;	return strcasecmp(a->name, b->name);}static uint32_t dict_value_value_hash(const void *data){	uint32_t hash;	const DICT_VALUE *dval = data;	hash = lrad_hash(&dval->attr, sizeof(dval->attr));	return lrad_hash_update(&dval->value, sizeof(dval->value), hash);}static int dict_value_value_cmp(const void *one, const void *two){	int rcode;	const DICT_VALUE *a = one;	const DICT_VALUE *b = two;	rcode = a->attr - b->attr;	if (rcode != 0) return rcode;	return a->value - b->value;}/* *	Free the list of stat buffers */static void dict_stat_free(void){	dict_stat_t *this, *next;	free(stat_root_dir);	stat_root_dir = NULL;	free(stat_root_file);	stat_root_file = NULL;	if (!stat_head) {		stat_tail = NULL;		return;	}	for (this = stat_head; this != NULL; this = next) {		next = this->next;		free(this->name);		free(this);	}	stat_head = stat_tail = NULL;}/* *	Add an entry to the list of stat buffers. */static void dict_stat_add(const char *name, const struct stat *stat_buf){	dict_stat_t *this;	this = malloc(sizeof(*this));	if (!this) return;	memset(this, 0, sizeof(*this));	this->name = strdup(name);	this->mtime = stat_buf->st_mtime;	if (!stat_head) {		stat_head = stat_tail = this;	} else {		stat_tail->next = this;		stat_tail = this;	}}/* *	See if any dictionaries have changed.  If not, don't *	do anything. */static int dict_stat_check(const char *root_dir, const char *root_file){	struct stat buf;	dict_stat_t *this;	if (!stat_root_dir) return 0;	if (!stat_root_file) return 0;	if (strcmp(root_dir, stat_root_dir) != 0) return 0;	if (strcmp(root_file, stat_root_file) != 0) return 0;	if (!stat_head) return 0; /* changed, reload */	for (this = stat_head; this != NULL; this = this->next) {		if (stat(this->name, &buf) < 0) return 0;		if (buf.st_mtime != this->mtime) return 0;	}	return 1;}/* *	Free the dictionary_attributes and dictionary_values lists. */void dict_free(void){	/*	 *	Free the tables	 */	lrad_hash_table_free(vendors_byname);	lrad_hash_table_free(vendors_byvalue);	vendors_byname = NULL;	vendors_byvalue = NULL;	lrad_hash_table_free(attributes_byname);	lrad_hash_table_free(attributes_byvalue);	attributes_byname = NULL;	attributes_byvalue = NULL;	lrad_hash_table_free(values_byname);	lrad_hash_table_free(values_byvalue);	values_byname = NULL;	values_byvalue = NULL;	dict_stat_free();}/* *	Add vendor to the list. */int dict_addvendor(const char *name, int value){	size_t length;	DICT_VENDOR *dv;	if (value >= (1 << 16)) {	       	librad_log("dict_addvendor: Cannot handle vendor ID larger than 65535");		return -1;	}	if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {		librad_log("dict_addvendor: vendor name too long");		return -1;	}		if ((dv = malloc(sizeof(*dv) + length)) == NULL) {		librad_log("dict_addvendor: out of memory");		return -1;	}	strcpy(dv->name, name);	dv->vendorpec  = value;	dv->type = dv->length = 1; /* defaults */	if (!lrad_hash_table_insert(vendors_byname, dv)) {		DICT_VENDOR *old_dv;		old_dv = lrad_hash_table_finddata(vendors_byname, dv);		if (!old_dv) {			librad_log("dict_addvendor: Failed inserting vendor name %s", name);			return -1;		}		if (old_dv->vendorpec != dv->vendorpec) {			librad_log("dict_addvendor: Duplicate vendor name %s", name);			return -1;		}		/*		 *	Already inserted.  Discard the duplicate entry.		 */		free(dv);		return 0;	}	/*	 *	Insert the SAME pointer (not free'd when this table is	 *	deleted), into another table.	 *	 *	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.	 */	if (!lrad_hash_table_replace(vendors_byvalue, dv)) {		librad_log("dict_addvendor: Failed inserting vendor %s",			   name);		return -1;	}	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) {		if (dict_attrbyname(name)) {			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 < 0) {		librad_log("dict_addattr: ATTRIBUTE has invalid number (less than zero)");		return -1;	}	if (value >= 65536) {		librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 65535).");		return -1;	}	if (vendor) {		DICT_VENDOR *dv = dict_vendorbyvalue(vendor);		/*		 *	If the vendor isn't defined, die/		 */		if (!dv) {			librad_log("dict_addattr: Unknown vendor");			return -1;		}		/*		 *	With a few exceptions, attributes can only be		 *	1..255.  The check above catches the less than		 *	zero case.		 */		if ((dv->type == 1) && (value >= 256)) {			librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");			return -1;		} /* else 256..65535 are allowed */	}	/*	 *	Create a new attribute for the list	 */	if ((attr = malloc(sizeof(*attr))) == NULL) {		librad_log("dict_addattr: out of memory");		return -1;	}	strcpy(attr->name, name);	attr->attr = value;	attr->attr |= (vendor << 16); /* FIXME: hack */	attr->type = type;	attr->flags = flags;	attr->vendor = vendor;	/*	 *	Insert the attribute, only if it's not a duplicate.	 */	if (!lrad_hash_table_insert(attributes_byname, attr)) {		DICT_ATTR	*a;		/*		 *	If the attribute has identical number, then		 *	ignore the duplicate.		 */		a = lrad_hash_table_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);				free(attr);				return -1;			}			/*			 *	Same name, same vendor, same attr,			 *	maybe the flags and/or type is			 *	different.  Let the new value			 *	over-ride the old one.			 */		}		lrad_hash_table_delete(attributes_byvalue, a);		if (!lrad_hash_table_replace(attributes_byname, attr)) {			librad_log("dict_addattr: Internal error storing attribute %s", name);			free(attr);			return -1;		}	}	/*	 *	Insert the SAME pointer (not free'd when this entry is	 *	deleted), into another table.	 *	 *	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.	 */	if (!lrad_hash_table_replace(attributes_byvalue, attr)) {		librad_log("dict_addattr: Failed inserting attribute name %s", name);		return -1;	}	return 0;}/* *	Add a value for an attribute to the dictionary. */int dict_addvalue(const char *namestr, const char *attrstr, int value){	size_t		length;	DICT_ATTR	*dattr;	DICT_VALUE	*dval;	if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {		librad_log("dict_addvalue: value name too long");		return -1;	}	if ((dval = malloc(sizeof(*dval) + length)) == 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;		/*		 *	Octets is allowed as a work-around for the		 *	fact that branch_1_1 doesn't have BYTE or SHORT		 */		if ((dattr->type != PW_TYPE_INTEGER) &&		    (dattr->type != PW_TYPE_OCTETS)) {			free(dval);			librad_log("dict_addvalue: VALUEs can only be defined for'integer' types");			return -1;		}	} else {		value_fixup_t *fixup;				fixup = (value_fixup_t *) malloc(sizeof(*fixup));		if (!fixup) {			free(dval);			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 (!lrad_hash_table_insert(values_byname, dval)) {		if (dattr) {			DICT_VALUE *old;						/*			 *	Suppress duplicates with the same			 *	name and value.  There are lots in			 *	dictionary.ascend.			 */			old = dict_valbyname(dattr->attr, namestr);			if (old && (old->value == dval->value)) {				free(dval);				return 0;			}		}		free(dval);		librad_log("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);		return -1;	}	/*	 *	There are multiple VALUE's, keyed by attribute, so we	 *	take care of that here.	 */	if (!lrad_hash_table_replace(values_byvalue, dval)) {		librad_log("dict_addvalue: Failed inserting value %s",			   namestr);		return -1;	}	return 0;}/* *	Process the ATTRIBUTE command */static int process_attribute(const char* fn, const int line,			     const int block_vendor, char **argv,			     int argc){	int		vendor = 0;	int		value;	int		type;	char		*s, *c;	ATTR_FLAGS	flags;	if ((argc < 3) || (argc > 4)) {		librad_log("dict_init: %s[%d]: invalid ATTRIBUTE line",			fn, line);		return -1;	}	/*	 *	Validate all entries	 */	if (!isdigit((int) argv[1][0])) {		librad_log("dict_init: %s[%d]: invalid value", fn, line);		return -1;	}	sscanf(argv[1], "%i", &value);	/*	 *	find the type of the attribute.	 */	type = lrad_str2int(type_table, argv[2], -1);	if (type < 0) {		librad_log("dict_init: %s[%d]: invalid type \"%s\"",			fn, line, argv[2]);		return -1;	}	/*	 *	Only look up the vendor if the string	 *	is non-empty.	 */	memset(&flags, 0, sizeof(flags));	if (argc == 4) {		s = strtok(argv[3], ",");		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, "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=", 7) == 0) {					/* New format */					s += 7;				}								vendor = dict_vendorbyname(s);				if (!vendor) {					librad_log( "dict_init: %s[%d]: unknown vendor %s",						    fn, line, s);					return -1;				}				if (block_vendor && argv[3][0] &&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -