Ejemplo n.º 1
0
/** Copy matching pairs
 *
 * Copy pairs of a matching attribute number, vendor number and tag from the
 * the input list to a new list, and returns the head of this list.
 *
 * @param[in] ctx for talloc
 * @param[in] from whence to copy VALUE_PAIRs.
 * @param[in] attr to match, if 0 input list will not be filtered by attr.
 * @param[in] vendor to match.
 * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
 * @return the head of the new VALUE_PAIR list or NULL on error.
 */
VALUE_PAIR *paircopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int attr, unsigned int vendor, int8_t tag)
{
	vp_cursor_t src, dst;

	VALUE_PAIR *out = NULL, *vp;

	fr_cursor_init(&dst, &out);
	for (vp = fr_cursor_init(&src, &from);
	     vp;
	     vp = fr_cursor_next(&src)) {
		VERIFY_VP(vp);

		if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
			continue;
		}

		if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) {
			continue;
		}

		vp = paircopyvp(ctx, vp);
		if (!vp) {
			pairfree(&out);
			return NULL;
		}
		fr_cursor_insert(&dst, vp);
	}

	return out;
}
Ejemplo n.º 2
0
/** Replace all matching VPs
 *
 * Walks over 'first', and replaces the first VP that matches 'replace'.
 *
 * @note Memory used by the VP being replaced will be freed.
 * @note Will not work with unknown attributes.
 *
 * @param[in,out] first VP in linked list. Will search and replace in this list.
 * @param[in] replace VP to replace.
 */
void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
{
	VALUE_PAIR *i, *next;
	VALUE_PAIR **prev = first;

	VERIFY_VP(replace);

	if (*first == NULL) {
		*first = replace;
		return;
	}

	/*
	 *	Not an empty list, so find item if it is there, and
	 *	replace it. Note, we always replace the first one, and
	 *	we ignore any others that might exist.
	 */
	for(i = *first; i; i = next) {
		VERIFY_VP(i);
		next = i->next;

		/*
		 *	Found the first attribute, replace it,
		 *	and return.
		 */
		if ((i->da == replace->da) && (!i->da->flags.has_tag || TAG_EQ(replace->tag, i->tag))) {
			*prev = replace;

			/*
			 *	Should really assert that replace->next == NULL
			 */
			replace->next = next;
			talloc_free(i);
			return;
		}

		/*
		 *	Point to where the attribute should go.
		 */
		prev = &i->next;
	}

	/*
	 *	If we got here, we didn't find anything to replace, so
	 *	stopped at the last item, which we just append to.
	 */
	*prev = replace;
}
Ejemplo n.º 3
0
/** Delete matching pairs
 *
 * Delete matching pairs from the attribute list.
 *
 * @param[in,out] first VP in list.
 * @param[in] attr to match.
 * @param[in] vendor to match.
 * @param[in] tag to match. TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
 *
 * @todo should take DAs and do a point comparison.
 */
void pairdelete(VALUE_PAIR **first, unsigned int attr, unsigned int vendor,
		int8_t tag)
{
	VALUE_PAIR *i, *next;
	VALUE_PAIR **last = first;

	for(i = *first; i; i = next) {
		VERIFY_VP(i);
		next = i->next;
		if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
		    (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
			*last = next;
			talloc_free(i);
		} else {
			last = &i->next;
		}
	}
}
Ejemplo n.º 4
0
/** Iterate over attributes of a given DA in the pairlist
 *
 * Find the next attribute of a given type. If no fr_cursor_next_by_* function
 * has been called on a cursor before, or the previous call returned
 * NULL, the search will start with the current attribute. Subsequent calls to
 * fr_cursor_next_by_* functions will start the search from the previously
 * matched attribute.
 *
 * @note DICT_ATTR pointers are compared, not the attribute numbers and vendors.
 *
 * @addtogroup module_safe
 *
 * @param cursor to operate on.
 * @param da to match.
 * @param tag to match. Either a tag number or TAG_ANY to match any tagged or
 *	  untagged attribute, TAG_NONE to match attributes without tags.
 * @return
 *	- Next matching #VALUE_PAIR.
 *	- NULL if no #VALUE_PAIR (s) match.
 */
VALUE_PAIR *fr_cursor_next_by_da(vp_cursor_t *cursor, DICT_ATTR const *da, int8_t tag)
{
	VALUE_PAIR *i;

	if (!cursor->first) return NULL;

	for (i = !cursor->found ? cursor->current : cursor->found->next;
	     i != NULL;
	     i = i->next) {
		VERIFY_VP(i);
		if ((i->da == da) &&
		    (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
			break;
		}
	}

	return fr_cursor_update(cursor, i);
}
Ejemplo n.º 5
0
/** Iterate over a collection of VALUE_PAIRs of a given type in the pairlist
 *
 * Find the next attribute of a given type. If no fr_cursor_next_by_* function
 * has been called on a cursor before, or the previous call returned
 * NULL, the search will start with the current attribute. Subsequent calls to
 * fr_cursor_next_by_* functions will start the search from the previously
 * matched attribute.
 *
 * @addtogroup module_safe
 *
 * @param cursor to operate on.
 * @param attr number to match.
 * @param vendor number to match (0 for none vendor attribute).
 * @param tag to match. Either a tag number or TAG_ANY to match any tagged or
 *	  untagged attribute, TAG_NONE to match attributes without tags.
 * @return
 *	- The next matching #VALUE_PAIR.
 *	- NULL if no #VALUE_PAIR (s) match.
 */
VALUE_PAIR *fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag)
{
	VALUE_PAIR *i;

	if (!cursor->first) return NULL;

	for (i = !cursor->found ? cursor->current : cursor->found->next;
	     i != NULL;
	     i = i->next) {
		VERIFY_VP(i);
		if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
		    (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
			break;
		}
	}

	return fr_cursor_update(cursor, i);
}
Ejemplo n.º 6
0
/** Write an error to the library errorbuff detailing the mismatch
 *
 * Retrieve output with fr_strerror();
 *
 * @todo add thread specific talloc contexts.
 *
 * @param ctx a hack until we have thread specific talloc contexts.
 * @param failed pair of attributes which didn't match.
 */
void pairvalidate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
{
	VALUE_PAIR const *filter = failed[0];
	VALUE_PAIR const *list = failed[1];

	char *value, *str;

	(void) fr_strerror();	/* Clear any existing messages */

	if (!fr_assert(!(!filter && !list))) return;

	if (!list) {
		if (!filter) return;
		fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
		return;
	}

	if (!filter || (filter->da != list->da)) {
		fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
		return;
	}

	if (!TAG_EQ(filter->tag, list->tag)) {
		fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
				   list->da->name, list->tag, filter->tag);
		return;
	}


	value = vp_aprints_value(ctx, list, '"');
	str = vp_aprints(ctx, filter, '"');

	fr_strerror_printf("Attribute value \"%s\" didn't match filter: %s", value, str);

	talloc_free(str);
	talloc_free(value);

	return;
}
/*
 * ---------------------------------------------------------------------------
 *  parse_xbv1
 *
 *      Scan the firmware file to find the TLVs we are interested in.
 *      Actions performed:
 *        - check we support the file format version in VERF
 *      Store these TLVs if we have a firmware image:
 *        - SLTP Symbol Lookup Table Pointer
 *        - FWDL firmware download segments
 *        - FWOL firmware overlay segment
 *        - VMEQ Register probe tests to verify matching h/w
 *      Store these TLVs if we have a patch file:
 *        - FWID the firmware build ID that this file patches
 *        - PTDL The actual patches
 *
 *      The structure pointed to by fwinfo is cleared and
 *      'fwinfo->mode' is set to 'unknown'.  The 'fwinfo->mode'
 *      variable is set to 'firmware' or 'patch' once we know which
 *      sort of XBV file we have.
 *
 *  Arguments:
 *      readfn          Pointer to function to call to read from the file.
 *      dlpriv          Opaque pointer arg to pass to readfn.
 *      fwinfo          Pointer to fwinfo struct to fill in.
 *
 *  Returns:
 *      CSR_RESULT_SUCCESS on success, CSR error code on failure
 * ---------------------------------------------------------------------------
 */
CsrResult xbv1_parse(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo)
{
    ct_t ct;
    tag_t tag;
    xbv_stack_t stack;

    ct.dlpriv = dlpriv;
    ct.ioffset = 0;
    ct.iread = readfn;

    CsrMemSet(fwinfo, 0, sizeof(xbv1_t));
    fwinfo->mode = xbv_unknown;

    /* File must start with XBV1 triplet */
    if (read_tag(card, &ct, &tag) <= 0)
    {
        unifi_error(NULL, "File is not UniFi firmware\n");
        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
    }

    DBG_TAG(tag.t_name);

    if (!TAG_EQ(tag.t_name, "XBV1"))
    {
        unifi_error(NULL, "File is not UniFi firmware (%s)\n", tag.t_name);
        return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
    }

    stack.ptr = 0;
    stack.s[stack.ptr].container = xbv_xbv1;
    stack.s[stack.ptr].ioffset_end = XBV_MAX_OFFS;

    /* Now scan the file */
    while (1)
    {
        CsrInt32 n;

        n = read_tag(card, &ct, &tag);
        if (n < 0)
        {
            unifi_error(NULL, "No tag\n");
            return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
        }
        if (n == 0)
        {
            /* End of file */
            break;
        }

        DBG_TAG(tag.t_name);

        /* File format version */
        if (TAG_EQ(tag.t_name, "VERF"))
        {
            CsrUint32 version;

            if (xbv_check(fwinfo, &stack, xbv_unknown, xbv_xbv1) ||
                (tag.t_len != 2) ||
                read_uint(card, &ct, &version, 2))
            {
                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
            }
            if (version != 0)
            {
                unifi_error(NULL, "Unsupported firmware file version: %d.%d\n",
                            version >> 8, version & 0xFF);
                return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
            }
        }
Ejemplo n.º 8
0
int paircmp_pairs(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
#endif
{
	int ret = 0;

	/*
	 *      Check for =* and !* and return appropriately
	 */
	if (check->op == T_OP_CMP_TRUE)  return 0;
	if (check->op == T_OP_CMP_FALSE) return 1;

	if (!vp) {
		REDEBUG("Non-Unary operations require two operands");
		return -2;
	}

#ifdef HAVE_REGEX
	if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) {
		ssize_t		slen;
		regex_t		*preg = NULL;
		uint32_t	subcaptures;
		fr_regmatch_t	*regmatch;

		char *expr = NULL, *value = NULL;
		char const *expr_p, *value_p;

		if (check->vp_type == FR_TYPE_STRING) {
			expr_p = check->vp_strvalue;
		} else {
			expr_p = expr = fr_pair_value_asprint(check, check, '\0');
		}

		if (vp->vp_type == FR_TYPE_STRING) {
			value_p = vp->vp_strvalue;
		} else {
			value_p = value = fr_pair_value_asprint(vp, vp, '\0');
		}

		if (!expr_p || !value_p) {
			REDEBUG("Error stringifying operand for regular expression");

		regex_error:
			talloc_free(preg);
			talloc_free(expr);
			talloc_free(value);
			return -2;
		}

		/*
		 *	Include substring matches.
		 */
		slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1,
				     false, false, true, true);
		if (slen <= 0) {
			REMARKER(expr_p, -slen, fr_strerror());

			goto regex_error;
		}

		subcaptures = regex_subcapture_count(preg);
		if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1;	/* +1 for %{0} (whole match) capture group */
		MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));

		/*
		 *	Evaluate the expression
		 */
		slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, regmatch);
		if (slen < 0) {
			RPERROR("Invalid regex");

			goto regex_error;
		}

		if (check->op == T_OP_REG_EQ) {
			/*
			 *	Add in %{0}. %{1}, etc.
			 */
			regex_sub_to_request(request, &preg, &regmatch);
			ret = (slen == 1) ? 0 : -1;
		} else {
			ret = (slen != 1) ? 0 : -1;
		}

		talloc_free(regmatch);
		talloc_free(preg);
		talloc_free(expr);
		talloc_free(value);

		goto finish;
	}
#endif

	/*
	 *	Attributes must be of the same type.
	 *
	 *	FIXME: deal with type mismatch properly if one side contain
	 *	ABINARY, OCTETS or STRING by converting the other side to
	 *	a string
	 *
	 */
	if (vp->vp_type != check->vp_type) return -1;

	/*
	 *	Tagged attributes are equal if and only if both the
	 *	tag AND value match.
	 */
	if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
		ret = ((int) vp->tag) - ((int) check->tag);
		if (ret != 0) goto finish;
	}

	/*
	 *	Not a regular expression, compare the types.
	 */
	switch (check->vp_type) {
#ifdef WITH_ASCEND_BINARY
		/*
		 *	Ascend binary attributes can be treated
		 *	as opaque objects, I guess...
		 */
		case FR_TYPE_ABINARY:
#endif
		case FR_TYPE_OCTETS:
			if (vp->vp_length != check->vp_length) {
				ret = 1; /* NOT equal */
				break;
			}
			ret = memcmp(vp->vp_strvalue, check->vp_strvalue, vp->vp_length);
			break;

		case FR_TYPE_STRING:
			ret = strcmp(vp->vp_strvalue, check->vp_strvalue);
			break;

		case FR_TYPE_UINT8:
			ret = vp->vp_uint8 - check->vp_uint8;
			break;

		case FR_TYPE_UINT16:
			ret = vp->vp_uint16 - check->vp_uint16;
			break;

		case FR_TYPE_UINT32:
			ret = vp->vp_uint32 - check->vp_uint32;
			break;

		case FR_TYPE_UINT64:
			/*
			 *	Don't want integer overflow!
			 */
			if (vp->vp_uint64 < check->vp_uint64) {
				ret = -1;
			} else if (vp->vp_uint64 > check->vp_uint64) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case FR_TYPE_INT32:
			if (vp->vp_int32 < check->vp_int32) {
				ret = -1;
			} else if (vp->vp_int32 > check->vp_int32) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case FR_TYPE_DATE:
			ret = vp->vp_date - check->vp_date;
			break;

		case FR_TYPE_IPV4_ADDR:
			ret = ntohl(vp->vp_ipv4addr) - ntohl(check->vp_ipv4addr);
			break;

		case FR_TYPE_IPV6_ADDR:
			ret = memcmp(vp->vp_ip.addr.v6.s6_addr, check->vp_ip.addr.v6.s6_addr,
				     sizeof(vp->vp_ip.addr.v6.s6_addr));
			break;

		case FR_TYPE_IPV4_PREFIX:
		case FR_TYPE_IPV6_PREFIX:
			ret = memcmp(&vp->vp_ip, &check->vp_ip, sizeof(vp->vp_ip));
			break;

		case FR_TYPE_IFID:
			ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid));
			break;

		default:
			break;
	}

finish:
	if (ret > 0) return 1;
	if (ret < 0) return -1;
	return 0;
}
Ejemplo n.º 9
0
/** Compares check and vp by value.
 *
 * Does not call any per-attribute comparison function, but does honour
 * check.operator. Basically does "vp.value check.op check.value".
 *
 * @param request Current request.
 * @param check rvalue, and operator.
 * @param vp lvalue.
 * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
 *	value, -2 on error.
 */
int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
{
	int ret = 0;

	/*
	 *      Check for =* and !* and return appropriately
	 */
	if (check->op == T_OP_CMP_TRUE)  return 0;
	if (check->op == T_OP_CMP_FALSE) return 1;

#ifdef HAVE_REGEX_H
	if (check->op == T_OP_REG_EQ) {
		int compare;
		regex_t reg;
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		vp_prints_value(value, sizeof(value), vp, -1);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
			return -2;
		}

		memset(&rxmatch, 0, sizeof(rxmatch));	/* regexec does not seem to initialise unused elements */
		compare = regexec(&reg, value, REQUEST_MAX_REGEX + 1, rxmatch, 0);
		regfree(&reg);
		rad_regcapture(request, compare, value, rxmatch);

		ret = (compare == 0) ? 0 : -1;
		goto finish;
	}

	if (check->op == T_OP_REG_NE) {
		int compare;
		regex_t reg;
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		vp_prints_value(value, sizeof(value), vp, -1);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
			return -2;
		}
		compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1, rxmatch, 0);
		regfree(&reg);

		ret = (compare != 0) ? 0 : -1;
	}
#endif

	/*
	 *	Attributes must be of the same type.
	 *
	 *	FIXME: deal with type mismatch properly if one side contain
	 *	ABINARY, OCTETS or STRING by converting the other side to
	 *	a string
	 *
	 */
	if (vp->da->type != check->da->type) return -1;

	/*
	 *	Tagged attributes are equal if and only if both the
	 *	tag AND value match.
	 */
	if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
		ret = ((int) vp->tag) - ((int) check->tag);
		if (ret != 0) goto finish;
	}

	/*
	 *	Not a regular expression, compare the types.
	 */
	switch(check->da->type) {
#ifdef WITH_ASCEND_BINARY
		/*
		 *	Ascend binary attributes can be treated
		 *	as opaque objects, I guess...
		 */
		case PW_TYPE_ABINARY:
#endif
		case PW_TYPE_OCTETS:
			if (vp->length != check->length) {
				ret = 1; /* NOT equal */
				break;
			}
			ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
				     vp->length);
			break;

		case PW_TYPE_STRING:
			ret = strcmp(vp->vp_strvalue,
				     check->vp_strvalue);
			break;

		case PW_TYPE_BYTE:
		case PW_TYPE_SHORT:
		case PW_TYPE_INTEGER:
			ret = vp->vp_integer - check->vp_integer;
			break;

		case PW_TYPE_INTEGER64:
			/*
			 *	Don't want integer overflow!
			 */
			if (vp->vp_integer64 < check->vp_integer64) {
				ret = -1;
			} else if (vp->vp_integer64 > check->vp_integer64) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case PW_TYPE_SIGNED:
			if (vp->vp_signed < check->vp_signed) {
				ret = -1;
			} else if (vp->vp_signed > check->vp_signed) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case PW_TYPE_DATE:
			ret = vp->vp_date - check->vp_date;
			break;

		case PW_TYPE_IPV4_ADDR:
			ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
			break;

		case PW_TYPE_IPV6_ADDR:
			ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
				     sizeof(vp->vp_ipv6addr));
			break;

		case PW_TYPE_IPV6_PREFIX:
			ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
				     sizeof(vp->vp_ipv6prefix));
			break;

		case PW_TYPE_IFID:
			ret = memcmp(&vp->vp_ifid, &check->vp_ifid,
				     sizeof(vp->vp_ifid));
			break;

		default:
			break;
	}

	finish:
	if (ret > 0) {
		return 1;
	}
	if (ret < 0) {
		return -1;
	}
	return 0;
}