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" };
44 * Create a new valuepair.
46 VALUE_PAIR *paircreate(int attr, int type)
51 if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
52 librad_log("out of memory");
55 memset(vp, 0, sizeof(VALUE_PAIR));
57 vp->operator = T_OP_EQ;
61 * Dictionary type over-rides what the caller says.
63 if ((da = dict_attrbyvalue(attr)) != NULL) {
64 strcpy(vp->name, da->name);
66 vp->flags = da->flags;
67 } else if (VENDOR(attr) == 0) {
68 sprintf(vp->name, "Attr-%u", attr);
72 v = dict_vendorbyvalue(VENDOR(attr));
74 sprintf(vp->name, "%s-Attr-%u",
75 v->name, attr & 0xffff);
77 sprintf(vp->name, "Vendor-%u-Attr-%u",
78 VENDOR(attr), attr & 0xffff);
97 vp->length = sizeof(vp->vp_ifid);
100 case PW_TYPE_IPV6ADDR:
101 vp->length = sizeof(vp->vp_ipv6addr);
104 case PW_TYPE_IPV6PREFIX:
105 vp->length = sizeof(vp->vp_ipv6prefix);
117 * release the memory used by a single attribute-value pair
118 * just a wrapper around free() for now.
120 void pairbasicfree(VALUE_PAIR *pair)
122 /* clear the memory here */
123 memset(pair, 0, sizeof(*pair));
128 * Release the memory used by a list of attribute-value
129 * pairs, and sets the pair pointer to NULL.
131 void pairfree(VALUE_PAIR **pair_ptr)
133 VALUE_PAIR *next, *pair;
135 if (!pair_ptr) return;
138 while (pair != NULL) {
149 * Find the pair with the matching attribute
151 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
153 while(first && first->attribute != attr)
160 * Delete the pair(s) with the matching attribute
162 void pairdelete(VALUE_PAIR **first, int attr)
164 VALUE_PAIR *i, *next;
165 VALUE_PAIR **last = first;
167 for(i = *first; i; i = next) {
169 if (i->attribute == attr) {
179 * Add a pair at the end of a VALUE_PAIR list.
181 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
187 if (*first == NULL) {
191 for(i = *first; i->next; i = i->next)
197 * Add or replace a pair at the end of a VALUE_PAIR list.
199 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
201 VALUE_PAIR *i, *next;
202 VALUE_PAIR **prev = first;
204 if (*first == NULL) {
210 * Not an empty list, so find item if it is there, and
211 * replace it. Note, we always replace the first one, and
212 * we ignore any others that might exist.
214 for(i = *first; i; i = next) {
218 * Found the first attribute, replace it,
221 if (i->attribute == replace->attribute) {
225 * Should really assert that replace->next == NULL
227 replace->next = next;
233 * Point to where the attribute should go.
239 * If we got here, we didn't find anything to replace, so
240 * stopped at the last item, which we just append to.
246 * Copy just a certain type of pairs.
248 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
250 VALUE_PAIR *first, *n, **last;
256 if (attr >= 0 && vp->attribute != attr) {
260 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
261 librad_log("out of memory");
264 memcpy(n, vp, sizeof(VALUE_PAIR));
277 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
279 return paircopy2(vp, -1);
284 * Move attributes from one list to the other
285 * if not already present.
287 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
289 VALUE_PAIR **tailto, *i, *j, *next;
290 VALUE_PAIR *tailfrom = NULL;
292 int has_password = 0;
295 * First, see if there are any passwords here, and
296 * point "tailto" to the end of the "to" list.
299 for(i = *to; i; i = i->next) {
300 if (i->attribute == PW_USER_PASSWORD ||
301 i->attribute == PW_CRYPT_PASSWORD)
307 * Loop over the "from" list.
309 for(i = *from; i; i = next) {
313 * If there was a password in the "to" list,
314 * do not move any other password from the
315 * "from" to the "to" list.
318 (i->attribute == PW_USER_PASSWORD ||
319 i->attribute == PW_CRYPT_PASSWORD)) {
324 switch (i->operator) {
326 * These are COMPARISON attributes
327 * from a check list, and are not
328 * supposed to be copied!
346 * If the attribute is already present in "to",
347 * do not move it from "from" to "to". We make
348 * an exception for "Hint" which can appear multiple
349 * times, and we never move "Fall-Through".
351 if (i->attribute == PW_FALL_THROUGH ||
352 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
354 found = pairfind(*to, i->attribute);
355 switch (i->operator) {
358 * If matching attributes are found,
361 case T_OP_SUB: /* -= */
363 if (!i->vp_strvalue[0] ||
364 (strcmp((char *)found->vp_strvalue,
365 (char *)i->vp_strvalue) == 0)){
366 pairdelete(to, found->attribute);
369 * 'tailto' may have been
373 for(j = *to; j; j = j->next) {
382 /* really HAVE_REGEX_H */
385 * Attr-Name =~ "s/find/replace/"
387 * Very bad code. Barely working,
393 (i->vp_strvalue[0] == 's')) {
400 p = i->vp_strvalue + 1;
401 q = strchr(p + 1, *p);
402 if (!q || (q[strlen(q) - 1] != *p)) {
406 str = strdup(i->vp_strvalue + 2);
409 q[strlen(q) - 1] = '\0';
411 regcomp(®, str, 0);
412 if (regexec(®, found->vp_strvalue,
414 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
415 found->vp_strvalue, match[0].rm_so,
422 tailfrom = i; /* don't copy it over */
426 case T_OP_EQ: /* = */
428 * FIXME: Tunnel attributes with
429 * different tags are different
434 continue; /* with the loop */
439 * If a similar attribute is found,
440 * replace it with the new one. Otherwise,
441 * add the new one to the list.
443 case T_OP_SET: /* := */
445 VALUE_PAIR *mynext = found->next;
448 * Do NOT call pairdelete()
449 * here, due to issues with
450 * re-writing "request->username".
452 * Everybody calls pairmove,
453 * and expects it to work.
454 * We can't update request->username
455 * here, so instead we over-write
456 * the vp that it's pointing to.
458 memcpy(found, i, sizeof(*found));
459 found->next = mynext;
461 pairdelete(&found->next, found->attribute);
464 * 'tailto' may have been
467 for(j = found; j; j = j->next) {
475 * Add the new element to the list, even
476 * if similar ones already exist.
479 case T_OP_ADD: /* += */
484 tailfrom->next = next;
489 * If ALL of the 'to' attributes have been deleted,
490 * then ensure that the 'tail' is updated to point
505 * Move one kind of attributes from one list to the other
507 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
509 VALUE_PAIR *to_tail, *i, *next;
510 VALUE_PAIR *iprev = NULL;
513 * Find the last pair in the "to" list and put it in "to_tail".
517 for(i = *to; i; i = i->next)
522 for(i = *from; i; i = next) {
527 * If the attribute to move is NOT a VSA, then it
528 * ignores any attributes which do not match exactly.
530 if ((attr != PW_VENDOR_SPECIFIC) &&
531 (i->attribute != attr)) {
537 * If the attribute to move IS a VSA, then it ignores
538 * any non-VSA attribute.
540 if ((attr == PW_VENDOR_SPECIFIC) &&
541 (VENDOR(i->attribute) == 0)) {
547 * Remove the attribute from the "from" list.
555 * Add the attribute to the "to" list.
568 * Sort of strtok/strsep function.
570 static char *mystrtok(char **ptr, const char *sep)
576 while (**ptr && strchr(sep, **ptr))
581 while (**ptr && strchr(sep, **ptr) == NULL)
589 * Turn printable string into time_t
590 * Returns -1 on error, 0 on OK.
592 static int gettime(const char *valstr, uint32_t *lvalue)
603 * Test for unix timestamp date
605 *lvalue = strtoul(valstr, &tail, 10);
611 memset(tm, 0, sizeof(*tm));
612 tm->tm_isdst = -1; /* don't know, and don't care about DST */
614 strlcpy(buf, valstr, sizeof(buf));
617 f[0] = mystrtok(&p, " \t");
618 f[1] = mystrtok(&p, " \t");
619 f[2] = mystrtok(&p, " \t");
620 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
621 if (!f[0] || !f[1] || !f[2]) return -1;
624 * The time has a colon, where nothing else does.
625 * So if we find it, bubble it to the back of the list.
628 for (i = 0; i < 3; i++) {
629 if (strchr(f[i], ':')) {
639 * The month is text, which allows us to find it easily.
642 for (i = 0; i < 3; i++) {
643 if (isalpha( (int) *f[i])) {
645 * Bubble the month to the front of the list
651 for (i = 0; i < 12; i++) {
652 if (strncasecmp(months[i], f[0], 3) == 0) {
660 /* month not found? */
661 if (tm->tm_mon == 12) return -1;
664 * The year may be in f[1], or in f[2]
666 tm->tm_year = atoi(f[1]);
667 tm->tm_mday = atoi(f[2]);
669 if (tm->tm_year >= 1900) {
674 * We can't use 2-digit years any more, they make it
675 * impossible to tell what's the day, and what's the year.
677 if (tm->tm_mday < 1900) return -1;
680 * Swap the year and the day.
683 tm->tm_year = tm->tm_mday - 1900;
688 * If the day is out of range, die.
690 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
695 * There may be %H:%M:%S. Parse it in a hacky way.
698 f[0] = f[3]; /* HH */
699 f[1] = strchr(f[0], ':'); /* find : separator */
700 if (!f[1]) return -1;
702 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
704 f[2] = strchr(f[1], ':'); /* find : separator */
706 *(f[2]++) = '\0'; /* nuke it, and point to SS */
708 strcpy(f[2], "0"); /* assignment would discard const */
711 tm->tm_hour = atoi(f[0]);
712 tm->tm_min = atoi(f[1]);
713 tm->tm_sec = atoi(f[2]);
717 * Returns -1 on error.
720 if (t == (time_t) -1) return -1;
729 * Parse a string value into a given VALUE_PAIR
731 * FIXME: we probably want to fix this function to accept
732 * octets as values for any type of attribute. We should then
733 * double-check the parsed value, to be sure it's legal for that
734 * type (length, etc.)
736 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
743 * Even for integers, dates and ip addresses we
744 * keep the original string in vp->vp_strvalue.
746 strlcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
747 vp->length = strlen(vp->vp_strvalue);
752 * Already handled above.
758 * It's a comparison, not a real IP.
760 if ((vp->operator == T_OP_REG_EQ) ||
761 (vp->operator == T_OP_REG_NE)) {
766 * FIXME: complain if hostname
767 * cannot be resolved, or resolve later!
769 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
770 cs = s = strdup(value);
773 vp->flags.addport = 1;
780 lrad_ipaddr_t ipaddr;
782 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
783 librad_log("Failed to find IP address for %s", cs);
787 vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
795 * Note that ALL integers are unsigned!
797 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
799 if (vp->vp_integer > 255) {
800 librad_log("Byte value \"%s\" is larger than 255", value);
808 * Look for the named value for the given
811 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
812 librad_log("Unknown value %s for attribute %s",
816 vp->vp_integer = dval->value;
822 * Note that ALL integers are unsigned!
824 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
826 if (vp->vp_integer > 65535) {
827 librad_log("Byte value \"%s\" is larger than 65535", value);
835 * Look for the named value for the given
838 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
839 librad_log("Unknown value %s for attribute %s",
843 vp->vp_integer = dval->value;
847 case PW_TYPE_INTEGER:
849 * Note that ALL integers are unsigned!
851 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
858 * Look for the named value for the given
861 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
862 librad_log("Unknown value %s for attribute %s",
866 vp->vp_integer = dval->value;
871 if (gettime(value, &vp->vp_date) < 0) {
872 librad_log("failed to parse time string "
878 case PW_TYPE_ABINARY:
880 if (strncasecmp(value, "0x", 2) == 0) {
881 vp->type = PW_TYPE_OCTETS;
885 if (ascend_parse_filter(vp) < 0 ) {
886 librad_log("failed to parse Ascend binary attribute: %s",
893 * If Ascend binary is NOT defined,
894 * then fall through to raw octets, so that
895 * the user can at least make them by hand...
899 /* raw octets: 0x01020304... */
901 if (strncasecmp(value, "0x", 2) == 0) {
909 * There is only one character,
912 if ((strlen(cp) & 0x01) != 0) {
913 librad_log("Hex string is not an even length string.");
919 (vp->length < MAX_STRING_LEN)) {
922 if (sscanf(cp, "%02x", &tmp) != 1) {
923 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
935 if (ifid_aton(value, (unsigned char *) vp->vp_strvalue) == NULL) {
936 librad_log("failed to parse interface-id "
937 "string \"%s\"", value);
941 vp->vp_strvalue[vp->length] = '\0';
944 case PW_TYPE_IPV6ADDR:
945 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
946 librad_log("failed to parse IPv6 address "
947 "string \"%s\"", value);
950 vp->length = 16; /* length of IPv6 address */
951 vp->vp_strvalue[vp->length] = '\0';
956 case PW_TYPE_IPV6PREFIX:
957 p = strchr(value, '/');
958 if (!p || ((p - value) >= 256)) {
959 librad_log("invalid IPv6 prefix "
960 "string \"%s\"", value);
964 char buffer[256], *eptr;
966 memcpy(buffer, value, p - value);
967 buffer[p - value] = '\0';
969 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
970 librad_log("failed to parse IPv6 address "
971 "string \"%s\"", value);
975 prefix = strtoul(p + 1, &eptr, 10);
976 if ((prefix > 128) || *eptr) {
977 librad_log("failed to parse IPv6 address "
978 "string \"%s\"", value);
981 vp->vp_strvalue[1] = prefix;
983 vp->vp_strvalue[0] = '\0';
988 librad_log("unknown attribute type %d", vp->type);
996 * Create a VALUE_PAIR from an ASCII attribute and value,
997 * where the attribute name is in the form:
1002 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1010 * Unknown attributes MUST be of type 'octets'
1012 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1019 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1020 attr = atoi(attribute + 5);
1022 p += strspn(p, "0123456789");
1023 if (*p != 0) goto error;
1028 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1031 vendor = atoi(attribute + 7);
1032 if ((vendor == 0) || (vendor > 65535)) goto error;
1035 p += strspn(p, "0123456789");
1038 * Not Vendor-%d-Attr-%d
1040 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1045 p += strspn(p, "0123456789");
1046 if (*p != 0) goto error;
1048 if ((attr == 0) || (attr > 65535)) goto error;
1050 attr |= (vendor << 16);
1053 * VendorName-Attr-%d
1055 } else if (((p = strchr(attribute, '-')) != NULL) &&
1056 (strncasecmp(p, "-Attr-", 6) == 0)) {
1060 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1062 memcpy(buffer, attribute, p - attribute);
1063 buffer[p - attribute] = '\0';
1065 vendor = dict_vendorbyname(buffer);
1066 if (vendor == 0) goto error;
1071 p += strspn(p, "0123456789");
1072 if (*p != 0) goto error;
1074 if ((attr == 0) || (attr > 65535)) goto error;
1076 attr |= (vendor << 16);
1078 } else { /* very much unknown: die */
1080 librad_log("Unknown attribute \"%s\"", attribute);
1085 * We've now parsed the attribute properly, and verified
1086 * it to have value 'octets'. Let's create it.
1088 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1089 librad_log("out of memory");
1092 memset(vp, 0, sizeof(VALUE_PAIR));
1093 vp->type = PW_TYPE_OCTETS;
1096 * It may not be valid hex characters. If not, die.
1098 if (pairparsevalue(vp, value) == NULL) {
1103 if (VENDOR(attr) == 0) {
1104 sprintf(vp->name, "Attr-%u", attr);
1106 sprintf(vp->name, "Vendor-%u-Attr-%u",
1107 VENDOR(attr), attr & 0xffff);
1110 vp->attribute = attr;
1111 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1119 * Create a VALUE_PAIR from an ASCII attribute and value.
1121 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1134 * Check for tags in 'Attribute:Tag' format.
1139 ts = strrchr(attribute, ':');
1141 librad_log("Invalid tag for attribute %s", attribute);
1146 /* Colon found with something behind it */
1147 if (ts[1] == '*' && ts[2] == 0) {
1148 /* Wildcard tag for check items */
1151 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1152 /* It's not a wild card tag */
1153 tag = strtol(ts + 1, &tc, 0);
1154 if (tc && !*tc && TAG_VALID_ZERO(tag))
1158 librad_log("Invalid tag for attribute %s", attribute);
1165 * It's not found in the dictionary, so we use
1166 * another method to create the attribute.
1168 if ((da = dict_attrbyname(attribute)) == NULL) {
1169 return pairmake_any(attribute, value, operator);
1172 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1173 librad_log("out of memory");
1177 memset(vp, 0, sizeof(VALUE_PAIR));
1178 vp->attribute = da->attr;
1179 vp->type = da->type;
1180 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1181 strcpy(vp->name, da->name);
1182 vp->flags = da->flags;
1185 /* Check for a tag in the 'Merit' format of:
1186 * :Tag:Value. Print an error if we already found
1187 * a tag in the Attribute.
1190 if (value && (*value == ':' && da->flags.has_tag)) {
1191 /* If we already found a tag, this is invalid */
1194 librad_log("Duplicate tag %s for attribute %s",
1196 DEBUG("Duplicate tag %s for attribute %s\n",
1201 /* Colon found and attribute allows a tag */
1202 if (value[1] == '*' && value[2] == ':') {
1203 /* Wildcard tag for check items */
1208 tag = strtol(value + 1, &tc, 0);
1209 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1217 vp->flags.tag = tag;
1220 switch (vp->operator) {
1225 * For =* and !* operators, the value is irrelevant
1229 case T_OP_CMP_FALSE:
1230 vp->vp_strvalue[0] = '\0';
1236 * Regular expression comparison of integer attributes
1237 * does a STRING comparison of the names of their
1238 * integer attributes.
1240 case T_OP_REG_EQ: /* =~ */
1241 case T_OP_REG_NE: /* !~ */
1242 if (vp->type == PW_TYPE_INTEGER) {
1247 * Regular expression match with no regular
1248 * expression is wrong.
1255 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1259 regerror(res, &cre, msg, sizeof(msg));
1260 librad_log("Illegal regular expression in attribute: %s: %s",
1267 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1275 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1276 * then the user MAY have typed in the attribute name
1277 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1279 * We probably want to fix pairparsevalue to accept
1280 * octets as values for any attribute.
1282 if (value && (pairparsevalue(vp, value) == NULL)) {
1294 static const int valid_attr_name[256] = {
1295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1298 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1299 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1300 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1301 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1302 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1304 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1310 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1314 * Read a valuepair from a buffer, and advance pointer.
1315 * Sets *eol to T_EOL if end of line was encountered.
1317 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1323 LRAD_TOKEN token, t, xlat;
1327 *eol = T_OP_INVALID;
1330 while ((*p == ' ') || (*p == '\t')) p++;
1333 *eol = T_OP_INVALID;
1334 librad_log("No token read where we expected an attribute name");
1340 librad_log("Read a comment instead of a token");
1345 for (len = 0; len < sizeof(attr); len++) {
1346 if (valid_attr_name[(int)*p]) {
1353 if (len == sizeof(attr)) {
1354 *eol = T_OP_INVALID;
1355 librad_log("Attribute name is too long");
1360 * We may have Foo-Bar:= stuff, so back up.
1362 if (attr[len - 1] == ':') {
1370 /* Now we should have an operator here. */
1371 token = gettoken(ptr, buf, sizeof(buf));
1372 if (token < T_EQSTART || token > T_EQEND) {
1373 librad_log("expecting operator");
1377 /* Read value. Note that empty string values are allowed */
1378 xlat = gettoken(ptr, value, sizeof(value));
1379 if (xlat == T_EOL) {
1380 librad_log("failed to get value");
1385 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1388 t = gettoken(&p, buf, sizeof(buf));
1389 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1390 librad_log("Expected end of line or comma");
1402 * Make the full pair now.
1405 vp = pairmake(attr, value, token);
1411 case T_DOUBLE_QUOTED_STRING:
1412 p = strchr(value, '%');
1413 if (p && (p[1] == '{')) {
1414 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1415 librad_log("Value too long");
1418 vp = pairmake(attr, NULL, token);
1420 *eol = T_OP_INVALID;
1424 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1425 vp->flags.do_xlat = 1;
1428 vp = pairmake(attr, value, token);
1434 * Mark the pair to be allocated later.
1436 case T_BACK_QUOTED_STRING:
1437 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1438 librad_log("Value too long");
1442 vp = pairmake(attr, NULL, token);
1444 *eol = T_OP_INVALID;
1448 vp->flags.do_xlat = 1;
1449 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1455 * If we didn't make a pair, return an error.
1458 *eol = T_OP_INVALID;
1466 * Read one line of attribute/value pairs. This might contain
1467 * multiple pairs seperated by comma's.
1469 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1473 LRAD_TOKEN last_token = T_OP_INVALID;
1474 LRAD_TOKEN previous_token;
1477 * We allow an empty line.
1484 previous_token = last_token;
1485 if ((vp = pairread(&p, &last_token)) == NULL) {
1488 pairadd(first_pair, vp);
1489 } while (*p && (last_token == T_COMMA));
1492 * Don't tell the caller that there was a comment.
1494 if (last_token == T_HASH) {
1495 return previous_token;
1499 * And return the last token which we read.
1505 * Read valuepairs from the fp up to End-Of-File.
1507 * Hmm... this function is only used by radclient..
1509 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1512 LRAD_TOKEN last_token = T_EOL;
1519 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1521 * If we get a '\n' by itself, we assume that's
1522 * the end of that VP
1524 if ((buf[0] == '\n') && (list)) {
1527 if ((buf[0] == '\n') && (!list)) {
1532 * Comments get ignored
1534 if (buf[0] == '#') continue;
1537 * Read all of the attributes on the current line.
1540 last_token = userparse(buf, &vp);
1542 if (last_token != T_EOL) {
1543 librad_perror("%s", errprefix);
1554 if (error) pairfree(&list);
1558 return error ? NULL: list;
1564 * Compare two pairs, using the operator from "one".
1566 * i.e. given two attributes, it does:
1568 * (two->data) (one->operator) (one->data)
1570 * e.g. "foo" != "bar"
1572 * Returns true (comparison is true), or false (comparison is not true);
1574 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1578 switch (one->operator) {
1580 return (two != NULL);
1582 case T_OP_CMP_FALSE:
1583 return (two == NULL);
1586 * One is a regex, compile it, print two to a string,
1587 * and then do string comparisons.
1591 #ifndef HAVE_REGEX_H
1596 char buffer[MAX_STRING_LEN * 4 + 1];
1598 compare = regcomp(®, one->vp_strvalue,
1601 regerror(compare, ®, buffer, sizeof(buffer));
1602 librad_log("Illegal regular expression in attribute: %s: %s",
1607 vp_prints_value(buffer, sizeof(buffer), two, 0);
1610 * Don't care about substring matches,
1613 compare = regexec(®, buffer, 0, NULL, 0);
1616 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1617 return (compare != 0);
1621 default: /* we're OK */
1626 * After doing the previous check for special comparisons,
1627 * do the per-type comparison here.
1629 switch (one->type) {
1630 case PW_TYPE_ABINARY:
1631 case PW_TYPE_OCTETS:
1634 const uint8_t *p, *q;
1636 if (one->length < two->length) {
1637 length = one->length;
1639 length = two->length;
1645 compare = ((int) *p) - ((int) *q);
1646 if (compare != 0) goto type_switch;
1650 * Contents are the same. The return code
1651 * is therefore the difference in lengths.
1653 * i.e. "0x00" is smaller than "0x0000"
1655 compare = two->length - one->length;
1659 case PW_TYPE_STRING:
1660 if (one->flags.caseless) {
1661 compare = strcasecmp(two->vp_strvalue,
1664 compare = strcmp(two->vp_strvalue,
1671 case PW_TYPE_INTEGER:
1673 compare = two->vp_integer - one->vp_integer;
1676 case PW_TYPE_IPADDR:
1677 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1680 case PW_TYPE_IPV6ADDR:
1681 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1682 sizeof(two->vp_ipv6addr));
1685 case PW_TYPE_IPV6PREFIX:
1686 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1687 sizeof(two->vp_ipv6prefix));
1691 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1692 sizeof(two->vp_ifid));
1696 return 0; /* unknown type */
1700 * Now do the operator comparison.
1703 switch (one->operator) {
1705 return (compare == 0);
1708 return (compare != 0);
1711 return (compare < 0);
1714 return (compare > 0);
1717 return (compare <= 0);
1720 return (compare >= 0);