2 * valuepair.c Functions to handle VALUE_PAIRs
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/libradius.h>
38 static const char *months[] = {
39 "jan", "feb", "mar", "apr", "may", "jun",
40 "jul", "aug", "sep", "oct", "nov", "dec" };
43 * This padding is necessary only for attributes that are NOT
44 * in the dictionary, and then only because the rest of the
45 * code accesses vp->name directly, rather than through an
48 * The name padding only has to large enough for:
50 * Vendor-65535-Attr-65535
52 * i.e. 23 characters, plus a zero. We add another 8 bytes for
53 * padding, because the VALUE_PAIR structure may be un-aligned.
55 * The result is that for the normal case, the server uses a less
56 * memory (36 bytes * number of VALUE_PAIRs).
58 #define FR_VP_NAME_PAD (32)
59 #define FR_VP_NAME_LEN (24)
61 VALUE_PAIR *pairalloc(DICT_ATTR *da)
67 * Not in the dictionary: the name is allocated AFTER
68 * the VALUE_PAIR struct.
70 if (!da) name_len = FR_VP_NAME_PAD;
72 vp = malloc(sizeof(*vp) + name_len);
74 memset(vp, 0, sizeof(*vp));
77 vp->attribute = da->attr;
78 vp->vendor = da->vendor;
81 vp->flags = da->flags;
85 vp->type = PW_TYPE_OCTETS;
87 memset(&vp->flags, 0, sizeof(vp->flags));
88 vp->flags.unknown_attr = 1;
100 case PW_TYPE_INTEGER:
108 vp->length = sizeof(vp->vp_ifid);
111 case PW_TYPE_IPV6ADDR:
112 vp->length = sizeof(vp->vp_ipv6addr);
115 case PW_TYPE_IPV6PREFIX:
116 vp->length = sizeof(vp->vp_ipv6prefix);
119 case PW_TYPE_ETHERNET:
120 vp->length = sizeof(vp->vp_ether);
128 case PW_TYPE_COMBO_IP:
139 * Create a new valuepair.
141 VALUE_PAIR *paircreate(int attr, int vendor, int type)
146 da = dict_attrbyvalue(attr, vendor);
147 if ((vp = pairalloc(da)) == NULL) {
148 fr_strerror_printf("out of memory");
151 vp->operator = T_OP_EQ;
154 * It isn't in the dictionary: update the name.
157 char *p = (char *) (vp + 1);
160 vp->attribute = attr;
162 vp->type = type; /* be forgiving */
164 if (!vp_print_name(p, FR_VP_NAME_LEN, attr, vendor)) {
174 * release the memory used by a single attribute-value pair
175 * just a wrapper around free() for now.
177 void pairbasicfree(VALUE_PAIR *pair)
179 if (pair->type == PW_TYPE_TLV) free(pair->vp_tlv);
180 /* clear the memory here */
181 memset(pair, 0, sizeof(*pair));
186 * Release the memory used by a list of attribute-value
187 * pairs, and sets the pair pointer to NULL.
189 void pairfree(VALUE_PAIR **pair_ptr)
191 VALUE_PAIR *next, *pair;
193 if (!pair_ptr) return;
196 while (pair != NULL) {
207 * Find the pair with the matching attribute
209 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr, int vendor)
212 if ((first->attribute == attr) && (first->vendor == vendor)) {
223 * Delete the pair(s) with the matching attribute
225 void pairdelete(VALUE_PAIR **first, int attr, int vendor)
227 VALUE_PAIR *i, *next;
228 VALUE_PAIR **last = first;
230 for(i = *first; i; i = next) {
232 if ((i->attribute == attr) && (i->vendor == vendor)) {
242 * Add a pair at the end of a VALUE_PAIR list.
244 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
250 if (*first == NULL) {
254 for(i = *first; i->next; i = i->next)
260 * Add or replace a pair at the end of a VALUE_PAIR list.
262 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
264 VALUE_PAIR *i, *next;
265 VALUE_PAIR **prev = first;
267 if (*first == NULL) {
273 * Not an empty list, so find item if it is there, and
274 * replace it. Note, we always replace the first one, and
275 * we ignore any others that might exist.
277 for(i = *first; i; i = next) {
281 * Found the first attribute, replace it,
284 if ((i->attribute == replace->attribute) &&
285 (i->vendor == replace->vendor)) {
289 * Should really assert that replace->next == NULL
291 replace->next = next;
297 * Point to where the attribute should go.
303 * If we got here, we didn't find anything to replace, so
304 * stopped at the last item, which we just append to.
313 VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp)
318 if (!vp->flags.unknown_attr) {
321 name_len = FR_VP_NAME_PAD;
324 if ((n = malloc(sizeof(*n) + name_len)) == NULL) {
325 fr_strerror_printf("out of memory");
328 memcpy(n, vp, sizeof(*n) + name_len);
331 if ((n->type == PW_TYPE_TLV) &&
332 (n->vp_tlv != NULL)) {
333 n->vp_tlv = malloc(n->length);
334 memcpy(n->vp_tlv, vp->vp_tlv, n->length);
342 * Copy just a certain type of pairs.
344 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr, int vendor)
346 VALUE_PAIR *first, *n, **last;
353 !((vp->attribute == attr) && (vp->vendor == vendor))) {
359 if (!n) return first;
371 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
373 return paircopy2(vp, -1, 0);
378 * Move attributes from one list to the other
379 * if not already present.
381 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
383 VALUE_PAIR **tailto, *i, *j, *next;
384 VALUE_PAIR *tailfrom = NULL;
386 int has_password = 0;
389 * First, see if there are any passwords here, and
390 * point "tailto" to the end of the "to" list.
393 for(i = *to; i; i = i->next) {
394 if (i->attribute == PW_USER_PASSWORD ||
395 i->attribute == PW_CRYPT_PASSWORD)
401 * Loop over the "from" list.
403 for(i = *from; i; i = next) {
407 * If there was a password in the "to" list,
408 * do not move any other password from the
409 * "from" to the "to" list.
412 (i->attribute == PW_USER_PASSWORD ||
413 i->attribute == PW_CRYPT_PASSWORD)) {
418 switch (i->operator) {
420 * These are COMPARISON attributes
421 * from a check list, and are not
422 * supposed to be copied!
440 * If the attribute is already present in "to",
441 * do not move it from "from" to "to". We make
442 * an exception for "Hint" which can appear multiple
443 * times, and we never move "Fall-Through".
445 if (i->attribute == PW_FALL_THROUGH ||
446 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
448 found = pairfind(*to, i->attribute, i->vendor);
449 switch (i->operator) {
452 * If matching attributes are found,
455 case T_OP_SUB: /* -= */
457 if (!i->vp_strvalue[0] ||
458 (strcmp((char *)found->vp_strvalue,
459 (char *)i->vp_strvalue) == 0)){
460 pairdelete(to, found->attribute, found->vendor);
463 * 'tailto' may have been
467 for(j = *to; j; j = j->next) {
476 /* really HAVE_REGEX_H */
479 * Attr-Name =~ "s/find/replace/"
481 * Very bad code. Barely working,
487 (i->vp_strvalue[0] == 's')) {
494 p = i->vp_strvalue + 1;
495 q = strchr(p + 1, *p);
496 if (!q || (q[strlen(q) - 1] != *p)) {
500 str = strdup(i->vp_strvalue + 2);
503 q[strlen(q) - 1] = '\0';
505 regcomp(®, str, 0);
506 if (regexec(®, found->vp_strvalue,
508 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
509 found->vp_strvalue, match[0].rm_so,
516 tailfrom = i; /* don't copy it over */
520 case T_OP_EQ: /* = */
522 * FIXME: Tunnel attributes with
523 * different tags are different
528 continue; /* with the loop */
533 * If a similar attribute is found,
534 * replace it with the new one. Otherwise,
535 * add the new one to the list.
537 case T_OP_SET: /* := */
539 VALUE_PAIR *mynext = found->next;
542 * Do NOT call pairdelete()
543 * here, due to issues with
544 * re-writing "request->username".
546 * Everybody calls pairmove,
547 * and expects it to work.
548 * We can't update request->username
549 * here, so instead we over-write
550 * the vp that it's pointing to.
552 memcpy(found, i, sizeof(*found));
553 found->next = mynext;
555 pairdelete(&found->next, found->attribute, found->vendor);
558 * 'tailto' may have been
561 for(j = found; j; j = j->next) {
569 * Add the new element to the list, even
570 * if similar ones already exist.
573 case T_OP_ADD: /* += */
578 tailfrom->next = next;
583 * If ALL of the 'to' attributes have been deleted,
584 * then ensure that the 'tail' is updated to point
599 * Move one kind of attributes from one list to the other
601 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr, int vendor)
603 VALUE_PAIR *to_tail, *i, *next;
604 VALUE_PAIR *iprev = NULL;
607 * Find the last pair in the "to" list and put it in "to_tail".
611 for(i = *to; i; i = i->next)
616 for(i = *from; i; i = next) {
620 * vendor=0, attr = PW_VENDOR_SPECIFIC means
621 * "match any vendor attribute". Otherwise, do
624 if (((vendor != 0) || (attr != PW_VENDOR_SPECIFIC)) &&
625 (i->attribute != attr) && (i->vendor != vendor)) {
631 * If the attribute to move IS a VSA, then it ignores
632 * any non-VSA attribute.
634 if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC) &&
641 * Remove the attribute from the "from" list.
649 * Add the attribute to the "to" list.
662 * Sort of strtok/strsep function.
664 static char *mystrtok(char **ptr, const char *sep)
670 while (**ptr && strchr(sep, **ptr))
675 while (**ptr && strchr(sep, **ptr) == NULL)
683 * Turn printable string into time_t
684 * Returns -1 on error, 0 on OK.
686 static int gettime(const char *valstr, time_t *date)
697 * Test for unix timestamp date
699 *date = strtoul(valstr, &tail, 10);
705 memset(tm, 0, sizeof(*tm));
706 tm->tm_isdst = -1; /* don't know, and don't care about DST */
708 strlcpy(buf, valstr, sizeof(buf));
711 f[0] = mystrtok(&p, " \t");
712 f[1] = mystrtok(&p, " \t");
713 f[2] = mystrtok(&p, " \t");
714 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
715 if (!f[0] || !f[1] || !f[2]) return -1;
718 * The time has a colon, where nothing else does.
719 * So if we find it, bubble it to the back of the list.
722 for (i = 0; i < 3; i++) {
723 if (strchr(f[i], ':')) {
733 * The month is text, which allows us to find it easily.
736 for (i = 0; i < 3; i++) {
737 if (isalpha( (int) *f[i])) {
739 * Bubble the month to the front of the list
745 for (i = 0; i < 12; i++) {
746 if (strncasecmp(months[i], f[0], 3) == 0) {
754 /* month not found? */
755 if (tm->tm_mon == 12) return -1;
758 * The year may be in f[1], or in f[2]
760 tm->tm_year = atoi(f[1]);
761 tm->tm_mday = atoi(f[2]);
763 if (tm->tm_year >= 1900) {
768 * We can't use 2-digit years any more, they make it
769 * impossible to tell what's the day, and what's the year.
771 if (tm->tm_mday < 1900) return -1;
774 * Swap the year and the day.
777 tm->tm_year = tm->tm_mday - 1900;
782 * If the day is out of range, die.
784 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
789 * There may be %H:%M:%S. Parse it in a hacky way.
792 f[0] = f[3]; /* HH */
793 f[1] = strchr(f[0], ':'); /* find : separator */
794 if (!f[1]) return -1;
796 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
798 f[2] = strchr(f[1], ':'); /* find : separator */
800 *(f[2]++) = '\0'; /* nuke it, and point to SS */
802 strcpy(f[2], "0"); /* assignment would discard const */
805 tm->tm_hour = atoi(f[0]);
806 tm->tm_min = atoi(f[1]);
807 tm->tm_sec = atoi(f[2]);
811 * Returns -1 on error.
814 if (t == (time_t) -1) return -1;
821 static const char *hextab = "0123456789abcdef";
824 * Parse a string value into a given VALUE_PAIR
826 * FIXME: we probably want to fix this function to accept
827 * octets as values for any type of attribute. We should then
828 * double-check the parsed value, to be sure it's legal for that
829 * type (length, etc.)
831 static uint32_t getint(const char *value, char **end)
833 if ((value[0] == '0') && (value[1] == 'x')) {
834 return strtoul(value, end, 16);
837 return strtoul(value, end, 10);
840 static int check_for_whitespace(const char *value)
843 if (!isspace((int) *value)) return 0;
852 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
860 if (!value) return NULL;
863 * Even for integers, dates and ip addresses we
864 * keep the original string in vp->vp_strvalue.
866 if (vp->type != PW_TYPE_TLV) {
867 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
868 vp->length = strlen(vp->vp_strvalue);
880 while (*cp && (length < (sizeof(vp->vp_strvalue) - 1))) {
910 c = '\\'; /* no cp++ */
913 if ((cp[0] >= '0') &&
919 (sscanf(cp, "%3o", &x) == 1)) {
922 } /* else just do '\\' */
928 vp->vp_strvalue[length] = '\0';
934 * It's a comparison, not a real IP.
936 if ((vp->operator == T_OP_REG_EQ) ||
937 (vp->operator == T_OP_REG_NE)) {
942 * FIXME: complain if hostname
943 * cannot be resolved, or resolve later!
946 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
947 cs = s = strdup(value);
951 vp->flags.addport = 1;
960 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
962 fr_strerror_printf("Failed to find IP address for %s", cs);
966 vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
976 * Note that ALL integers are unsigned!
978 vp->vp_integer = getint(value, &p);
980 if (vp->vp_integer > 255) {
981 fr_strerror_printf("Byte value \"%s\" is larger than 255", value);
986 if (check_for_whitespace(p)) break;
987 goto check_for_value;
991 * Note that ALL integers are unsigned!
993 vp->vp_integer = getint(value, &p);
996 if (vp->vp_integer > 65535) {
997 fr_strerror_printf("Byte value \"%s\" is larger than 65535", value);
1002 if (check_for_whitespace(p)) break;
1003 goto check_for_value;
1005 case PW_TYPE_INTEGER:
1007 * Note that ALL integers are unsigned!
1009 vp->vp_integer = getint(value, &p);
1012 if (check_for_whitespace(p)) break;
1016 * Look for the named value for the given
1019 if ((dval = dict_valbyname(vp->attribute, vp->vendor, value)) == NULL) {
1020 fr_strerror_printf("Unknown value %s for attribute %s",
1024 vp->vp_integer = dval->value;
1030 * time_t may be 64 bits, whule vp_date
1031 * MUST be 32-bits. We need an
1032 * intermediary variable to handle
1037 if (gettime(value, &date) < 0) {
1038 fr_strerror_printf("failed to parse time string "
1048 case PW_TYPE_ABINARY:
1049 #ifdef ASCEND_BINARY
1050 if (strncasecmp(value, "0x", 2) == 0) {
1051 vp->type = PW_TYPE_OCTETS;
1055 if (ascend_parse_filter(vp) < 0 ) {
1056 fr_strerror_printf("failed to parse Ascend binary attribute: %s",
1063 * If Ascend binary is NOT defined,
1064 * then fall through to raw octets, so that
1065 * the user can at least make them by hand...
1069 /* raw octets: 0x01020304... */
1070 case PW_TYPE_OCTETS:
1071 if (strncasecmp(value, "0x", 2) == 0) {
1079 * There is only one character,
1082 if ((strlen(cp) & 0x01) != 0) {
1083 fr_strerror_printf("Hex string is not an even length string.");
1089 (vp->length < MAX_STRING_LEN)) {
1092 if (sscanf(cp, "%02x", &tmp) != 1) {
1093 fr_strerror_printf("Non-hex characters at %c%c", cp[0], cp[1]);
1105 if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
1106 fr_strerror_printf("failed to parse interface-id "
1107 "string \"%s\"", value);
1113 case PW_TYPE_IPV6ADDR:
1117 if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
1120 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1122 fr_strerror_printf("failed to parse IPv6 address "
1123 "string \"%s\": %s", value, buffer);
1126 vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
1127 vp->length = 16; /* length of IPv6 address */
1131 case PW_TYPE_IPV6PREFIX:
1132 p = strchr(value, '/');
1133 if (!p || ((p - value) >= 256)) {
1134 fr_strerror_printf("invalid IPv6 prefix "
1135 "string \"%s\"", value);
1138 unsigned int prefix;
1139 char buffer[256], *eptr;
1141 memcpy(buffer, value, p - value);
1142 buffer[p - value] = '\0';
1144 if (inet_pton(AF_INET6, buffer, vp->vp_octets + 2) <= 0) {
1145 fr_strerror_printf("failed to parse IPv6 address "
1146 "string \"%s\"", value);
1150 prefix = strtoul(p + 1, &eptr, 10);
1151 if ((prefix > 128) || *eptr) {
1152 fr_strerror_printf("failed to parse IPv6 address "
1153 "string \"%s\"", value);
1156 vp->vp_octets[1] = prefix;
1158 vp->vp_octets[0] = '\0';
1159 vp->length = 16 + 2;
1162 case PW_TYPE_ETHERNET:
1164 const char *c1, *c2;
1171 c2 = memchr(hextab, tolower((int) cp[0]), 16);
1173 } else if ((cp[1] != '\0') &&
1176 c1 = memchr(hextab, tolower((int) cp[0]), 16);
1177 c2 = memchr(hextab, tolower((int) cp[1]), 16);
1179 if (*cp == ':') cp++;
1183 if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
1184 fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
1187 vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
1194 case PW_TYPE_COMBO_IP:
1195 if (inet_pton(AF_INET6, value, vp->vp_strvalue) > 0) {
1196 vp->type = PW_TYPE_IPV6ADDR;
1197 vp->length = 16; /* length of IPv6 address */
1198 vp->vp_strvalue[vp->length] = '\0';
1203 if (ip_hton(value, AF_INET, &ipaddr) < 0) {
1204 fr_strerror_printf("Failed to find IPv4 address for %s", value);
1208 vp->type = PW_TYPE_IPADDR;
1209 vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
1214 case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1215 vp->vp_signed = (int32_t) strtol(value, &p, 10);
1219 case PW_TYPE_TLV: /* don't use this! */
1220 if (strncasecmp(value, "0x", 2) != 0) {
1221 fr_strerror_printf("Invalid TLV specification");
1224 length = strlen(value + 2) / 2;
1225 if (vp->length < length) {
1229 vp->vp_tlv = malloc(length);
1231 fr_strerror_printf("No memory");
1234 if (fr_hex2bin(value + 2, vp->vp_tlv,
1235 length) != length) {
1236 fr_strerror_printf("Invalid hex data in TLV");
1239 vp->length = length;
1246 fr_strerror_printf("unknown attribute type %d", vp->type);
1254 * Create a VALUE_PAIR from an ASCII attribute and value,
1255 * where the attribute name is in the form:
1259 * VendorName-Attr-%d
1261 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1266 const char *p = attribute;
1271 * Unknown attributes MUST be of type 'octets'
1273 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1274 fr_strerror_printf("Invalid octet string \"%s\" for attribute name \"%s\"", value, attribute);
1281 * Pull off vendor prefix first.
1283 if (strncasecmp(p, "Attr-", 5) != 0) {
1284 if (strncasecmp(p, "Vendor-", 7) == 0) {
1285 vendor = (int) strtol(p + 7, &q, 10);
1286 if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
1287 fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", attribute);
1293 } else { /* must be vendor name */
1299 fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", attribute);
1303 if ((size_t) (q - p) >= sizeof(buffer)) {
1304 fr_strerror_printf("Vendor name too long in attribute name \"%s\"", attribute);
1308 memcpy(buffer, p, (q - p));
1309 buffer[q - p] = '\0';
1311 vendor = dict_vendorbyname(buffer);
1313 fr_strerror_printf("Unknown vendor name in attribute name \"%s\"", attribute);
1321 fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", attribute);
1330 if (strncasecmp(p, "Attr-", 5) != 0) {
1331 fr_strerror_printf("Invalid format in attribute name \"%s\"", attribute);
1335 attr = strtol(p + 5, &q, 10);
1338 * Invalid, or trailing text after number.
1340 if ((attr == 0) || *q) {
1341 fr_strerror_printf("Invalid value in attribute name \"%s\"", attribute);
1346 * Double-check the size of attr.
1349 DICT_VENDOR *dv = dict_vendorbyvalue(vendor);
1354 fr_strerror_printf("Invalid attribute number in attribute name \"%s\"", attribute);
1358 } else switch (dv->type) {
1360 if (attr > 255) goto attr_error;
1364 if (attr > 65535) goto attr_error;
1371 fr_strerror_printf("Internal sanity check failed");
1377 * We've now parsed the attribute properly, Let's create
1378 * it. This next stop also looks the attribute up in the
1379 * dictionary, and creates the appropriate type for it.
1381 if ((vp = paircreate(attr, vendor, PW_TYPE_OCTETS)) == NULL) {
1382 fr_strerror_printf("out of memory");
1386 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1387 if (!value) return vp;
1389 size = strlen(value + 2);
1392 * We may be reading something like Attr-5. i.e.
1393 * who-ever wrote the text didn't understand it, but we
1398 if (size == (vp->length * 2)) break;
1399 vp->type = PW_TYPE_OCTETS;
1402 case PW_TYPE_STRING:
1403 case PW_TYPE_OCTETS:
1404 case PW_TYPE_ABINARY:
1405 vp->length = size >> 1;
1409 if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
1410 fr_strerror_printf("Invalid hex string");
1416 * Move contents around based on type. This is
1417 * to work around the historical use of "lvalue".
1421 case PW_TYPE_IPADDR:
1422 case PW_TYPE_INTEGER:
1423 memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue));
1424 vp->vp_strvalue[0] = '\0';
1436 * Create a VALUE_PAIR from an ASCII attribute and value.
1438 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1446 const char *attrname = attribute;
1449 * Check for tags in 'Attribute:Tag' format.
1454 ts = strrchr(attribute, ':');
1456 fr_strerror_printf("Invalid tag for attribute %s", attribute);
1461 strlcpy(buffer, attribute, sizeof(buffer));
1463 ts = strrchr(attrname, ':');
1465 /* Colon found with something behind it */
1466 if (ts[1] == '*' && ts[2] == 0) {
1467 /* Wildcard tag for check items */
1470 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1471 /* It's not a wild card tag */
1472 tag = strtol(ts + 1, &tc, 0);
1473 if (tc && !*tc && TAG_VALID_ZERO(tag))
1477 fr_strerror_printf("Invalid tag for attribute %s", attribute);
1484 * It's not found in the dictionary, so we use
1485 * another method to create the attribute.
1487 if ((da = dict_attrbyname(attrname)) == NULL) {
1488 return pairmake_any(attrname, value, operator);
1491 if ((vp = pairalloc(da)) == NULL) {
1492 fr_strerror_printf("out of memory");
1495 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1497 /* Check for a tag in the 'Merit' format of:
1498 * :Tag:Value. Print an error if we already found
1499 * a tag in the Attribute.
1502 if (value && (*value == ':' && da->flags.has_tag)) {
1503 /* If we already found a tag, this is invalid */
1505 fr_strerror_printf("Duplicate tag %s for attribute %s",
1507 DEBUG("Duplicate tag %s for attribute %s\n",
1512 /* Colon found and attribute allows a tag */
1513 if (value[1] == '*' && value[2] == ':') {
1514 /* Wildcard tag for check items */
1519 tag = strtol(value + 1, &tc, 0);
1520 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1528 vp->flags.tag = tag;
1531 switch (vp->operator) {
1536 * For =* and !* operators, the value is irrelevant
1540 case T_OP_CMP_FALSE:
1541 vp->vp_strvalue[0] = '\0';
1547 * Regular expression comparison of integer attributes
1548 * does a STRING comparison of the names of their
1549 * integer attributes.
1551 case T_OP_REG_EQ: /* =~ */
1552 case T_OP_REG_NE: /* !~ */
1554 fr_strerror_printf("No regular expression found in %s",
1560 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1561 vp->length = strlen(vp->vp_strvalue);
1563 * If anything goes wrong, this is a run-time error,
1564 * not a compile-time error.
1571 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1572 * then the user MAY have typed in the attribute name
1573 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1575 * We probably want to fix pairparsevalue to accept
1576 * octets as values for any attribute.
1578 if (value && (pairparsevalue(vp, value) == NULL)) {
1590 static const int valid_attr_name[256] = {
1591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1594 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1595 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1596 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1597 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1598 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1599 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1602 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1603 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1605 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1606 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1610 * Read a valuepair from a buffer, and advance pointer.
1611 * Sets *eol to T_EOL if end of line was encountered.
1613 VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol)
1617 char value[1024], *q;
1619 FR_TOKEN token, t, xlat;
1623 *eol = T_OP_INVALID;
1626 while ((*p == ' ') || (*p == '\t')) p++;
1629 *eol = T_OP_INVALID;
1630 fr_strerror_printf("No token read where we expected an attribute name");
1636 fr_strerror_printf("Read a comment instead of a token");
1641 for (len = 0; len < sizeof(attr); len++) {
1642 if (valid_attr_name[(int)*p]) {
1649 if (len == sizeof(attr)) {
1650 *eol = T_OP_INVALID;
1651 fr_strerror_printf("Attribute name is too long");
1656 * We may have Foo-Bar:= stuff, so back up.
1658 if ((len > 0) && (attr[len - 1] == ':')) {
1666 /* Now we should have an operator here. */
1667 token = gettoken(ptr, buf, sizeof(buf));
1668 if (token < T_EQSTART || token > T_EQEND) {
1669 fr_strerror_printf("expecting operator");
1673 /* Read value. Note that empty string values are allowed */
1674 xlat = gettoken(ptr, value, sizeof(value));
1675 if (xlat == T_EOL) {
1676 fr_strerror_printf("failed to get value");
1681 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1684 t = gettoken(&p, buf, sizeof(buf));
1685 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1686 fr_strerror_printf("Expected end of line or comma");
1698 * Make the full pair now.
1701 vp = pairmake(attr, value, token);
1707 case T_DOUBLE_QUOTED_STRING:
1708 p = strchr(value, '%');
1709 if (p && (p[1] == '{')) {
1710 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1711 fr_strerror_printf("Value too long");
1714 vp = pairmake(attr, NULL, token);
1716 *eol = T_OP_INVALID;
1720 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1721 vp->flags.do_xlat = 1;
1725 * Parse && escape it, as defined by the
1728 vp = pairmake(attr, value, token);
1730 *eol = T_OP_INVALID;
1736 case T_SINGLE_QUOTED_STRING:
1737 vp = pairmake(attr, NULL, token);
1739 *eol = T_OP_INVALID;
1744 * String and octet types get copied verbatim.
1746 if ((vp->type == PW_TYPE_STRING) ||
1747 (vp->type == PW_TYPE_OCTETS)) {
1748 strlcpy(vp->vp_strvalue, value,
1749 sizeof(vp->vp_strvalue));
1750 vp->length = strlen(vp->vp_strvalue);
1753 * Everything else gets parsed: it's
1754 * DATA, not a string!
1756 } else if (!pairparsevalue(vp, value)) {
1758 *eol = T_OP_INVALID;
1764 * Mark the pair to be allocated later.
1766 case T_BACK_QUOTED_STRING:
1767 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1768 fr_strerror_printf("Value too long");
1772 vp = pairmake(attr, NULL, token);
1774 *eol = T_OP_INVALID;
1778 vp->flags.do_xlat = 1;
1779 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1785 * If we didn't make a pair, return an error.
1788 *eol = T_OP_INVALID;
1796 * Read one line of attribute/value pairs. This might contain
1797 * multiple pairs seperated by comma's.
1799 FR_TOKEN userparse(const char *buffer, VALUE_PAIR **first_pair)
1803 FR_TOKEN last_token = T_OP_INVALID;
1804 FR_TOKEN previous_token;
1807 * We allow an empty line.
1814 previous_token = last_token;
1815 if ((vp = pairread(&p, &last_token)) == NULL) {
1818 pairadd(first_pair, vp);
1819 } while (*p && (last_token == T_COMMA));
1822 * Don't tell the caller that there was a comment.
1824 if (last_token == T_HASH) {
1825 return previous_token;
1829 * And return the last token which we read.
1835 * Read valuepairs from the fp up to End-Of-File.
1837 * Hmm... this function is only used by radclient..
1839 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1842 FR_TOKEN last_token = T_EOL;
1849 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1851 * If we get a '\n' by itself, we assume that's
1852 * the end of that VP
1854 if ((buf[0] == '\n') && (list)) {
1857 if ((buf[0] == '\n') && (!list)) {
1862 * Comments get ignored
1864 if (buf[0] == '#') continue;
1867 * Read all of the attributes on the current line.
1870 last_token = userparse(buf, &vp);
1872 if (last_token != T_EOL) {
1873 fr_perror("%s", errprefix);
1884 if (error) pairfree(&list);
1888 return error ? NULL: list;
1894 * Compare two pairs, using the operator from "one".
1896 * i.e. given two attributes, it does:
1898 * (two->data) (one->operator) (one->data)
1900 * e.g. "foo" != "bar"
1902 * Returns true (comparison is true), or false (comparison is not true);
1904 * FIXME: Ignores tags!
1906 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1910 switch (one->operator) {
1912 return (two != NULL);
1914 case T_OP_CMP_FALSE:
1915 return (two == NULL);
1918 * One is a regex, compile it, print two to a string,
1919 * and then do string comparisons.
1923 #ifndef HAVE_REGEX_H
1928 char buffer[MAX_STRING_LEN * 4 + 1];
1930 compare = regcomp(®, one->vp_strvalue,
1933 regerror(compare, ®, buffer, sizeof(buffer));
1934 fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
1939 vp_prints_value(buffer, sizeof(buffer), two, 0);
1942 * Don't care about substring matches,
1945 compare = regexec(®, buffer, 0, NULL, 0);
1948 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1949 return (compare != 0);
1953 default: /* we're OK */
1958 * After doing the previous check for special comparisons,
1959 * do the per-type comparison here.
1961 switch (one->type) {
1962 case PW_TYPE_ABINARY:
1963 case PW_TYPE_OCTETS:
1967 if (one->length < two->length) {
1968 length = one->length;
1970 length = two->length;
1974 compare = memcmp(two->vp_octets, one->vp_octets,
1976 if (compare != 0) break;
1980 * Contents are the same. The return code
1981 * is therefore the difference in lengths.
1983 * i.e. "0x00" is smaller than "0x0000"
1985 compare = two->length - one->length;
1989 case PW_TYPE_STRING:
1990 compare = strcmp(two->vp_strvalue, one->vp_strvalue);
1995 case PW_TYPE_INTEGER:
1997 compare = two->vp_integer - one->vp_integer;
2000 case PW_TYPE_IPADDR:
2001 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
2004 case PW_TYPE_IPV6ADDR:
2005 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
2006 sizeof(two->vp_ipv6addr));
2009 case PW_TYPE_IPV6PREFIX:
2010 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
2011 sizeof(two->vp_ipv6prefix));
2015 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
2016 sizeof(two->vp_ifid));
2020 return 0; /* unknown type */
2024 * Now do the operator comparison.
2026 switch (one->operator) {
2028 return (compare == 0);
2031 return (compare != 0);
2034 return (compare < 0);
2037 return (compare > 0);
2040 return (compare <= 0);
2043 return (compare >= 0);