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" };
42 VALUE_PAIR *pairalloc(DICT_ATTR *da)
46 vp = malloc(sizeof(*vp));
48 memset(vp, 0, sizeof(*vp));
51 vp->attribute = da->attr;
52 vp->vendor = da->vendor;
54 strlcpy(vp->name, da->name, sizeof(vp->name));
55 vp->flags = da->flags;
59 vp->type = PW_TYPE_OCTETS;
61 memset(&vp->flags, 0, sizeof(vp->flags));
80 vp->length = sizeof(vp->vp_ifid);
83 case PW_TYPE_IPV6ADDR:
84 vp->length = sizeof(vp->vp_ipv6addr);
87 case PW_TYPE_IPV6PREFIX:
88 vp->length = sizeof(vp->vp_ipv6prefix);
91 case PW_TYPE_ETHERNET:
92 vp->length = sizeof(vp->vp_ether);
105 * Create a new valuepair.
107 VALUE_PAIR *paircreate(int attr, int type)
112 da = dict_attrbyvalue(attr);
113 if ((vp = pairalloc(da)) == NULL) {
114 librad_log("out of memory");
117 vp->operator = T_OP_EQ;
123 if (VENDOR(attr) == 0) {
124 sprintf(vp->name, "Attr-%u", attr);
129 v = dict_vendorbyvalue(VENDOR(attr));
131 sprintf(vp->name, "%s-Attr-%u",
132 v->name, attr & 0xffff);
134 sprintf(vp->name, "Vendor-%u-Attr-%u",
135 VENDOR(attr), attr & 0xffff);
148 * release the memory used by a single attribute-value pair
149 * just a wrapper around free() for now.
151 void pairbasicfree(VALUE_PAIR *pair)
153 /* clear the memory here */
154 memset(pair, 0, sizeof(*pair));
159 * Release the memory used by a list of attribute-value
160 * pairs, and sets the pair pointer to NULL.
162 void pairfree(VALUE_PAIR **pair_ptr)
164 VALUE_PAIR *next, *pair;
166 if (!pair_ptr) return;
169 while (pair != NULL) {
180 * Find the pair with the matching attribute
182 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
184 while(first && first->attribute != attr)
191 * Delete the pair(s) with the matching attribute
193 void pairdelete(VALUE_PAIR **first, int attr)
195 VALUE_PAIR *i, *next;
196 VALUE_PAIR **last = first;
198 for(i = *first; i; i = next) {
200 if (i->attribute == attr) {
210 * Add a pair at the end of a VALUE_PAIR list.
212 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
218 if (*first == NULL) {
222 for(i = *first; i->next; i = i->next)
228 * Add or replace a pair at the end of a VALUE_PAIR list.
230 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
232 VALUE_PAIR *i, *next;
233 VALUE_PAIR **prev = first;
235 if (*first == NULL) {
241 * Not an empty list, so find item if it is there, and
242 * replace it. Note, we always replace the first one, and
243 * we ignore any others that might exist.
245 for(i = *first; i; i = next) {
249 * Found the first attribute, replace it,
252 if (i->attribute == replace->attribute) {
256 * Should really assert that replace->next == NULL
258 replace->next = next;
264 * Point to where the attribute should go.
270 * If we got here, we didn't find anything to replace, so
271 * stopped at the last item, which we just append to.
277 * Copy just a certain type of pairs.
279 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
281 VALUE_PAIR *first, *n, **last;
287 if (attr >= 0 && vp->attribute != attr) {
291 if ((n = malloc(sizeof(*n))) == NULL) {
292 librad_log("out of memory");
295 memcpy(n, vp, sizeof(VALUE_PAIR));
308 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
310 return paircopy2(vp, -1);
315 * Move attributes from one list to the other
316 * if not already present.
318 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
320 VALUE_PAIR **tailto, *i, *j, *next;
321 VALUE_PAIR *tailfrom = NULL;
323 int has_password = 0;
326 * First, see if there are any passwords here, and
327 * point "tailto" to the end of the "to" list.
330 for(i = *to; i; i = i->next) {
331 if (i->attribute == PW_USER_PASSWORD ||
332 i->attribute == PW_CRYPT_PASSWORD)
338 * Loop over the "from" list.
340 for(i = *from; i; i = next) {
344 * If there was a password in the "to" list,
345 * do not move any other password from the
346 * "from" to the "to" list.
349 (i->attribute == PW_USER_PASSWORD ||
350 i->attribute == PW_CRYPT_PASSWORD)) {
355 switch (i->operator) {
357 * These are COMPARISON attributes
358 * from a check list, and are not
359 * supposed to be copied!
377 * If the attribute is already present in "to",
378 * do not move it from "from" to "to". We make
379 * an exception for "Hint" which can appear multiple
380 * times, and we never move "Fall-Through".
382 if (i->attribute == PW_FALL_THROUGH ||
383 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
385 found = pairfind(*to, i->attribute);
386 switch (i->operator) {
389 * If matching attributes are found,
392 case T_OP_SUB: /* -= */
394 if (!i->vp_strvalue[0] ||
395 (strcmp((char *)found->vp_strvalue,
396 (char *)i->vp_strvalue) == 0)){
397 pairdelete(to, found->attribute);
400 * 'tailto' may have been
404 for(j = *to; j; j = j->next) {
413 /* really HAVE_REGEX_H */
416 * Attr-Name =~ "s/find/replace/"
418 * Very bad code. Barely working,
424 (i->vp_strvalue[0] == 's')) {
431 p = i->vp_strvalue + 1;
432 q = strchr(p + 1, *p);
433 if (!q || (q[strlen(q) - 1] != *p)) {
437 str = strdup(i->vp_strvalue + 2);
440 q[strlen(q) - 1] = '\0';
442 regcomp(®, str, 0);
443 if (regexec(®, found->vp_strvalue,
445 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
446 found->vp_strvalue, match[0].rm_so,
453 tailfrom = i; /* don't copy it over */
457 case T_OP_EQ: /* = */
459 * FIXME: Tunnel attributes with
460 * different tags are different
465 continue; /* with the loop */
470 * If a similar attribute is found,
471 * replace it with the new one. Otherwise,
472 * add the new one to the list.
474 case T_OP_SET: /* := */
476 VALUE_PAIR *mynext = found->next;
479 * Do NOT call pairdelete()
480 * here, due to issues with
481 * re-writing "request->username".
483 * Everybody calls pairmove,
484 * and expects it to work.
485 * We can't update request->username
486 * here, so instead we over-write
487 * the vp that it's pointing to.
489 memcpy(found, i, sizeof(*found));
490 found->next = mynext;
492 pairdelete(&found->next, found->attribute);
495 * 'tailto' may have been
498 for(j = found; j; j = j->next) {
506 * Add the new element to the list, even
507 * if similar ones already exist.
510 case T_OP_ADD: /* += */
515 tailfrom->next = next;
520 * If ALL of the 'to' attributes have been deleted,
521 * then ensure that the 'tail' is updated to point
536 * Move one kind of attributes from one list to the other
538 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
540 VALUE_PAIR *to_tail, *i, *next;
541 VALUE_PAIR *iprev = NULL;
544 * Find the last pair in the "to" list and put it in "to_tail".
548 for(i = *to; i; i = i->next)
553 for(i = *from; i; i = next) {
558 * If the attribute to move is NOT a VSA, then it
559 * ignores any attributes which do not match exactly.
561 if ((attr != PW_VENDOR_SPECIFIC) &&
562 (i->attribute != attr)) {
568 * If the attribute to move IS a VSA, then it ignores
569 * any non-VSA attribute.
571 if ((attr == PW_VENDOR_SPECIFIC) &&
572 (VENDOR(i->attribute) == 0)) {
578 * Remove the attribute from the "from" list.
586 * Add the attribute to the "to" list.
599 * Sort of strtok/strsep function.
601 static char *mystrtok(char **ptr, const char *sep)
607 while (**ptr && strchr(sep, **ptr))
612 while (**ptr && strchr(sep, **ptr) == NULL)
620 * Turn printable string into time_t
621 * Returns -1 on error, 0 on OK.
623 static int gettime(const char *valstr, uint32_t *lvalue)
634 * Test for unix timestamp date
636 *lvalue = strtoul(valstr, &tail, 10);
642 memset(tm, 0, sizeof(*tm));
643 tm->tm_isdst = -1; /* don't know, and don't care about DST */
645 strlcpy(buf, valstr, sizeof(buf));
648 f[0] = mystrtok(&p, " \t");
649 f[1] = mystrtok(&p, " \t");
650 f[2] = mystrtok(&p, " \t");
651 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
652 if (!f[0] || !f[1] || !f[2]) return -1;
655 * The time has a colon, where nothing else does.
656 * So if we find it, bubble it to the back of the list.
659 for (i = 0; i < 3; i++) {
660 if (strchr(f[i], ':')) {
670 * The month is text, which allows us to find it easily.
673 for (i = 0; i < 3; i++) {
674 if (isalpha( (int) *f[i])) {
676 * Bubble the month to the front of the list
682 for (i = 0; i < 12; i++) {
683 if (strncasecmp(months[i], f[0], 3) == 0) {
691 /* month not found? */
692 if (tm->tm_mon == 12) return -1;
695 * The year may be in f[1], or in f[2]
697 tm->tm_year = atoi(f[1]);
698 tm->tm_mday = atoi(f[2]);
700 if (tm->tm_year >= 1900) {
705 * We can't use 2-digit years any more, they make it
706 * impossible to tell what's the day, and what's the year.
708 if (tm->tm_mday < 1900) return -1;
711 * Swap the year and the day.
714 tm->tm_year = tm->tm_mday - 1900;
719 * If the day is out of range, die.
721 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
726 * There may be %H:%M:%S. Parse it in a hacky way.
729 f[0] = f[3]; /* HH */
730 f[1] = strchr(f[0], ':'); /* find : separator */
731 if (!f[1]) return -1;
733 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
735 f[2] = strchr(f[1], ':'); /* find : separator */
737 *(f[2]++) = '\0'; /* nuke it, and point to SS */
739 strcpy(f[2], "0"); /* assignment would discard const */
742 tm->tm_hour = atoi(f[0]);
743 tm->tm_min = atoi(f[1]);
744 tm->tm_sec = atoi(f[2]);
748 * Returns -1 on error.
751 if (t == (time_t) -1) return -1;
758 static const char *hextab = "0123456789abcdef";
761 * Parse a string value into a given VALUE_PAIR
763 * FIXME: we probably want to fix this function to accept
764 * octets as values for any type of attribute. We should then
765 * double-check the parsed value, to be sure it's legal for that
766 * type (length, etc.)
768 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
776 * Even for integers, dates and ip addresses we
777 * keep the original string in vp->vp_strvalue.
779 strlcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
780 vp->length = strlen(vp->vp_strvalue);
791 while (*cp && (length < sizeof(vp->vp_strvalue))) {
821 c = '\\'; /* no cp++ */
824 if ((cp[0] >= '0') &&
830 (sscanf(cp, "%3o", &x) == 1)) {
833 } /* else just do '\\' */
844 * It's a comparison, not a real IP.
846 if ((vp->operator == T_OP_REG_EQ) ||
847 (vp->operator == T_OP_REG_NE)) {
852 * FIXME: complain if hostname
853 * cannot be resolved, or resolve later!
855 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
856 cs = s = strdup(value);
859 vp->flags.addport = 1;
866 lrad_ipaddr_t ipaddr;
868 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
869 librad_log("Failed to find IP address for %s", cs);
873 vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
880 if ((value[0] == '0') && (value[1] == 'x')) {
885 * Note that ALL integers are unsigned!
887 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
889 if (vp->vp_integer > 255) {
890 librad_log("Byte value \"%s\" is larger than 255", value);
898 * Look for the named value for the given
901 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
902 librad_log("Unknown value %s for attribute %s",
906 vp->vp_integer = dval->value;
912 * Note that ALL integers are unsigned!
914 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
916 if (vp->vp_integer > 65535) {
917 librad_log("Byte value \"%s\" is larger than 65535", value);
925 * Look for the named value for the given
928 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
929 librad_log("Unknown value %s for attribute %s",
933 vp->vp_integer = dval->value;
937 case PW_TYPE_INTEGER:
939 * Note that ALL integers are unsigned!
941 vp->vp_integer = (uint32_t) strtoul(value, &p, 10);
948 * Look for the named value for the given
951 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
952 librad_log("Unknown value %s for attribute %s",
956 vp->vp_integer = dval->value;
963 * time_t may be 64 bits, whule vp_date
964 * MUST be 32-bits. We need an
965 * intermediary variable to handle
970 if (gettime(value, &date) < 0) {
971 librad_log("failed to parse time string "
981 case PW_TYPE_ABINARY:
983 if (strncasecmp(value, "0x", 2) == 0) {
984 vp->type = PW_TYPE_OCTETS;
988 if (ascend_parse_filter(vp) < 0 ) {
989 librad_log("failed to parse Ascend binary attribute: %s",
996 * If Ascend binary is NOT defined,
997 * then fall through to raw octets, so that
998 * the user can at least make them by hand...
1002 /* raw octets: 0x01020304... */
1003 case PW_TYPE_OCTETS:
1004 if (strncasecmp(value, "0x", 2) == 0) {
1012 * There is only one character,
1015 if ((strlen(cp) & 0x01) != 0) {
1016 librad_log("Hex string is not an even length string.");
1022 (vp->length < MAX_STRING_LEN)) {
1025 if (sscanf(cp, "%02x", &tmp) != 1) {
1026 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
1038 if (ifid_aton(value, (unsigned char *) vp->vp_strvalue) == NULL) {
1039 librad_log("failed to parse interface-id "
1040 "string \"%s\"", value);
1044 vp->vp_strvalue[vp->length] = '\0';
1047 case PW_TYPE_IPV6ADDR:
1048 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
1049 librad_log("failed to parse IPv6 address "
1050 "string \"%s\"", value);
1053 vp->length = 16; /* length of IPv6 address */
1054 vp->vp_strvalue[vp->length] = '\0';
1057 case PW_TYPE_IPV6PREFIX:
1058 p = strchr(value, '/');
1059 if (!p || ((p - value) >= 256)) {
1060 librad_log("invalid IPv6 prefix "
1061 "string \"%s\"", value);
1064 unsigned int prefix;
1065 char buffer[256], *eptr;
1067 memcpy(buffer, value, p - value);
1068 buffer[p - value] = '\0';
1070 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
1071 librad_log("failed to parse IPv6 address "
1072 "string \"%s\"", value);
1076 prefix = strtoul(p + 1, &eptr, 10);
1077 if ((prefix > 128) || *eptr) {
1078 librad_log("failed to parse IPv6 address "
1079 "string \"%s\"", value);
1082 vp->vp_strvalue[1] = prefix;
1084 vp->vp_strvalue[0] = '\0';
1085 vp->length = 16 + 2;
1088 case PW_TYPE_ETHERNET:
1091 const char *c1, *c2;
1097 c2 = memchr(hextab, tolower((int) cp[0]), 16);
1099 } else if ((cp[1] != '\0') &&
1102 c1 = memchr(hextab, tolower((int) cp[0]), 16);
1103 c2 = memchr(hextab, tolower((int) cp[1]), 16);
1105 if (*cp == ':') cp++;
1109 if (!c1 || !c2 || (i >= sizeof(vp->vp_ether))) {
1110 librad_log("failed to parse Ethernet address \"%s\"", value);
1113 vp->vp_ether[i] = ((c1-hextab)<<4) + (c2-hextab);
1124 librad_log("unknown attribute type %d", vp->type);
1132 * Create a VALUE_PAIR from an ASCII attribute and value,
1133 * where the attribute name is in the form:
1138 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1146 * Unknown attributes MUST be of type 'octets'
1148 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1155 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1156 attr = atoi(attribute + 5);
1158 p += strspn(p, "0123456789");
1159 if (*p != 0) goto error;
1164 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1167 vendor = atoi(attribute + 7);
1168 if ((vendor == 0) || (vendor > 65535)) goto error;
1171 p += strspn(p, "0123456789");
1174 * Not Vendor-%d-Attr-%d
1176 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1181 p += strspn(p, "0123456789");
1182 if (*p != 0) goto error;
1184 if ((attr == 0) || (attr > 65535)) goto error;
1186 attr |= (vendor << 16);
1189 * VendorName-Attr-%d
1191 } else if (((p = strchr(attribute, '-')) != NULL) &&
1192 (strncasecmp(p, "-Attr-", 6) == 0)) {
1196 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1198 memcpy(buffer, attribute, p - attribute);
1199 buffer[p - attribute] = '\0';
1201 vendor = dict_vendorbyname(buffer);
1202 if (vendor == 0) goto error;
1207 p += strspn(p, "0123456789");
1208 if (*p != 0) goto error;
1210 if ((attr == 0) || (attr > 65535)) goto error;
1212 attr |= (vendor << 16);
1214 } else { /* very much unknown: die */
1216 librad_log("Unknown attribute \"%s\"", attribute);
1221 * We've now parsed the attribute properly, Let's create
1222 * it. This next stop also looks the attribute up in the
1223 * dictionary, and creates the appropriate type for it.
1225 if ((vp = paircreate(attr, PW_TYPE_OCTETS)) == NULL) {
1226 librad_log("out of memory");
1230 if (pairparsevalue(vp, value) == NULL) {
1234 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1241 * Create a VALUE_PAIR from an ASCII attribute and value.
1243 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1256 * Check for tags in 'Attribute:Tag' format.
1261 ts = strrchr(attribute, ':');
1263 librad_log("Invalid tag for attribute %s", attribute);
1268 /* Colon found with something behind it */
1269 if (ts[1] == '*' && ts[2] == 0) {
1270 /* Wildcard tag for check items */
1273 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1274 /* It's not a wild card tag */
1275 tag = strtol(ts + 1, &tc, 0);
1276 if (tc && !*tc && TAG_VALID_ZERO(tag))
1280 librad_log("Invalid tag for attribute %s", attribute);
1287 * It's not found in the dictionary, so we use
1288 * another method to create the attribute.
1290 if ((da = dict_attrbyname(attribute)) == NULL) {
1291 return pairmake_any(attribute, value, operator);
1294 if ((vp = pairalloc(da)) == NULL) {
1295 librad_log("out of memory");
1298 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1300 /* Check for a tag in the 'Merit' format of:
1301 * :Tag:Value. Print an error if we already found
1302 * a tag in the Attribute.
1305 if (value && (*value == ':' && da->flags.has_tag)) {
1306 /* If we already found a tag, this is invalid */
1309 librad_log("Duplicate tag %s for attribute %s",
1311 DEBUG("Duplicate tag %s for attribute %s\n",
1316 /* Colon found and attribute allows a tag */
1317 if (value[1] == '*' && value[2] == ':') {
1318 /* Wildcard tag for check items */
1323 tag = strtol(value + 1, &tc, 0);
1324 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1332 vp->flags.tag = tag;
1335 switch (vp->operator) {
1340 * For =* and !* operators, the value is irrelevant
1344 case T_OP_CMP_FALSE:
1345 vp->vp_strvalue[0] = '\0';
1351 * Regular expression comparison of integer attributes
1352 * does a STRING comparison of the names of their
1353 * integer attributes.
1355 case T_OP_REG_EQ: /* =~ */
1356 case T_OP_REG_NE: /* !~ */
1357 if (vp->type == PW_TYPE_INTEGER) {
1362 * Regular expression match with no regular
1363 * expression is wrong.
1370 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1374 regerror(res, &cre, msg, sizeof(msg));
1375 librad_log("Illegal regular expression in attribute: %s: %s",
1382 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1390 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1391 * then the user MAY have typed in the attribute name
1392 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1394 * We probably want to fix pairparsevalue to accept
1395 * octets as values for any attribute.
1397 if (value && (pairparsevalue(vp, value) == NULL)) {
1409 static const int valid_attr_name[256] = {
1410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1413 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1414 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1416 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1419 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1429 * Read a valuepair from a buffer, and advance pointer.
1430 * Sets *eol to T_EOL if end of line was encountered.
1432 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1438 LRAD_TOKEN token, t, xlat;
1442 *eol = T_OP_INVALID;
1445 while ((*p == ' ') || (*p == '\t')) p++;
1448 *eol = T_OP_INVALID;
1449 librad_log("No token read where we expected an attribute name");
1455 librad_log("Read a comment instead of a token");
1460 for (len = 0; len < sizeof(attr); len++) {
1461 if (valid_attr_name[(int)*p]) {
1468 if (len == sizeof(attr)) {
1469 *eol = T_OP_INVALID;
1470 librad_log("Attribute name is too long");
1475 * We may have Foo-Bar:= stuff, so back up.
1477 if (attr[len - 1] == ':') {
1485 /* Now we should have an operator here. */
1486 token = gettoken(ptr, buf, sizeof(buf));
1487 if (token < T_EQSTART || token > T_EQEND) {
1488 librad_log("expecting operator");
1492 /* Read value. Note that empty string values are allowed */
1493 xlat = gettoken(ptr, value, sizeof(value));
1494 if (xlat == T_EOL) {
1495 librad_log("failed to get value");
1500 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1503 t = gettoken(&p, buf, sizeof(buf));
1504 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1505 librad_log("Expected end of line or comma");
1517 * Make the full pair now.
1520 vp = pairmake(attr, value, token);
1526 case T_DOUBLE_QUOTED_STRING:
1527 p = strchr(value, '%');
1528 if (p && (p[1] == '{')) {
1529 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1530 librad_log("Value too long");
1533 vp = pairmake(attr, NULL, token);
1535 *eol = T_OP_INVALID;
1539 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1540 vp->flags.do_xlat = 1;
1543 vp = pairmake(attr, value, token);
1549 * Mark the pair to be allocated later.
1551 case T_BACK_QUOTED_STRING:
1552 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1553 librad_log("Value too long");
1557 vp = pairmake(attr, NULL, token);
1559 *eol = T_OP_INVALID;
1563 vp->flags.do_xlat = 1;
1564 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1570 * If we didn't make a pair, return an error.
1573 *eol = T_OP_INVALID;
1581 * Read one line of attribute/value pairs. This might contain
1582 * multiple pairs seperated by comma's.
1584 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1588 LRAD_TOKEN last_token = T_OP_INVALID;
1589 LRAD_TOKEN previous_token;
1592 * We allow an empty line.
1599 previous_token = last_token;
1600 if ((vp = pairread(&p, &last_token)) == NULL) {
1603 pairadd(first_pair, vp);
1604 } while (*p && (last_token == T_COMMA));
1607 * Don't tell the caller that there was a comment.
1609 if (last_token == T_HASH) {
1610 return previous_token;
1614 * And return the last token which we read.
1620 * Read valuepairs from the fp up to End-Of-File.
1622 * Hmm... this function is only used by radclient..
1624 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1627 LRAD_TOKEN last_token = T_EOL;
1634 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1636 * If we get a '\n' by itself, we assume that's
1637 * the end of that VP
1639 if ((buf[0] == '\n') && (list)) {
1642 if ((buf[0] == '\n') && (!list)) {
1647 * Comments get ignored
1649 if (buf[0] == '#') continue;
1652 * Read all of the attributes on the current line.
1655 last_token = userparse(buf, &vp);
1657 if (last_token != T_EOL) {
1658 librad_perror("%s", errprefix);
1669 if (error) pairfree(&list);
1673 return error ? NULL: list;
1679 * Compare two pairs, using the operator from "one".
1681 * i.e. given two attributes, it does:
1683 * (two->data) (one->operator) (one->data)
1685 * e.g. "foo" != "bar"
1687 * Returns true (comparison is true), or false (comparison is not true);
1689 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1693 switch (one->operator) {
1695 return (two != NULL);
1697 case T_OP_CMP_FALSE:
1698 return (two == NULL);
1701 * One is a regex, compile it, print two to a string,
1702 * and then do string comparisons.
1706 #ifndef HAVE_REGEX_H
1711 char buffer[MAX_STRING_LEN * 4 + 1];
1713 compare = regcomp(®, one->vp_strvalue,
1716 regerror(compare, ®, buffer, sizeof(buffer));
1717 librad_log("Illegal regular expression in attribute: %s: %s",
1722 vp_prints_value(buffer, sizeof(buffer), two, 0);
1725 * Don't care about substring matches,
1728 compare = regexec(®, buffer, 0, NULL, 0);
1731 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1732 return (compare != 0);
1736 default: /* we're OK */
1741 * After doing the previous check for special comparisons,
1742 * do the per-type comparison here.
1744 switch (one->type) {
1745 case PW_TYPE_ABINARY:
1746 case PW_TYPE_OCTETS:
1749 const uint8_t *p, *q;
1751 if (one->length < two->length) {
1752 length = one->length;
1754 length = two->length;
1760 compare = ((int) *p) - ((int) *q);
1761 if (compare != 0) goto type_switch;
1765 * Contents are the same. The return code
1766 * is therefore the difference in lengths.
1768 * i.e. "0x00" is smaller than "0x0000"
1770 compare = two->length - one->length;
1774 case PW_TYPE_STRING:
1775 if (one->flags.caseless) {
1776 compare = strcasecmp(two->vp_strvalue,
1779 compare = strcmp(two->vp_strvalue,
1786 case PW_TYPE_INTEGER:
1788 compare = two->vp_integer - one->vp_integer;
1791 case PW_TYPE_IPADDR:
1792 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1795 case PW_TYPE_IPV6ADDR:
1796 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1797 sizeof(two->vp_ipv6addr));
1800 case PW_TYPE_IPV6PREFIX:
1801 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1802 sizeof(two->vp_ipv6prefix));
1806 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1807 sizeof(two->vp_ifid));
1811 return 0; /* unknown type */
1815 * Now do the operator comparison.
1818 switch (one->operator) {
1820 return (compare == 0);
1823 return (compare != 0);
1826 return (compare < 0);
1829 return (compare > 0);
1832 return (compare <= 0);
1835 return (compare >= 0);