/****************************************************************************** * Global function define * *****************************************************************************/ int gparse_radius_parse(gpacket_info_t *pkt_info, gradius_info_t *radius_info) { uint32_t code; uint8_t *radius; uint8_t *avp; size_t avp_len; radius = gparse_pkt_payload(pkt_info); code = GRADIUS_CODE(radius); //We care accounting request only! if(code != RADIUS_CODE_ACCT_REQUEST){ return -1; } radius_info->hdr = radius; radius_info->code = code; radius_info->avp_bitmap = 0; avp = GRADIUS_AVP(radius); avp_len = GRADIUS_LEN(radius) - GRADIUS_HDR_SIZE; radius_parse_attr(avp, avp_len, radius_info); if(radius_info->avp_bitmap == 0) { return -2; } return 0; }
/** Return a VP from the specified request. * * @param out where to write the pointer to the resolved VP. * Will be NULL if the attribute couldn't be resolved. * @param request current request. * @param name attribute name including qualifiers. * @return -4 if either the attribute or qualifier were invalid, and the same error codes as radius_vpt_get_vp for other * error conditions. */ int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name) { value_pair_tmpl_t vpt; *out = NULL; if (radius_parse_attr(name, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) { return -4; } return radius_vpt_get_vp(out, request, &vpt); }
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. * * @param[in] name attribute name including qualifiers. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return pointer to a value_pair_tmpl_t struct (must be freed with * radius_tmplfree) or NULL on error. */ value_pair_tmpl_t *radius_attr2tmpl(const char *name, request_refs_t request_def, pair_lists_t list_def) { value_pair_tmpl_t *vpt; const char *copy = strdup(name); vpt = rad_calloc(sizeof(value_pair_tmpl_t)); if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) { radius_tmplfree(&vpt); return NULL; } return vpt; }
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. * * @param[in] ctx for talloc * @param[in] name attribute name including qualifiers. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return pointer to a value_pair_tmpl_t struct (must be freed with * radius_tmplfree) or NULL on error. */ value_pair_tmpl_t *radius_attr2tmpl(TALLOC_CTX *ctx, char const *name, request_refs_t request_def, pair_lists_t list_def) { value_pair_tmpl_t *vpt; char const *copy; vpt = talloc(ctx, value_pair_tmpl_t); /* parse_attr zeroes it */ copy = talloc_strdup(vpt, name); if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) { radius_tmplfree(&vpt); return NULL; } return vpt; }
/** Parse qualifiers to convert attrname into a VALUE_PAIR_TMPL. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. * * @param[in] name attribute name including qualifiers. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return pointer to a VALUE_PAIR_TMPL struct (must be freed with * radius_tmplfree) or NULL on error. */ VALUE_PAIR_TMPL *radius_attr2tmpl(const char *name, request_refs_t request_def, pair_lists_t list_def) { VALUE_PAIR_TMPL *vpt; const char *copy = strdup(name); vpt = rad_malloc(sizeof(VALUE_PAIR_TMPL)); memset(vpt, 0, sizeof(VALUE_PAIR_TMPL)); if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) { radius_tmplfree(&vpt); return NULL; } return vpt; }
/** Return a VP from the specified request. * * @param request current request. * @param name attribute name including qualifiers. * @param vp_p where to write the pointer to the resolved VP. * Will be NULL if the attribute couldn't be resolved. * @return -1 if either the attribute or qualifier were invalid, else 0 */ int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p) { value_pair_tmpl_t vpt; VALUE_PAIR **vps; *vp_p = NULL; if (radius_parse_attr(name, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) { return -1; } if (radius_request(&request, vpt.request) < 0) { return 0; } vps = radius_list(request, vpt.list); if (!vps) { return 0; } switch (vpt.type) { /* * May not may not be found, but it *is* a known name. */ case VPT_TYPE_ATTR: *vp_p = pairfind(*vps, vpt.da->attr, vpt.da->vendor, TAG_ANY); break; case VPT_TYPE_LIST: *vp_p = *vps; break; default: rad_assert(0); return -1; break; } return 0; }
/** Return a VP from the specified request. * * @param request current request. * @param name attribute name including qualifiers. * @param vp_p where to write the pointer to the resolved VP. * Will be NULL if the attribute couldn't be resolved. * @return -1 if either the attribute or qualifier were invalid, else 0 */ int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p) { VALUE_PAIR_TMPL vpt; VALUE_PAIR **vps; *vp_p = NULL; if (radius_parse_attr(name, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) { return -1; } if (radius_request(&request, vpt.request) < 0) { RDEBUG("WARNING: Specified request \"%s\" is not available in " "this context", fr_int2str(request_refs, vpt.request, "¿unknown?")); return 0; } vps = radius_list(request, vpt.list); if (!vps) { RDEBUG("WARNING: Specified list \"%s\" is not available in " "this context", fr_int2str(pair_lists, vpt.list, "¿unknown?")); return 0; } /* * May not may not be found, but it *is* a known name. */ *vp_p = pairfind(*vps, vpt.da->attr, vpt.da->vendor, TAG_ANY); return 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(¤t, 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; }
/** Convert module specific attribute id to value_pair_tmpl_t. * * @param[in] ctx for talloc * @param[in] name string to convert. * @param[in] type Type of quoting around value. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return pointer to new VPT. */ value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def) { int rcode; char const *p; value_pair_tmpl_t *vpt; char buffer[1024]; vpt = talloc_zero(ctx, value_pair_tmpl_t); vpt->name = talloc_typed_strdup(vpt, name); switch (type) { case T_BARE_WORD: /* * If we can parse it as an attribute, it's an attribute. * Otherwise, treat it as a literal. */ rcode = radius_parse_attr(vpt, vpt->name, request_def, list_def); if (rcode == -2) { talloc_free(vpt); return NULL; } if (rcode == 0) { break; } /* FALL-THROUGH */ case T_SINGLE_QUOTED_STRING: vpt->type = VPT_TYPE_LITERAL; break; case T_DOUBLE_QUOTED_STRING: p = name; while (*p) { if (*p == '\\') { if (!p[1]) break; p += 2; continue; } if (*p == '%') break; p++; } /* * If the double quoted string needs to be * expanded at run time, make it an xlat * expansion. Otherwise, convert it to be a * literal. */ if (*p) { vpt->type = VPT_TYPE_XLAT; } else { vpt->type = VPT_TYPE_LITERAL; } break; case T_BACK_QUOTED_STRING: vpt->type = VPT_TYPE_EXEC; break; case T_OP_REG_EQ: /* hack */ vpt->type = VPT_TYPE_REGEX; break; default: rad_assert(0); return NULL; } radius_tmpl2str(buffer, sizeof(buffer), vpt); return vpt; }