]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add util/dpair_legacy.c and util/dpair_legacy.h
authorNick Porter <nick@portercomputing.co.uk>
Tue, 22 Dec 2020 16:16:16 +0000 (16:16 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 21 Jan 2021 23:05:49 +0000 (23:05 +0000)
src/lib/util/dpair.c
src/lib/util/dpair_legacy.c [new file with mode: 0644]
src/lib/util/dpair_legacy.h [new file with mode: 0644]
src/lib/util/libfreeradius-util.mk
src/lib/util/pair_legacy.h

index 201fe4dc7a2dd3ad101205ed8d703aaaea769cc4..00b50dc939e1e791d895e78c6bafbeecbd5a1d67 100644 (file)
@@ -24,8 +24,8 @@ RCSID("$Id$")
 
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/misc.h>
-#include <freeradius-devel/util/pair_legacy.h>
 #include <freeradius-devel/util/dpair.h>
+#include <freeradius-devel/util/dpair_legacy.h>
 #include <freeradius-devel/util/print.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/regex.h>
diff --git a/src/lib/util/dpair_legacy.c b/src/lib/util/dpair_legacy.c
new file mode 100644 (file)
index 0000000..e9e444e
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ *   This library is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU Lesser General Public
+ *   License as published by the Free Software Foundation; either
+ *   version 2.1 of the License, or (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** AVP manipulation and search API
+ *
+ * @file src/lib/util/pair.c
+ *
+ * @copyright 2000,2006,2015 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/pair.h>
+#include <freeradius-devel/util/pair_legacy.h>
+#include <freeradius-devel/util/print.h>
+#include <freeradius-devel/util/proto.h>
+#include <freeradius-devel/util/regex.h>
+#include <freeradius-devel/util/talloc.h>
+
+#include <freeradius-devel/protocol/radius/rfc2865.h>
+#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
+
+#include <ctype.h>
+
+fr_sbuff_term_t const          bareword_terminals =
+                               FR_SBUFF_TERMS(
+                                       L("\t"),
+                                       L("\n"),
+                                       L(" "),
+                                       L("!*"),
+                                       L("!="),
+                                       L("!~"),
+                                       L("&&"),                /* Logical operator */
+                                       L(")"),                 /* Close condition/sub-condition */
+                                       L("+="),
+                                       L("-="),
+                                       L(":="),
+                                       L("<"),
+                                       L("<="),
+                                       L("=*"),
+                                       L("=="),
+                                       L("=~"),
+                                       L(">"),
+                                       L(">="),
+                                       L("||"),                /* Logical operator */
+                               );
+
+/** Mark a valuepair for xlat expansion
+ *
+ * Copies xlat source (unprocessed) string to valuepair value, and sets value type.
+ *
+ * @param vp to mark for expansion.
+ * @param value to expand.
+ * @return
+ *     - 0 if marking succeeded.
+ *     - -1 if #fr_pair_t already had a value, or OOM.
+ */
+int fr_pair_mark_xlat(fr_pair_t *vp, char const *value)
+{
+       char *raw;
+
+       /*
+        *      valuepair should not already have a value.
+        */
+       if (vp->type != VT_NONE) {
+               fr_strerror_const("Pair already has a value");
+               return -1;
+       }
+
+       raw = talloc_typed_strdup(vp, value);
+       if (!raw) {
+               fr_strerror_const("Out of memory");
+               return -1;
+       }
+
+       vp->type = VT_XLAT;
+       vp->xlat = raw;
+       vp->vp_length = 0;
+
+       return 0;
+}
+
+/** Create a valuepair from an ASCII attribute and value
+ *
+ * Where the attribute name is in the form:
+ *  - Attr-%d
+ *  - Attr-%d.%d.%d...
+ *
+ * @param ctx for talloc
+ * @param dict to user for partial resolution.
+ * @param attribute name to parse.
+ * @param value to parse (must be a hex string).
+ * @param op to assign to new valuepair.
+ * @return new #fr_pair_t or NULL on error.
+ */
+static fr_pair_t *fr_pair_make_unknown(TALLOC_CTX *ctx, fr_dict_t const *dict,
+                                       char const *attribute, char const *value,
+                                       fr_token_t op)
+{
+       fr_pair_t               *vp;
+       fr_dict_attr_t          *n;
+       fr_sbuff_t              sbuff = FR_SBUFF_IN(attribute, strlen(attribute));
+
+       vp = fr_pair_alloc_null(ctx);
+       if (!vp) return NULL;
+
+       if ((fr_dict_unknown_afrom_oid_substr(vp, NULL, &n, fr_dict_root(dict), &sbuff, NULL) <= 0) ||
+                                             fr_sbuff_remaining(&sbuff)) {
+               talloc_free(vp);
+               return NULL;
+       }
+       vp->da = n;
+
+       /*
+        *      No value, but ensure that we still set up vp->data properly.
+        */
+       if (!value) {
+               value = "";
+
+       } else if (strncasecmp(value, "0x", 2) != 0) {
+               /*
+                *      Unknown attributes MUST be of type 'octets'
+                */
+               fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
+                                  "string, not \"%s\"", attribute, value);
+               talloc_free(vp);
+               return NULL;
+       }
+
+       if (fr_pair_value_from_str(vp, value, -1, '"', false) < 0) {
+               talloc_free(vp);
+               return NULL;
+       }
+
+       vp->op = (op == 0) ? T_OP_EQ : op;
+       return vp;
+}
+
+/** Create a #fr_pair_t from ASCII strings
+ *
+ * Converts an attribute string identifier (with an optional tag qualifier)
+ * and value string into a #fr_pair_t.
+ *
+ * The string value is parsed according to the type of #fr_pair_t being created.
+ *
+ * @param[in] ctx      for talloc.
+ * @param[in] dict     to look attributes up in.
+ * @param[in] vps      list where the attribute will be added (optional)
+ * @param[in] attribute        name.
+ * @param[in] value    attribute value (may be NULL if value will be set later).
+ * @param[in] op       to assign to new #fr_pair_t.
+ * @return a new #fr_pair_t.
+ */
+fr_pair_t *fr_pair_make(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *vps,
+                       char const *attribute, char const *value, fr_token_t op)
+{
+       fr_dict_attr_t const    *da;
+       fr_pair_t               *vp;
+       char const              *attrname = attribute;
+
+       /*
+        *      It's not found in the dictionary, so we use
+        *      another method to create the attribute.
+        */
+       da = fr_dict_attr_search_by_qualified_oid(NULL, dict, attrname, true);
+       if (!da) {
+               vp = fr_pair_make_unknown(ctx, dict, attrname, value, op);
+               if (!vp) return NULL;
+
+               if (vps) fr_pair_add(vps, vp);
+               return vp;
+       }
+
+       if (da->type == FR_TYPE_GROUP) {
+               fr_strerror_const("Attributes of type 'group' are not supported");
+               return NULL;
+       }
+
+       vp = fr_pair_afrom_da(ctx, da);
+       if (!vp) return NULL;
+       vp->op = (op == 0) ? T_OP_EQ : op;
+
+       switch (vp->op) {
+       case T_OP_CMP_TRUE:
+       case T_OP_CMP_FALSE:
+               fr_pair_value_clear(vp);
+               value = NULL;   /* ignore it! */
+               break;
+
+               /*
+                *      Regular expression comparison of integer attributes
+                *      does a STRING comparison of the names of their
+                *      integer attributes.
+                */
+       case T_OP_REG_EQ:       /* =~ */
+       case T_OP_REG_NE:       /* !~ */
+       {
+#ifndef HAVE_REGEX
+               fr_strerror_const("Regular expressions are not supported");
+               return NULL;
+#else
+               ssize_t slen;
+               regex_t *preg;
+
+               /*
+                *      Someone else will fill in the value.
+                */
+               if (!value) break;
+
+               talloc_free(vp);
+
+               slen = regex_compile(ctx, &preg, value, strlen(value), NULL, false, true);
+               if (slen <= 0) {
+                       fr_strerror_printf_push("Error at offset %zu compiling regex for %s", -slen, attribute);
+                       return NULL;
+               }
+               talloc_free(preg);
+
+               vp = fr_pair_afrom_da(ctx, da);
+               if (!vp) return NULL;
+               vp->op = op;
+
+               if (fr_pair_mark_xlat(vp, value) < 0) {
+                       talloc_free(vp);
+                       return NULL;
+               }
+
+               value = NULL;   /* ignore it */
+               break;
+#endif
+       }
+       default:
+               break;
+       }
+
+       /*
+        *      We probably want to fix fr_pair_value_from_str to accept
+        *      octets as values for any attribute.
+        */
+       if (value && (fr_pair_value_from_str(vp, value, -1, '\"', true) < 0)) {
+               talloc_free(vp);
+               return NULL;
+       }
+
+       if (vps) fr_pair_add(vps, vp);
+       return vp;
+}
+
+/** 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 to start referencing from
+ * @param[in] buffer   to read valuepairs from.
+ * @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
+ * @return
+ *     - <= 0 on failure.
+ *     - The number of bytes of name consumed on success.
+ */
+static ssize_t fr_pair_list_afrom_substr(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *buffer,
+                                        fr_pair_list_t *list, fr_token_t *token, int depth)
+{
+       fr_pair_list_t  tmp_list;
+       fr_pair_t       *vp;
+       char const      *p, *next;
+       fr_token_t      last_token = T_INVALID;
+       fr_pair_t_RAW   raw;
+       fr_dict_attr_t  const *internal = fr_dict_root(fr_dict_internal());
+
+       if (internal == parent) internal = NULL;
+
+       /*
+        *      We allow an empty line.
+        */
+       if (buffer[0] == 0) {
+               *token = T_EOL;
+               return 0;
+       }
+
+       fr_pair_list_init(&tmp_list);
+
+       p = buffer;
+       while (true) {
+               ssize_t slen;
+               fr_dict_attr_t const *da;
+               fr_dict_attr_t *da_unknown = NULL;
+               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;
+               }
+
+               /*
+                *      Hacky hack...
+                */
+               if (strncmp(p, "raw.", 4) == 0) goto do_unknown;
+
+               /*
+                *      Parse the name.
+                */
+               slen = fr_dict_attr_by_oid_substr(NULL, &da, parent,
+                                                 &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
+               if ((slen <= 0) && internal) {
+                       slen = fr_dict_attr_by_oid_substr(NULL, &da, internal,
+                                                         &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
+               }
+               if (slen <= 0) {
+               do_unknown:
+                       slen = fr_dict_unknown_afrom_oid_substr(ctx, NULL, &da_unknown, parent,
+                                                               &FR_SBUFF_IN(p, strlen(p)), &bareword_terminals);
+                       if (slen <= 0) {
+                               p += -slen;
+
+                       error:
+                               fr_pair_list_free(&tmp_list);
+                               *token = T_INVALID;
+                               return -(p - buffer);
+                       }
+
+                       da = da_unknown;
+               }
+
+               next = p + slen;
+
+               if ((size_t) (next - p) >= sizeof(raw.l_opand)) {
+                       fr_dict_unknown_free(&da);
+                       fr_strerror_const("Attribute name too long");
+                       goto error;
+               }
+
+               memcpy(raw.l_opand, p, next - p);
+               raw.l_opand[next - p] = '\0';
+               raw.r_opand[0] = '\0';
+
+               p = next;
+               fr_skip_whitespace(p);
+
+               /*
+                *      There must be an operator here.
+                */
+               raw.op = gettoken(&p, raw.r_opand, sizeof(raw.r_opand), false);
+               if ((raw.op  < T_EQSTART) || (raw.op  > T_EQEND)) {
+                       fr_dict_unknown_free(&da);
+                       fr_strerror_const("Expecting operator");
+                       goto error;
+               }
+
+               fr_skip_whitespace(p);
+
+               /*
+                *      Allow grouping attributes.
+                */
+               if ((da->type == FR_TYPE_GROUP) || (da->type == FR_TYPE_TLV) || (da->type == FR_TYPE_STRUCT)) {
+                       if (*p != '{') {
+                               fr_strerror_printf("Group list for %s MUST start with '{'", da->name);
+                               goto error;
+                       }
+                       p++;
+
+                       vp = fr_pair_afrom_da(ctx, da);
+                       if (!vp) goto error;
+
+                       /*
+                        *      Find the new root attribute to start encoding from.
+                        */
+                       parent = fr_dict_attr_ref(da);
+                       if (!parent) parent = da;
+
+                       slen = fr_pair_list_afrom_substr(vp, parent, p, &vp->vp_group, &last_token, depth + 1);
+                       if (slen <= 0) {
+                               talloc_free(vp);
+                               goto error;
+                       }
+
+                       if (last_token != T_RCBRACE) {
+                       failed_group:
+                               fr_strerror_const("Failed to end group list with '}'");
+                               talloc_free(vp);
+                               goto error;
+                       }
+
+                       p += slen;
+                       fr_skip_whitespace(p);
+                       if (*p != '}') goto failed_group;
+                       p++;
+
+               } else {
+                       fr_token_t quote;
+                       char const *q;
+
+                       /*
+                        *      Get the RHS thing.
+                        */
+                       quote = gettoken(&p, raw.r_opand, sizeof(raw.r_opand), false);
+                       if (quote == T_EOL) {
+                               fr_strerror_const("Failed to get value");
+                               goto error;
+                       }
+
+                       switch (quote) {
+                               /*
+                                *      Perhaps do xlat's
+                                */
+                       case T_DOUBLE_QUOTED_STRING:
+                               /*
+                                *      Only report as double quoted if it contained valid
+                                *      a valid xlat expansion.
+                                */
+                               q = strchr(raw.r_opand, '%');
+                               if (q && (q[1] == '{')) {
+                                       raw.quote = quote;
+                               } else {
+                                       raw.quote = T_SINGLE_QUOTED_STRING;
+                               }
+                               break;
+
+                       case T_SINGLE_QUOTED_STRING:
+                       case T_BACK_QUOTED_STRING:
+                       case T_BARE_WORD:
+                               raw.quote = quote;
+                               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 ((raw.op == T_OP_REG_EQ) || (raw.op == T_OP_REG_NE)) {
+                               vp = fr_pair_afrom_da(ctx, da);
+                               if (!vp) goto error;
+                               vp->op = raw.op;
+
+                               fr_pair_value_bstrndup(vp, raw.r_opand, strlen(raw.r_opand), false);
+                       } else {
+                               /*
+                                *      All other attributes get the name
+                                *      parsed.
+                                */
+                               vp = fr_pair_afrom_da(ctx, da);
+                               if (!vp) goto error;
+                               vp->op = raw.op;
+
+                               /*
+                                *      We don't care what the value is, so
+                                *      ignore it.
+                                */
+                               if ((raw.op == T_OP_CMP_TRUE) || (raw.op == T_OP_CMP_FALSE)) goto next;
+
+                               /*
+                                *      fr_pair_raw_from_str() only returns this when
+                                *      the input looks like it needs to be xlat'd.
+                                */
+                               if (raw.quote == T_DOUBLE_QUOTED_STRING) {
+                                       if (fr_pair_mark_xlat(vp, raw.r_opand) < 0) {
+                                               talloc_free(vp);
+                                               goto error;
+                                       }
+
+                                       /*
+                                        *      Parse it ourselves.  The RHS
+                                        *      might NOT be tainted, but we
+                                        *      don't know.  So just mark it
+                                        *      as such to be safe.
+                                        */
+                               } else if (fr_pair_value_from_str(vp, raw.r_opand, -1, '"', true) < 0) {
+                                       talloc_free(vp);
+                                       goto error;
+                               }
+                       }
+               }
+
+       next:
+               /*
+                *      Free the unknown attribute, we don't need it any more.
+                */
+               fr_dict_unknown_free(&da);
+
+               fr_pair_add(&tmp_list, vp);
+
+               /*
+                *      Now look for EOL, hash, etc.
+                */
+               if (!*p || (*p == '#') || (*p == '\n')) {
+                       last_token = T_EOL;
+                       break;
+               }
+
+               /*
+                *      Check for nested groups.
+                */
+               if ((depth > 0) && (p[0] == ' ') && (p[1] == '}')) 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;
+       }
+
+       if (!fr_pair_list_empty(&tmp_list)) fr_tmp_pair_list_move(list, &tmp_list);
+
+       /*
+        *      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] dict     to resolve attributes in.
+ * @param[in] buffer   to read valuepairs from.
+ * @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_t const *dict, char const *buffer, fr_pair_list_t *list)
+{
+       fr_token_t token;
+
+       (void) fr_pair_list_afrom_substr(ctx, fr_dict_root(dict), buffer, list, &token, 0);
+       return token;
+}
+
+/** Read valuepairs from the fp up to End-Of-File.
+ *
+ * @param[in] ctx              for talloc
+ * @param[in] dict             to resolve attributes in.
+ * @param[in,out] out          where the parsed fr_pair_ts will be appended.
+ * @param[in] fp               to read valuepairs from.
+ * @param[out] pfiledone       true if file parsing complete;
+ * @return
+ *     - 0 on success
+ *     - -1 on error
+ */
+int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
+{
+       fr_token_t      last_token = T_EOL;
+       bool            found = false;
+       char            buf[8192];
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               fr_pair_list_t tmp_list;
+
+               /*
+                *      If we get a '\n' by itself, we assume that's
+                *      the end of that VP list.
+                */
+               if (buf[0] == '\n') {
+                       if (found) {
+                               *pfiledone = false;
+                               return 0;
+                       }
+                       continue;
+               }
+
+               /*
+                *      Comments get ignored
+                */
+               if (buf[0] == '#') continue;
+
+               /*
+                *      Read all of the attributes on the current line.
+                *
+                *      If we get nothing but an EOL, it's likely OK.
+                */
+               fr_pair_list_init(&tmp_list);
+               last_token = fr_pair_list_afrom_str(ctx, dict, buf, &tmp_list);
+               if (fr_dlist_empty(&tmp_list.head)) {
+                       if (last_token == T_EOL) break;
+
+                       /*
+                        *      Didn't read anything, but the previous
+                        *      line wasn't EOL.  The input file has a
+                        *      format error.
+                        */
+                       *pfiledone = false;
+                       fr_pair_list_free(out);
+                       return -1;
+               }
+
+               found = true;
+               fr_tmp_pair_list_move(out, &tmp_list);
+       }
+
+       *pfiledone = true;
+       return 0;
+}
+
+
+/** Move pairs from source list to destination list respecting operator
+ *
+ * @note This function does some additional magic that's probably not needed
+ *      in most places. Consider using radius_pairmove in server code.
+ *
+ * @note fr_pair_list_free should be called on the head of the source list to free
+ *      unmoved attributes (if they're no longer needed).
+ *
+ * @param[in,out] to destination list.
+ * @param[in,out] from source list.
+ *
+ * @see radius_pairmove
+ */
+void fr_pair_list_move(fr_pair_list_t *to, fr_pair_list_t *from)
+{
+       fr_pair_t *i, *found;
+       fr_pair_list_t head_new;
+
+       if (!to || fr_pair_list_empty(from)) return;
+
+       /*
+        *      We're editing the "to" list while we're adding new
+        *      attributes to it.  We don't want the new attributes to
+        *      be edited, so we create an intermediate list to hold
+        *      them during the editing process.
+        */
+       fr_pair_list_init(&head_new);
+
+       /*
+        *      We're looping over the "from" list, moving some
+        *      attributes out, but leaving others in place.
+        */
+       for (i = fr_pair_list_head(from); i; ) {
+               fr_pair_t *j;
+
+               VP_VERIFY(i);
+
+               /*
+                *      We never move Fall-Through.
+                */
+               if (fr_dict_attr_is_top_level(i->da) && (i->da->attr == FR_FALL_THROUGH)) {
+                       i = fr_pair_list_next(from, i);
+                       continue;
+               }
+
+               /*
+                *      Unlike previous versions, we treat all other
+                *      attributes as normal.  i.e. there's no special
+                *      treatment for passwords or Hint.
+                */
+
+               switch (i->op) {
+               /*
+                *      Anything else are operators which
+                *      shouldn't occur.  We ignore them, and
+                *      leave them in place.
+                */
+               default:
+                       i = fr_pair_list_next(from, i);
+                       continue;
+
+               /*
+                *      Add it to the "to" list, but only if
+                *      it doesn't already exist.
+                */
+               case T_OP_EQ:
+                       found = fr_pair_find_by_da(to, i->da);
+                       if (!found) goto do_add;
+
+                       i = fr_pair_list_next(from, i);
+                       continue;
+
+               /*
+                *      Add it to the "to" list, and delete any attribute
+                *      of the same vendor/attr which already exists.
+                */
+               case T_OP_SET:
+                       found = fr_pair_find_by_da(to, i->da);
+                       if (!found) goto do_add;
+
+                       /*
+                        *      Delete *all* of the attributes
+                        *      of the same number.
+                        */
+                       fr_pair_delete_by_da(to, found->da);
+                       goto do_add;
+
+               /*
+                *      Move it from the old list and add it
+                *      to the new list.
+                */
+               case T_OP_ADD:
+       do_add:
+                       j = fr_pair_list_next(from, i);
+                       fr_pair_remove(from, i);
+                       fr_pair_add(&head_new, i);
+                       i = j;
+                       continue;
+               }
+       } /* loop over the "from" list. */
+
+       /*
+        *      Take the "new" list, and append it to the "to" list.
+        */
+       fr_tmp_pair_list_move(to, &head_new);
+}
diff --git a/src/lib/util/dpair_legacy.h b/src/lib/util/dpair_legacy.h
new file mode 100644 (file)
index 0000000..90636df
--- /dev/null
@@ -0,0 +1,51 @@
+#pragma once
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Legacy API functions - DO NOT USE IN NEW CODE
+ *
+ * @file src/lib/util/pair.h
+ *
+ * @copyright 2015 The FreeRADIUS server project
+ */
+RCSIDH(pair_legacy_h, "$Id$")
+
+#include <freeradius-devel/build.h>
+#include <freeradius-devel/missing.h>
+#include <freeradius-devel/util/cursor.h>
+#include <freeradius-devel/util/value.h>
+#include <freeradius-devel/util/token.h>
+#include <freeradius-devel/util/pair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+fr_pair_t      *fr_pair_make(TALLOC_CTX *ctx, fr_dict_t const *dict,
+                             fr_pair_list_t *vps, char const *attribute, char const *value, fr_token_t op);
+
+int            fr_pair_mark_xlat(fr_pair_t *vp, char const *value);
+
+fr_token_t     fr_pair_list_afrom_str(TALLOC_CTX *ctx, fr_dict_t const *dict,
+                                      char const *buffer, 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);
+
+void           fr_pair_list_move(fr_pair_list_t *to, fr_pair_list_t *from);
+
+#ifdef __cplusplus
+}
+#endif
index e11c9386052a5ded90148331a08fba44c63593de..7270f49d76f872104acb66b1d85f8d7a3a6fc881 100644 (file)
@@ -42,8 +42,8 @@ SOURCES               := \
                   missing.c \
                   net.c \
                   packet.c \
-                  pair_legacy.c \
                   $(if $(findstring USE_DOUBLE_LIST,$(CFLAGS)),dpair.c,pair.c) \
+                  $(if $(findstring USE_DOUBLE_LIST,$(CFLAGS)),dpair_legacy.c,pair_legacy.c) \
                   pair_print.c \
                   pair_tokenize.c \
                   paths.c \
index 90636df8c85de55bb4728dc40666223e5c9ed4b2..19689299aa84959eefd785d481404d066e23a53c 100644 (file)
@@ -21,6 +21,9 @@
  *
  * @copyright 2015 The FreeRADIUS server project
  */
+#ifdef USE_DOUBLE_LIST
+#include <freeradius-devel/util/dpair_legacy.h>
+#else
 RCSIDH(pair_legacy_h, "$Id$")
 
 #include <freeradius-devel/build.h>
@@ -49,3 +52,4 @@ void          fr_pair_list_move(fr_pair_list_t *to, fr_pair_list_t *from);
 #ifdef __cplusplus
 }
 #endif
+#endif