diff --git a/src/lib/util/pair_legacy.c b/src/lib/util/pair_legacy.c index 347062fa5006..295e3ba4d658 100644 --- a/src/lib/util/pair_legacy.c +++ b/src/lib/util/pair_legacy.c @@ -520,432 +520,6 @@ fr_slen_t fr_pair_list_afrom_substr(fr_pair_parse_t const *root, fr_pair_parse_t FR_SBUFF_SET_RETURN(in, &our_in); } -/** Read one line of attribute/value pairs into a list. - * - * The line may specify multiple attributes separated by commas. - * - * @note If the function returns #T_INVALID, an error has occurred and - * @note the valuepair list should probably be freed. - * - * @param[in] ctx for talloc - * @param[in] parent parent DA to start referencing from - * @param[in] parent_vp vp where we place the result - * @param[in] buffer to read valuepairs from. - * @param[in] end end of the buffer - * @param[in] list where the parsed fr_pair_ts will be appended. - * @param[in,out] token The last token we parsed - * @param[in] depth the nesting depth for FR_TYPE_GROUP - * @param[in,out] relative_vp for relative attributes - * @return - * - <= 0 on failure. - * - The number of bytes of name consumed on success. - */ -static ssize_t pair_parse_legacy(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, fr_pair_t *parent_vp, char const *buffer, char const *end, - fr_pair_list_t *list, fr_token_t *token, unsigned int depth, fr_pair_t **relative_vp) -{ - fr_pair_t *vp = NULL; - fr_pair_t *my_relative_vp; - char const *p, *next, *op_p; - fr_token_t quote, last_token = T_INVALID; - fr_dict_attr_t const *internal = NULL; - fr_pair_list_t *my_list = list; - TALLOC_CTX *my_ctx; - char rhs[1024]; - - if (fr_dict_internal()) internal = fr_dict_root(fr_dict_internal()); - if (!internal && !parent) return 0; - if (internal == parent) internal = NULL; - - /* - * Zero data, or empty line. - */ - if ((buffer == end) || (buffer[0] == 0)) { - *token = T_EOL; - return 0; - } - -#ifndef NDEBUG - if (parent_vp) { - fr_assert(ctx == parent_vp); - fr_assert(list == &parent_vp->vp_group); - } -#endif - - p = buffer; - while (true) { - bool is_raw = false; - ssize_t slen; - fr_token_t op; - fr_dict_attr_t const *da, *my_parent; - fr_dict_attr_t const *da_unknown = NULL; - fr_dict_attr_err_t err; - - fr_skip_whitespace(p); - - /* - * Stop at the end of the input, returning - * whatever token was last read. - */ - if (!*p) break; - - if (*p == '#') { - last_token = T_EOL; - break; - } - - /* - * Stop at '}', too, if we're inside of a group. - */ - if ((depth > 0) && (*p == '}')) { - last_token = T_RCBRACE; - break; - } - - /* - * Relative attributes can only exist if there's a relative VP parent. - */ - if (*p == '.') { - p++; - - if (!*relative_vp) { - fr_strerror_const("The '.Attribute' syntax can only be used if the previous attribute is structural, and the line ends with ','"); - goto error; - } - - my_parent = (*relative_vp)->da; - my_list = &(*relative_vp)->vp_group; - my_ctx = *relative_vp; - } else { - /* - * Be nice to people who expect to see '&' everywhere. - */ - if (*p == '&') p++; - - /* - * We can find an attribute from the parent, but if the path is fully specified, - * then we reset any relative VP. So that the _next_ line we parse cannot use - * ".foo = bar" to get a relative attribute which was used when parsing _this_ - * line. - */ - my_parent = parent; - *relative_vp = NULL; - my_list = list; - my_ctx = ctx; - - /* - * Raw attributes get a special parser. - */ - if (strncmp(p, "raw.", 4) == 0) { - p += 4; - is_raw = true; - } - } - - /* - * Parse the name. - */ - slen = fr_dict_attr_by_oid_substr(&err, &da, my_parent, &FR_SBUFF_IN(p, (end - p)), &bareword_terminals); - if (err == FR_DICT_ATTR_NOTFOUND) { - if (is_raw) { - /* - * We have something like raw.KNOWN.26, let's go parse the unknown OID - * portion, starting from where the parsing failed. - */ - if (((slen > 0) && (p[slen] == '.') && isdigit((int) p[slen + 1])) || - ((slen == 0) && isdigit((int) *p))) { - char const *q = p + slen + (slen > 0); - - slen = fr_dict_unknown_afrom_oid_substr(NULL, &da_unknown, da, &FR_SBUFF_IN(q, (end - q))); - if (slen < 0) goto error; - - p = q; - da = da_unknown; - goto check_for_operator; - } - - goto notfound; - } - - /* - * We have an internal dictionary, look up the attribute there. Note that we - * can't have raw internal attributes. - */ - if (internal) { - slen = fr_dict_attr_by_oid_substr(&err, &da, internal, - &FR_SBUFF_IN(p, (end - p)), &bareword_terminals); - } - } - if (err != FR_DICT_ATTR_OK) { - if (slen < 0) slen = -slen; - p += slen; - - /* - * Regenerate the error message so that it's for the correct parent. - */ - if (err == FR_DICT_ATTR_NOTFOUND) { - uint8_t const *q; - - if (!fr_dict_attr_allowed_chars[(unsigned char) *p]) { - fr_strerror_printf("Invalid character '%c' in attribute name at %s", *p, p); - } else { - notfound: - for (q = (uint8_t const *) p; q < (uint8_t const *) end && fr_dict_attr_allowed_chars[*q]; q++) { - /* nothing */ - } - fr_strerror_printf("Unknown attribute \"%.*s\" for parent \"%s\"", (int) (q - ((uint8_t const *) p)), p, my_parent->name); - } - } - error: - fr_dict_unknown_free(&da_unknown); - *token = T_INVALID; - return -(p - buffer); - } - - /* - * If we force it to be raw, then only do that if it's not already unknown. - */ - if (is_raw && !da_unknown) { - da_unknown = fr_dict_unknown_afrom_da(ctx, da); - if (!da_unknown) goto error; - da = da_unknown; - } - - check_for_operator: -#ifdef STATIC_ANALYZER - if (!da) goto error; -#endif - - next = p + slen; - - rhs[0] = '\0'; - - p = next; - fr_skip_whitespace(p); - op_p = p; - - /* - * There must be an operator here. - */ - op = gettoken(&p, rhs, sizeof(rhs), false); - if ((op < T_EQSTART) || (op > T_EQEND)) { - fr_strerror_const("Expecting operator"); - goto error; - } - - fr_skip_whitespace(p); - - if (parent_vp || (*relative_vp && ((*relative_vp)->da == da->parent))) { - vp = fr_pair_afrom_da(my_ctx, da); - if (!vp) goto error; - fr_pair_append(my_list, vp); - - } else if (*relative_vp) { - - if (op != T_OP_ADD_EQ) { - fr_strerror_const("Relative attributes can only use '+=' for the operator"); - p = op_p; - goto error; - } - - vp = fr_pair_afrom_da_depth_nested(my_ctx, my_list, da, (*relative_vp)->da->depth); - if (!vp) goto error; - - } else if (op != T_OP_ADD_EQ) { - fr_assert(op != T_OP_PREPEND); - - vp = fr_pair_afrom_da_nested(my_ctx, my_list, da); - if (!vp) goto error; - - } else { - if (fr_pair_append_by_da_parent(my_ctx, &vp, my_list, da) < 0) goto error; - } - - vp->op = op; - - /* - * Peek ahead for structural elements which are raw. If the caller wants to parse them - * as a set of raw octets, then swap the data type to be octets. - */ - if (is_raw && (p[0] == '0') && (p[1] == 'x') && (da->type != FR_TYPE_OCTETS)) { - fr_dict_unknown_free(&da_unknown); - - da_unknown = fr_dict_unknown_attr_afrom_da(vp, vp->da); - if (!da_unknown) goto error; - - fr_assert(da_unknown->type == FR_TYPE_OCTETS); - - if (fr_pair_reinit_from_da(NULL, vp, da_unknown) < 0) goto error; - - da = vp->da; - da_unknown = NULL; /* already parented from vp */ - } - - /* - * Allow grouping attributes. - */ - switch (vp->vp_type) { - case FR_TYPE_NON_LEAF: - if ((op != T_OP_EQ) && (op != T_OP_CMP_EQ)) { - fr_strerror_printf("Group list for %s MUST use '=' as the operator", da->name); - goto error; - } - - if (*p != '{') { - fr_strerror_printf("Group list for %s MUST start with '{'", da->name); - goto error; - } - p++; - - /* - * Parse nested attributes, but the - * attributes here are relative to each - * other, and not to our parent relative VP. - */ - my_relative_vp = NULL; - - slen = pair_parse_legacy(vp, vp->da, vp, p, end, &vp->vp_group, &last_token, depth + 1, &my_relative_vp); - if (slen <= 0) { - goto error; - } - - if (last_token != T_RCBRACE) { - failed_group: - fr_strerror_const("Failed to end group list with '}'"); - goto error; - } - - p += slen; - fr_skip_whitespace(p); - if (*p != '}') goto failed_group; - p++; - - /* - * Cache which VP is now the one for - * relative references. - */ - *relative_vp = vp; - break; - - case FR_TYPE_LEAF: - /* - * Get the RHS thing. - */ - quote = gettoken(&p, rhs, sizeof(rhs), false); - if (quote == T_EOL) { - fr_strerror_const("Failed to get value"); - goto error; - } - - switch (quote) { - case T_DOUBLE_QUOTED_STRING: - case T_SINGLE_QUOTED_STRING: - case T_BACK_QUOTED_STRING: - case T_BARE_WORD: - break; - - default: - fr_strerror_printf("Failed to find expected value on right hand side in %s", da->name); - goto error; - } - - fr_skip_whitespace(p); - - /* - * Regular expressions get sanity checked by pair_make(). - * - * @todo - note that they will also be escaped, - * so we may need to fix that later. - */ - if ((vp->op == T_OP_REG_EQ) || (vp->op == T_OP_REG_NE)) { - if (fr_pair_value_bstrndup(vp, rhs, strlen(rhs), false) < 0) goto error; - - } else if ((vp->op == T_OP_CMP_TRUE) || (vp->op == T_OP_CMP_FALSE)) { - /* - * We don't care what the value is, so - * ignore it. - */ - break; - } - - if (fr_pair_value_from_str(vp, rhs, strlen(rhs), - fr_value_unescape_by_quote[quote], false) < 0) goto error; - break; - } - - /* - * Free the unknown attribute, we don't need it any more. - */ - fr_dict_unknown_free(&da_unknown); - - fr_assert(vp != NULL); - - PAIR_VERIFY(vp); - - /* - * Now look for EOL, hash, etc. - */ - if (!*p || (*p == '#') || (*p == '\n')) { - last_token = T_EOL; - break; - } - - fr_skip_whitespace(p); - - /* - * Stop at '}', too, if we're inside of a group. - */ - if ((depth > 0) && (*p == '}')) { - last_token = T_RCBRACE; - break; - } - - if (*p != ',') { - fr_strerror_printf("Expected ',', got '%c' at offset %zu", *p, p - buffer); - goto error; - } - p++; - last_token = T_COMMA; - } - - /* - * And return the last token which we read. - */ - *token = last_token; - return p - buffer; -} - -/** Read one line of attribute/value pairs into a list. - * - * The line may specify multiple attributes separated by commas. - * - * @note If the function returns #T_INVALID, an error has occurred and - * @note the valuepair list should probably be freed. - * - * @param[in] ctx for talloc - * @param[in] parent parent attribute for resolution - * @param[in] buffer to read valuepairs from. - * @param[in] len length of the buffer - * @param[in] list where the parsed fr_pair_ts will be appended. - * @return the last token parsed, or #T_INVALID - */ -fr_token_t fr_pair_list_afrom_str(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *buffer, size_t len, fr_pair_list_t *list) -{ - fr_token_t token; - fr_pair_t *relative_vp = NULL; - fr_pair_list_t tmp_list; - - fr_pair_list_init(&tmp_list); - - if (pair_parse_legacy(ctx, parent, NULL, buffer, buffer + len, &tmp_list, &token, 0, &relative_vp) < 0) { - fr_pair_list_free(&tmp_list); - return T_INVALID; - } - - fr_pair_list_append(list, &tmp_list); - - return token; -} - /** Read valuepairs from the fp up to End-Of-File. * * @param[in] ctx for talloc diff --git a/src/lib/util/pair_legacy.h b/src/lib/util/pair_legacy.h index ddebb8ce94b0..b2837a2fa848 100644 --- a/src/lib/util/pair_legacy.h +++ b/src/lib/util/pair_legacy.h @@ -34,8 +34,6 @@ RCSIDH(pair_legacy_h, "$Id$") extern "C" { #endif -fr_token_t fr_pair_list_afrom_str(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, - char const *buffer, size_t len, fr_pair_list_t *head); int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone);