Beispiel #1
0
const char *vp_print_name(char *buffer, size_t bufsize, int attr)
{
	int vendor;
	size_t len = 0;

	if (!buffer) return NULL;

	vendor = VENDOR(attr);
	if (vendor) {
		DICT_VENDOR *v;
		
		v = dict_vendorbyvalue(vendor);
		if (v) {
			snprintf(buffer, bufsize, "%s-", v->name);
		} else {
			snprintf(buffer, bufsize, "Vendor-%u-", vendor);
		}

		len = strlen(buffer);
		if (len == bufsize) {
			return NULL;
		}
	}

	snprintf(buffer + len, bufsize - len, "Attr-%u", attr & 0xffff);
	len += strlen(buffer + len);
	if (len == bufsize) {
		return NULL;
	}

	return buffer;
}
Beispiel #2
0
/*
 *	Create a VALUE_PAIR from an ASCII attribute and value,
 *	where the attribute name is in the form:
 *
 *	Attr-%d
 *	Vendor-%d-Attr-%d
 *	VendorName-Attr-%d
 */
static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
				int operator)
{
	int		attr, vendor;
	size_t		size;
	const char	*p = attribute;
	char		*q;
	VALUE_PAIR	*vp;

	/*
	 *	Unknown attributes MUST be of type 'octets'
	 */
	if (value && (strncasecmp(value, "0x", 2) != 0)) {
		fr_strerror_printf("Unknown attribute \"%s\" requires a hex string, not \"%s\"", attribute, value);
		return NULL;
	}

	vendor = 0;

	/*
	 *	Pull off vendor prefix first.
	 */
	if (strncasecmp(p, "Attr-", 5) != 0) {
		if (strncasecmp(p, "Vendor-", 7) == 0) {
			vendor = (int) strtol(p + 7, &q, 10);
			if ((vendor == 0) || (vendor > 65535)) {
				fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
				return NULL;
			}

			p = q;

		} else {	/* must be vendor name */
			char buffer[256];

			q = strchr(p, '-');

			if (!q) {
				fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
				return NULL;
			}

			if ((size_t) (q - p) >= sizeof(buffer)) {
				fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
				return NULL;
			}

			memcpy(buffer, p, (q - p));
			buffer[q - p] = '\0';

			vendor = dict_vendorbyname(buffer);
			if (!vendor) {
				fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
				return NULL;
			}

			p = q;
		}

		if (*p != '-') {
			fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
			return NULL;
		}
		p++;
	}

	/*
	 *	Attr-%d
	 */
	if (strncasecmp(p, "Attr-", 5) != 0) {
		fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
		return NULL;
	}

	attr = strtol(p + 5, &q, 10);

	/*
	 *	Invalid, or trailing text after number.
	 */
	if ((attr == 0) || *q) {
		fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
		return NULL;
	}

	/*
	 *	Double-check the size of attr.
	 */
	if (vendor) {
		DICT_VENDOR *dv = dict_vendorbyvalue(vendor);

		if (!dv) {
			if (attr > 255) {
			attr_error:
				fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
				return NULL;
			}

		} else switch (dv->type) {
			case 1:
				if (attr > 255) goto attr_error;
				break;

			case 2:
				if (attr > 65535) goto attr_error;
				break;

			case 4:	/* Internal limitations! */
				if (attr > 65535) goto attr_error;
				break;

			default:
				fr_strerror_printf("Internal sanity check failed");
				return NULL;
		}
	}

	attr |= vendor << 16;

	/*
	 *	We've now parsed the attribute properly, Let's create
	 *	it.  This next stop also looks the attribute up in the
	 *	dictionary, and creates the appropriate type for it.
	 */
	if ((vp = paircreate(attr, PW_TYPE_OCTETS)) == NULL) {
		fr_strerror_printf("out of memory");
		return NULL;
	}

	vp->operator = (operator == 0) ? T_OP_EQ : operator;
	if (!value) return vp;

	size = strlen(value + 2);

	/*
	 *	We may be reading something like Attr-5.  i.e.
	 *	who-ever wrote the text didn't understand it, but we
	 *	do.
	 */
	switch (vp->type) {
	default:
		if (size == (vp->length * 2)) break;
		vp->type = PW_TYPE_OCTETS;
		/* FALL-THROUGH */
		
	case PW_TYPE_OCTETS:
	case PW_TYPE_ABINARY:
		vp->length = size >> 1;
		if (vp->length > sizeof(vp->vp_octets)) {
			vp->length = sizeof(vp->vp_octets);
		}
		break;

	case PW_TYPE_STRING:
		vp->length = size >> 1;
		memset(&vp->vp_strvalue, 0, sizeof(vp->vp_strvalue));
		if (vp->length >= sizeof(vp->vp_strvalue)) {
			vp->length = sizeof(vp->vp_strvalue) - 1;
		}
		break;
	}

	if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
		fr_strerror_printf("Invalid hex string");
		free(vp);
		return NULL;
	}

	/*
	 *	Move contents around based on type.  This is
	 *	to work around the historical use of "lvalue".
	 */
	switch (vp->type) {
	case PW_TYPE_DATE:
	case PW_TYPE_IPADDR:
	case PW_TYPE_INTEGER:
		memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue));
		vp->vp_strvalue[0] = '\0';
		break;
		
	default:
		break;
	}
       
	return vp;
}
Beispiel #3
0
/** Print out attribute info
 *
 * Prints out all instances of a current attribute, or all attributes in a list.
 *
 * At higher debugging levels, also prints out alternative decodings of the same
 * value. This is helpful to determine types for unknown attributes of long
 * passed vendors, or just crazy/broken NAS.
 *
 * It's also useful for exposing issues in the packet decoding functions, as in
 * some cases they get fed random garbage data.
 *
 * This expands to a zero length string.
 */
static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
			       char *out, UNUSED size_t outlen)
{
	VALUE_PAIR *vp, **vps;
	REQUEST *current;
	value_pair_tmpl_t vpt;
	vp_cursor_t cursor;
	char buffer[1024];

	if (!RDEBUG_ENABLED2) {
		*out = '\0';
		return -1;
	}

	while (isspace((int) *fmt)) fmt++;
	if (*fmt == '&') fmt++;

	if (radius_parse_attr(fmt, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
		return -1;
	}

	current = request;
	if (radius_request(&current, vpt.request) < 0) return -2;

	vps = radius_list(current, vpt.list);
	if (!vps) {
		return -2;
	}

	RIDEBUG("Attributes matching \"%s\"", fmt);
	vp = fr_cursor_init(&cursor, vps);

	if (vpt.da) {
		vp = fr_cursor_next_by_num(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY);
	}
	while (vp) {
		DICT_ATTR *dac = NULL;
		DICT_VENDOR *dv;
		VALUE_PAIR *vpc = NULL;
		FR_NAME_NUMBER const *type;

		vp_prints_value(buffer, sizeof(buffer), vp, '\'');

		if (vp->da->flags.has_tag) {
			RIDEBUG2("\t%s:%s:%i %s %s",
				fr_int2str(pair_lists, vpt.list, "<INVALID>"),
				vp->da->name,
				vp->tag,
				fr_int2str(fr_tokens, vp->op, "<INVALID>"),
				buffer);
		} else {
			RIDEBUG2("\t%s:%s %s %s",
				fr_int2str(pair_lists, vpt.list, "<INVALID>"),
				vp->da->name,
				fr_int2str(fr_tokens, vp->op, "<INVALID>"),
				buffer);
		}

		if (!RDEBUG_ENABLED3) {
			goto next_vp;
		}

		if (vp->da->vendor) {
			dv = dict_vendorbyvalue(vp->da->vendor);
			RDEBUG3("\t\tvendor        : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
		}
		RDEBUG3("\t\ttype          : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
		RDEBUG3("\t\tlength        : %zu", vp->length);

		dac = talloc_memdup(request, vp->da, sizeof(DICT_ATTR));
		if (!dac) {
			return -1;
		}
		dac->flags.vp_free = 0;

		if (!RDEBUG_ENABLED4) {
			goto next_vp;
		}

		type = dict_attr_types;
		while (type->name) {
			int pad;
			ssize_t len;
			uint8_t const *data = NULL;
			vpc = NULL;

			if ((PW_TYPE) type->number == vp->da->type) {
				goto next_type;
			}

			switch (type->number) {
				case PW_TYPE_INVALID:		/* Not real type */
				case PW_TYPE_MAX:		/* Not real type */
				case PW_TYPE_EXTENDED:		/* Not safe/appropriate */
				case PW_TYPE_LONG_EXTENDED:	/* Not safe/appropriate */
				case PW_TYPE_TLV:		/* Not safe/appropriate */
				case PW_TYPE_VSA:		/* @fixme We need special behaviour for these */
					goto next_type;
				default:
					break;
			}

			dac->type = type->number;
			len = rad_vp2data(&data, vp);
			if (len < 0) {
				goto next_type;
			}
			if (data2vp(NULL, NULL, NULL, dac, data, len, len, &vpc) < 0) {
				goto next_type;
			}

			/*
			 *	data2vp has knowledge of expected format lengths, if the length
			 *	from rad_vp2data doesn't match, it encodes the attribute
			 *	as raw octets. This results in many useless debug lines with
			 *	the same hex string.
			 */
			if ((type->number != PW_TYPE_OCTETS) && (vpc->da->type == PW_TYPE_OCTETS)) {
				goto next_type;
			}

			if (!vp_prints_value(buffer, sizeof(buffer), vpc, '\'')) {
				goto next_type;
			}

			if ((pad = (11 - strlen(type->name))) < 0) {
				pad = 0;
			}

			/*
			 *	@fixme: if the value happens to decode as a VSA
			 *	(someone put a VSA into a VSA?), we probably to print
			 *	extended info for that/reparse
			 */
			RDEBUG4("\t\tas %s%*s: %s", type->name, pad, " ", buffer);

			next_type:
			talloc_free(vpc);
			type++;
		}
		next_vp:

		talloc_free(dac);

		if (vpt.da) {
			vp = fr_cursor_next_by_num(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY);
		} else {
			vp = fr_cursor_next(&cursor);
		}
	}

	*out = '\0';
	return 0;
}
Beispiel #4
0
/*
 *	Add an attribute to the dictionary.
 */
int dict_addattr(const char *name, int vendor, int type, int value,
		 ATTR_FLAGS flags)
{
	size_t namelen;
	static int      max_attr = 0;
	DICT_ATTR	*attr;

	namelen = strlen(name);
	if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
		fr_strerror_printf("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) {
		fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
		return -1;
	}

	if (value >= 65536) {
		fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 65535).");
		return -1;
	}

	if (vendor) {
		DICT_VENDOR *dv;
		static DICT_VENDOR *last_vendor = NULL;

		if (flags.is_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
			fr_strerror_printf("Sub-TLV's cannot be encrypted");
			return -1;
		}

		if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
			fr_strerror_printf("TLV's cannot be encrypted");
			return -1;
		}

		if (flags.is_tlv && flags.has_tag) {
			fr_strerror_printf("Sub-TLV's cannot have a tag");
			return -1;
		}

		if (flags.has_tlv && flags.has_tag) {
			fr_strerror_printf("TLV's cannot have a tag");
			return -1;
		}

		/*
		 *	Most ATTRIBUTEs are bunched together by
		 *	VENDOR.  We can save a lot of lookups on
		 *	dictionary initialization by caching the last
		 *	vendor.
		 */
		if (last_vendor && (vendor == last_vendor->vendorpec)) {
			dv = last_vendor;
		} else {
			dv = dict_vendorbyvalue(vendor);
			last_vendor = dv;
		}

		/*
		 *	If the vendor isn't defined, die.
		 */
		if (!dv) {
			fr_strerror_printf("dict_addattr: Unknown vendor");
			return -1;
		}

		/*
		 *	FIXME: Switch over dv->type, and limit things
		 *	properly.
		 */
		if ((dv->type == 1) && (value >= 256) && !flags.is_tlv) {
			fr_strerror_printf("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 = fr_pool_alloc(sizeof(*attr) + namelen)) == NULL) {
		fr_strerror_printf("dict_addattr: out of memory");
		return -1;
	}

	memcpy(attr->name, name, namelen);
	attr->name[namelen] = '\0';
	attr->attr = value;
	attr->attr |= (vendor << 16); /* FIXME: hack */
	attr->vendor = vendor;
	attr->type = type;
	attr->flags = flags;
	attr->vendor = vendor;

	/*
	 *	Insert the attribute, only if it's not a duplicate.
	 */
	if (!fr_hash_table_insert(attributes_byname, attr)) {
		DICT_ATTR	*a;

		/*
		 *	If the attribute has identical number, then
		 *	ignore the duplicate.
		 */
		a = fr_hash_table_finddata(attributes_byname, attr);
		if (a && (strcasecmp(a->name, attr->name) == 0)) {
			if (a->attr != attr->attr) {
				fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
				fr_pool_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.
			 */
		}


		fr_hash_table_delete(attributes_byvalue, a);

		if (!fr_hash_table_replace(attributes_byname, attr)) {
			fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
			fr_pool_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 (!fr_hash_table_replace(attributes_byvalue, attr)) {
		fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
		return -1;
	}

	if (!vendor && (value > 0) && (value < 256)) {
	 	 dict_base_attrs[value] = attr;
	}

	return 0;
}
Beispiel #5
0
/*
 *	Process the VENDOR command
 */
static int process_vendor(const char* fn, const int line, char **argv,
			  int argc)
{
	int	value;
	int	continuation = 0;
	const	char *format = NULL;

	if ((argc < 2) || (argc > 3)) {
		fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
			    fn, line);
		return -1;
	}

	/*
	 *	 Validate all entries
	 */
	if (!isdigit((int) argv[1][0])) {
		fr_strerror_printf("dict_init: %s[%d]: invalid value",
			fn, line);
		return -1;
	}
	value = atoi(argv[1]);

	/* Create a new VENDOR entry for the list */
	if (dict_addvendor(argv[0], value) < 0) {
		char buffer[256];

		strlcpy(buffer, fr_strerror(), sizeof(buffer));

		fr_strerror_printf("dict_init: %s[%d]: %s",
			   fn, line, buffer);
		return -1;
	}

	/*
	 *	Look for a format statement
	 */
	if (argc == 3) {
		format = argv[2];

	} else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
		format = "format=4,0";

	} else if (value == VENDORPEC_LUCENT) {
		format = "format=2,1";

	} else if (value == VENDORPEC_STARENT) {
		format = "format=2,2";

	} /* else no fixups to do */

	if (format) {
		int type, length;
		const char *p;
		DICT_VENDOR *dv;

		if (strncasecmp(format, "format=", 7) != 0) {
			fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
				   fn, line, format);
			return -1;
		}

		p = format + 7;
		if ((strlen(p) < 3) ||
		    !isdigit((int) p[0]) ||
		    (p[1] != ',') ||
		    !isdigit((int) p[2]) ||
		    (p[3] && (p[3] != ','))) {
			fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
				   fn, line, p);
			return -1;
		}

		type = (int) (p[0] - '0');
		length = (int) (p[2] - '0');

		if (p[3] == ',') {
			if ((p[4] != 'c') ||
			    (p[5] != '\0')) {
				fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
					   fn, line, p);
				return -1;
			}
			continuation = 1;
		}

		dv = dict_vendorbyvalue(value);
		if (!dv) {
			fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
				   fn, line);
			return -1;
		}

		if ((type != 1) && (type != 2) && (type != 4)) {
			fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
				   fn, line, type);
			return -1;
		}

		if ((length != 0) && (length != 1) && (length != 2)) {
			fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
				   fn, line, length);
			return -1;
		}

		dv->type = type;
		dv->length = length;
		dv->flags = continuation;
	}

	return 0;
}