/** 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; }
/** 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; }
/** 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; } } }
/** 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); }
/** 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); }
/** 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; } }
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, ®match); 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; }
/** 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(®, check->vp_strvalue, REG_EXTENDED); if (compare != 0) { char buffer[256]; regerror(compare, ®, 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(®, value, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); 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(®, check->vp_strvalue, REG_EXTENDED); if (compare != 0) { char buffer[256]; regerror(compare, ®, buffer, sizeof(buffer)); RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer); return -2; } compare = regexec(®, value, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); 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; }