예제 #1
0
static int arp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
{
	int			i;
	uint8_t	const		*p = request->packet->data, *end = p + request->packet->data_len;
	fr_cursor_t		cursor;

	fr_cursor_init(&cursor, &request->packet->vps);

	for (i = 0; header_names[i].name != NULL; i++) {
		ssize_t			ret;
		size_t			len;
		fr_dict_attr_t const	*da;
		VALUE_PAIR		*vp = NULL;

		len = header_names[i].len;

		if (!fr_cond_assert((size_t)(end - p) < len)) return -1; /* Should have been detected in socket_recv */

		da = fr_dict_attr_by_name(dict_arp, header_names[i].name);
		if (!da) return 0;

		MEM(vp = fr_pair_afrom_da(request->packet, da));
		ret = fr_value_box_from_network(vp, &vp->data, da->type, da, p, len, true);
		if (ret <= 0) {
			fr_pair_to_unknown(vp);
			fr_pair_value_memcpy(vp, p, len);
		}

		DEBUG2("&%pP", vp);
		fr_cursor_insert(&cursor, vp);
	}

	return 0;
}
예제 #2
0
/**
 *
 * FIXME do something with mandatory
 */
ssize_t eap_fast_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_attr_t const *parent,
			     uint8_t const *data, size_t data_len,
			     void *decoder_ctx)
{
	fr_dict_attr_t const	*da;
	uint8_t	const		*p = data, *end = p + data_len;

	/*
	 *	Decode the TLVs
	 */
	while (p < end) {
		ssize_t		ret;
		uint16_t	attr;
		uint16_t	len;
		VALUE_PAIR	*vp;

		attr = fr_ntoh16_bin(p) & EAP_FAST_TLV_TYPE;
		p += 2;
		len = fr_ntoh16_bin(p);
		p += 2;

		da = fr_dict_attr_child_by_num(parent, attr);
		if (!da) {
			MEM(vp = fr_pair_afrom_child_num(ctx, parent, attr));

		} else if (da->type == FR_TYPE_TLV) {
			p += (size_t) eap_fast_decode_pair(ctx, cursor, parent, p, len, decoder_ctx);
			continue;

		} else {
			MEM(vp = fr_pair_afrom_da(ctx, da));
		}

		ret = fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da, p, len, true);
		if (ret != len) {
			fr_pair_to_unknown(vp);
			fr_pair_value_memcpy(vp, p, len, true);
		}
		fr_cursor_append(cursor, vp);
		p += len;
	}

	return p - data;
}
예제 #3
0
/** Builds attribute representing OID string and adds 'index' attributes where required
 *
 * Will convert an OID string in the format @verbatim .1.2.3.4.5.0 @endverbatim
 * into a pair with a #fr_dict_attr_t of the dictionary attribute matching the OID
 * string, as evaluated from the specified parent.
 *
 * If an OID component does not match a child of a previous OID component, but a child
 * with attribute number 0 exists, and a child with attribute number 1 also exists,
 * the child with attribute number 0 will be used as an 'index' pair, and will be
 * created with the value of the non matching OID component.
 *
 * Parsing will then resume using the child with attribute number 1.
 *
 * This allows traversals of SNMP tables to be represented by the sequence of pairs
 * and allows the full range of entry indexes which would not be possible if we represented
 * table index numbers as TLV attributes.
 *
 * @param[in] ctx	to allocate new pairs in.
 * @param[in] conf	radsnmp config.
 * @param[in] cursor	to add pairs to.
 * @param[in] oid	string to evaluate.
 * @param[in] type	SNMP value type.
 * @param[in] value	to assign to OID attribute (SET operations only).
 * @return
 *	- >0 on success (how much of the OID string we parsed).
 *	- <=0 on failure (where format error occurred).
 */
static ssize_t radsnmp_pair_from_oid(TALLOC_CTX *ctx, radsnmp_conf_t *conf, fr_cursor_t *cursor,
				     char const *oid, int type, char const *value)
{
	ssize_t			slen;
	char const		*p = oid;
	unsigned int		attr;
	fr_dict_attr_t const	*index_attr, *da;
	fr_dict_attr_t const	*parent = conf->snmp_root;
	VALUE_PAIR		*vp;
	int			ret;

	if (!oid) return 0;

	fr_cursor_tail(cursor);

	/*
	 *	Trim first.
	 */
	if (p[0] == '.') p++;

	/*
	 *	Support for indexes.  If we can't find an attribute
	 *	matching a child at a given level in the OID tree,
	 *	look for attribute 0 (type integer) at that level.
	 *	We use this to represent the index instead.
	 */
	for (;;) {
		unsigned int num = 0;

		slen = fr_dict_attr_by_oid(conf->dict, &parent, &attr, p);
		if (slen > 0) break;
		p += -(slen);

		if (fr_dict_oid_component(&num, &p) < 0) break;	/* Just advances the pointer */
		assert(attr == num);
		p++;

		/*
		 *	Check for an index attribute
		 */
		index_attr = fr_dict_attr_child_by_num(parent, 0);
		if (!index_attr) {
			fr_strerror_printf("Unknown OID component: No index attribute at this level");
			break;
		}

		if (index_attr->type != FR_TYPE_UINT32) {
			fr_strerror_printf("Index is not a \"integer\"");
			break;
		}

		/*
		 *	By convention SNMP entries are at .1
		 */
		parent = fr_dict_attr_child_by_num(parent, 1);
		if (!parent) {
			fr_strerror_printf("Unknown OID component: No entry attribute at this level");
			break;
		}

		/*
		 *	Entry must be a TLV type
		 */
		if (parent->type != FR_TYPE_TLV) {
			fr_strerror_printf("Entry is not \"tlv\"");
			break;
		}

		/*
		 *	We've skipped over the index attribute, and
		 *	the index number should be available in attr.
		 */
		MEM(vp = fr_pair_afrom_da(ctx, index_attr));
		vp->vp_uint32 = attr;

		fr_cursor_append(cursor, vp);
	}

	/*
	 *	We errored out processing the OID.
	 */
	if (slen <= 0) {
	error:
		fr_cursor_free_list(cursor);
		return slen;
	}

	fr_strerror();	/* Clear pending errors */

	/*
	 *	SNMP requests the leaf under the OID with .0.
	 */
	if (attr != 0) {
		da = fr_dict_attr_child_by_num(parent, attr);
		if (!da) {
			fr_strerror_printf("Unknown leaf attribute %i", attr);
			return -(slen);
		}
	} else {
		da = parent;
	}

	vp = fr_pair_afrom_da(ctx, da);
	if (!vp) {
		fr_strerror_printf("Failed allocating OID attribute");
		return -(slen);
	}

	/*
	 *	VALUE_PAIRs with no value need a 1 byte value buffer.
	 */
	if (!value) {
		switch (da->type) {
		/*
		 *	We can blame the authors of RFC 6929 for
		 *	this hack.  Apparently the presence or absence
		 *	of an attribute isn't considered a useful means
		 *	of conveying information, so empty TLVs are
		 *	disallowed.
		 */
		case FR_TYPE_TLV:
			fr_pair_to_unknown(vp);
			/* FALL-THROUGH */

		case FR_TYPE_OCTETS:
			fr_pair_value_memcpy(vp, (uint8_t const *)"\0", 1, true);
			break;

		case FR_TYPE_STRING:
			fr_pair_value_bstrncpy(vp, "\0", 1);
			break;

		/*
		 *	Fine to leave other values zeroed out.
		 */
		default:
			break;
		}

		fr_cursor_append(cursor, vp);
		return slen;
	}

	if (da->type == FR_TYPE_TLV) {
		fr_strerror_printf("TLVs cannot hold values");
		return -(slen);
	}

	ret = fr_pair_value_from_str(vp, value, strlen(value), '\0', true);
	if (ret < 0) {
		slen = -(slen);
		goto error;
	}

	vp = fr_pair_afrom_da(ctx, attr_freeradius_snmp_type);
	if (!vp) {
		slen = -(slen);
		goto error;
	}
	vp->vp_uint32 = type;

	fr_cursor_append(cursor, vp);

	return slen;
}
예제 #4
0
/*
 *	Decode ONE value into a VP
 */
static ssize_t decode_value_internal(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dict_attr_t const *da,
				     uint8_t const *data, size_t data_len)
{
	VALUE_PAIR *vp;
	uint8_t const *p = data;

	FR_PROTO_TRACE("%s called to parse %zu bytes", __FUNCTION__, data_len);
	FR_PROTO_HEX_DUMP(data, data_len, NULL);

	vp = fr_pair_afrom_da(ctx, da);
	if (!vp) return -1;

	/*
	 *	Unknown attributes always get converted to
	 *	octet types, so there's no way there could
	 *	be multiple attributes, so its safe to
	 *	steal the unknown attribute into the context
	 *	of the pair.
	 */
	if (da->flags.is_unknown) talloc_steal(vp, da);

	if (vp->da->type == FR_TYPE_STRING) {
		uint8_t const *q, *end;

		q = end = data + data_len;

		/*
		 *	Not allowed to be an array, copy the whole value
		 */
		if (!vp->da->flags.array) {
			fr_pair_value_bstrncpy(vp, (char const *)p, end - p);
			p = end;
			goto finish;
		}

		for (;;) {
			q = memchr(p, '\0', q - p);

			/* Malformed but recoverable */
			if (!q) q = end;

			fr_pair_value_bstrncpy(vp, (char const *)p, q - p);
			p = q + 1;
			vp->vp_tainted = true;

			/* Need another VP for the next round */
			if (p < end) {
				fr_cursor_append(cursor, vp);

				vp = fr_pair_afrom_da(ctx, da);
				if (!vp) return -1;
				continue;
			}
			break;
		}
		goto finish;
	}

	switch (vp->da->type) {
	/*
	 *	Doesn't include scope, whereas the generic format can
	 */
	case FR_TYPE_IPV6_ADDR:
		memcpy(&vp->vp_ipv6addr, p, sizeof(vp->vp_ipv6addr));
		vp->vp_ip.af = AF_INET6;
		vp->vp_ip.scope_id = 0;
		vp->vp_ip.prefix = 128;
		vp->vp_tainted = true;
		p += sizeof(vp->vp_ipv6addr);
		break;

	case FR_TYPE_IPV6_PREFIX:
		memcpy(&vp->vp_ipv6addr, p + 1, sizeof(vp->vp_ipv6addr));
		vp->vp_ip.af = AF_INET6;
		vp->vp_ip.scope_id = 0;
		vp->vp_ip.prefix = p[0];
		vp->vp_tainted = true;
		p += sizeof(vp->vp_ipv6addr) + 1;
		break;

	default:
	{
		ssize_t ret;

		ret = fr_value_box_from_network(vp, &vp->data, vp->da->type, da, p, data_len, true);
		if (ret < 0) {
			FR_PROTO_TRACE("decoding as unknown type");
			if (fr_pair_to_unknown(vp) < 0) return -1;
			fr_pair_value_memcpy(vp, p, data_len);
			ret = data_len;
		}
		p += (size_t) ret;
	}
	}

finish:
	FR_PROTO_TRACE("decoding value complete, adding new pair and returning %zu byte(s)", p - data);
	fr_cursor_append(cursor, vp);

	return p - data;
}