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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 * Copyright 2000 The FreeRADIUS server project
23 static const char rcsid[] = "$Id$";
25 #include <freeradius-devel/autoconf.h>
27 #include <sys/types.h>
42 #include <freeradius-devel/missing.h>
43 #include <freeradius-devel/libradius.h>
45 static const char *months[] = {
46 "jan", "feb", "mar", "apr", "may", "jun",
47 "jul", "aug", "sep", "oct", "nov", "dec" };
51 * Create a new valuepair.
53 VALUE_PAIR *paircreate(int attr, int type)
58 if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
59 librad_log("out of memory");
62 memset(vp, 0, sizeof(VALUE_PAIR));
64 vp->operator = T_OP_EQ;
68 * Dictionary type over-rides what the caller says.
70 if ((da = dict_attrbyvalue(attr)) != NULL) {
71 strcpy(vp->name, da->name);
73 vp->flags = da->flags;
74 } else if (VENDOR(attr) == 0) {
75 sprintf(vp->name, "Attr-%u", attr);
79 v = dict_vendorbyvalue(VENDOR(attr));
81 sprintf(vp->name, "%s-Attr-%u",
82 v->name, attr & 0xffff);
84 sprintf(vp->name, "Vendor-%u-Attr-%u",
85 VENDOR(attr), attr & 0xffff);
96 vp->length = sizeof(vp->vp_ifid);
99 case PW_TYPE_IPV6ADDR:
100 vp->length = sizeof(vp->vp_ipv6addr);
103 case PW_TYPE_IPV6PREFIX:
104 vp->length = sizeof(vp->vp_ipv6prefix);
116 * release the memory used by a single attribute-value pair
117 * just a wrapper around free() for now.
119 void pairbasicfree(VALUE_PAIR *pair)
121 /* clear the memory here */
122 memset(pair, 0, sizeof(*pair));
127 * Release the memory used by a list of attribute-value
128 * pairs, and sets the pair pointer to NULL.
130 void pairfree(VALUE_PAIR **pair_ptr)
132 VALUE_PAIR *next, *pair;
134 if (!pair_ptr) return;
137 while (pair != NULL) {
148 * Find the pair with the matching attribute
150 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
152 while(first && first->attribute != attr)
159 * Delete the pair(s) with the matching attribute
161 void pairdelete(VALUE_PAIR **first, int attr)
163 VALUE_PAIR *i, *next;
164 VALUE_PAIR **last = first;
166 for(i = *first; i; i = next) {
168 if (i->attribute == attr) {
178 * Add a pair at the end of a VALUE_PAIR list.
180 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
186 if (*first == NULL) {
190 for(i = *first; i->next; i = i->next)
196 * Add or replace a pair at the end of a VALUE_PAIR list.
198 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
200 VALUE_PAIR *i, *next;
201 VALUE_PAIR **prev = first;
203 if (*first == NULL) {
209 * Not an empty list, so find item if it is there, and
210 * replace it. Note, we always replace the first one, and
211 * we ignore any others that might exist.
213 for(i = *first; i; i = next) {
217 * Found the first attribute, replace it,
220 if (i->attribute == replace->attribute) {
224 * Should really assert that replace->next == NULL
226 replace->next = next;
232 * Point to where the attribute should go.
238 * If we got here, we didn't find anything to replace, so
239 * stopped at the last item, which we just append to.
245 * Copy just a certain type of pairs.
247 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
249 VALUE_PAIR *first, *n, **last;
255 if (attr >= 0 && vp->attribute != attr) {
259 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
260 librad_log("out of memory");
263 memcpy(n, vp, sizeof(VALUE_PAIR));
276 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
278 return paircopy2(vp, -1);
283 * Move attributes from one list to the other
284 * if not already present.
286 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
288 VALUE_PAIR **tailto, *i, *j, *next;
289 VALUE_PAIR *tailfrom = NULL;
291 int has_password = 0;
300 * First, see if there are any passwords here, and
301 * point "tailto" to the end of the "to" list.
304 for(i = *to; i; i = i->next) {
305 if (i->attribute == PW_PASSWORD ||
306 i->attribute == PW_CRYPT_PASSWORD)
312 * Loop over the "from" list.
314 for(i = *from; i; i = next) {
317 * If there was a password in the "to" list,
318 * do not move any other password from the
319 * "from" to the "to" list.
322 (i->attribute == PW_PASSWORD ||
323 i->attribute == PW_CRYPT_PASSWORD)) {
328 * If the attribute is already present in "to",
329 * do not move it from "from" to "to". We make
330 * an exception for "Hint" which can appear multiple
331 * times, and we never move "Fall-Through".
333 if (i->attribute == PW_FALL_THROUGH ||
334 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
336 found = pairfind(*to, i->attribute);
337 switch (i->operator) {
340 * If matching attributes are found,
343 case T_OP_SUB: /* -= */
345 if (!i->vp_strvalue[0] ||
346 (strcmp((char *)found->vp_strvalue,
347 (char *)i->vp_strvalue) == 0)){
348 pairdelete(to, found->attribute);
351 * 'tailto' may have been
355 for(j = *to; j; j = j->next) {
364 /* really HAVE_REGEX_H */
367 * Attr-Name =~ "s/find/replace/"
369 * Very bad code. Barely working,
375 (i->vp_strvalue[0] == 's')) {
382 p = i->vp_strvalue + 1;
383 q = strchr(p + 1, *p);
384 if (!q || (q[strlen(q) - 1] != *p)) {
388 str = strdup(i->vp_strvalue + 2);
391 q[strlen(q) - 1] = '\0';
393 regcomp(®, str, 0);
394 if (regexec(®, found->vp_strvalue,
396 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
397 found->vp_strvalue, match[0].rm_so,
404 tailfrom = i; /* don't copy it over */
408 case T_OP_EQ: /* = */
410 * FIXME: Tunnel attributes with
411 * different tags are different
416 continue; /* with the loop */
421 * If a similar attribute is found,
422 * replace it with the new one. Otherwise,
423 * add the new one to the list.
425 case T_OP_SET: /* := */
427 VALUE_PAIR *mynext = found->next;
430 * Do NOT call pairdelete()
431 * here, due to issues with
432 * re-writing "request->username".
434 * Everybody calls pairmove,
435 * and expects it to work.
436 * We can't update request->username
437 * here, so instead we over-write
438 * the vp that it's pointing to.
440 memcpy(found, i, sizeof(*found));
441 found->next = mynext;
443 pairdelete(&found->next, found->attribute);
446 * 'tailto' may have been
449 for(j = found; j; j = j->next) {
457 * Add the new element to the list, even
458 * if similar ones already exist.
461 case T_OP_ADD: /* += */
466 tailfrom->next = next;
471 * If ALL of the 'to' attributes have been deleted,
472 * then ensure that the 'tail' is updated to point
487 * Move one kind of attributes from one list to the other
489 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
491 VALUE_PAIR *to_tail, *i, *next;
492 VALUE_PAIR *iprev = NULL;
495 * Find the last pair in the "to" list and put it in "to_tail".
499 for(i = *to; i; i = i->next)
504 for(i = *from; i; i = next) {
509 * If the attribute to move is NOT a VSA, then it
510 * ignores any attributes which do not match exactly.
512 if ((attr != PW_VENDOR_SPECIFIC) &&
513 (i->attribute != attr)) {
519 * If the attribute to move IS a VSA, then it ignores
520 * any non-VSA attribute.
522 if ((attr == PW_VENDOR_SPECIFIC) &&
523 (VENDOR(i->attribute) == 0)) {
529 * Remove the attribute from the "from" list.
537 * Add the attribute to the "to" list.
550 * Sort of strtok/strsep function.
552 static char *mystrtok(char **ptr, const char *sep)
558 while (**ptr && strchr(sep, **ptr))
563 while (**ptr && strchr(sep, **ptr) == NULL)
571 * Turn printable string into time_t
572 * Returns -1 on error, 0 on OK.
574 static int gettime(const char *valstr, time_t *lvalue)
585 * Test for unix timestamp date
587 *lvalue = strtoul(valstr, &tail, 10);
593 memset(tm, 0, sizeof(*tm));
594 tm->tm_isdst = -1; /* don't know, and don't care about DST */
596 strNcpy(buf, valstr, sizeof(buf));
599 f[0] = mystrtok(&p, " \t");
600 f[1] = mystrtok(&p, " \t");
601 f[2] = mystrtok(&p, " \t");
602 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
603 if (!f[0] || !f[1] || !f[2]) return -1;
606 * The time has a colon, where nothing else does.
607 * So if we find it, bubble it to the back of the list.
610 for (i = 0; i < 3; i++) {
611 if (strchr(f[i], ':')) {
621 * The month is text, which allows us to find it easily.
624 for (i = 0; i < 3; i++) {
625 if (isalpha( (int) *f[i])) {
627 * Bubble the month to the front of the list
633 for (i = 0; i < 12; i++) {
634 if (strncasecmp(months[i], f[0], 3) == 0) {
642 /* month not found? */
643 if (tm->tm_mon == 12) return -1;
646 * The year may be in f[1], or in f[2]
648 tm->tm_year = atoi(f[1]);
649 tm->tm_mday = atoi(f[2]);
651 if (tm->tm_year >= 1900) {
656 * We can't use 2-digit years any more, they make it
657 * impossible to tell what's the day, and what's the year.
659 if (tm->tm_mday < 1900) return -1;
662 * Swap the year and the day.
665 tm->tm_year = tm->tm_mday - 1900;
670 * If the day is out of range, die.
672 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
677 * There may be %H:%M:%S. Parse it in a hacky way.
680 f[0] = f[3]; /* HH */
681 f[1] = strchr(f[0], ':'); /* find : separator */
682 if (!f[1]) return -1;
684 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
686 f[2] = strchr(f[1], ':'); /* find : separator */
688 *(f[2]++) = '\0'; /* nuke it, and point to SS */
693 tm->tm_hour = atoi(f[0]);
694 tm->tm_min = atoi(f[1]);
695 tm->tm_sec = atoi(f[2]);
699 * Returns -1 on error.
702 if (t == (time_t) -1) return -1;
711 * Parse a string value into a given VALUE_PAIR
713 * FIXME: we probably want to fix this function to accept
714 * octets as values for any type of attribute. We should then
715 * double-check the parsed value, to be sure it's legal for that
716 * type (length, etc.)
718 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
725 * Even for integers, dates and ip addresses we
726 * keep the original string in vp->vp_strvalue.
728 strNcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
729 vp->length = strlen(vp->vp_strvalue);
734 * Already handled above.
740 * It's a comparison, not a real IP.
742 if ((vp->operator == T_OP_REG_EQ) ||
743 (vp->operator == T_OP_REG_NE)) {
748 * FIXME: complain if hostname
749 * cannot be resolved, or resolve later!
751 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
752 cs = s = strdup(value);
755 vp->flags.addport = 1;
762 lrad_ipaddr_t ipaddr;
764 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
765 librad_log("Failed to find IP address for %s", cs);
769 vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
774 case PW_TYPE_INTEGER:
776 * If it starts with a digit, it must
777 * be a number (or a range).
779 * Note that ALL integers are unsigned!
781 if (isdigit((int) *value)) {
782 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
786 * Look for the named value for the given
789 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
790 librad_log("Unknown value %s for attribute %s",
794 vp->lvalue = dval->value;
800 if (gettime(value, (time_t *)&vp->lvalue) < 0) {
801 librad_log("failed to parse time string "
807 case PW_TYPE_ABINARY:
810 * Special case to convert filter to binary
812 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
813 if (ascend_parse_filter(vp) < 0 ) {
814 librad_log("failed to parse Ascend binary attribute: %s",
820 * If Ascend binary is NOT defined,
821 * then fall through to raw octets, so that
822 * the user can at least make them by hand...
825 /* raw octets: 0x01020304... */
827 if (strncasecmp(value, "0x", 2) == 0) {
830 us = vp->vp_strvalue;
835 * There is only one character,
838 if ((strlen(cp) & 0x01) != 0) {
839 librad_log("Hex string is not an even length string.");
844 while (*cp && vp->length < MAX_STRING_LEN) {
847 if (sscanf(cp, "%02x", &tmp) != 1) {
848 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
861 if (ifid_aton(value, vp->vp_strvalue) == NULL) {
862 librad_log("failed to parse interface-id "
863 "string \"%s\"", value);
867 vp->vp_strvalue[vp->length] = '\0';
870 case PW_TYPE_IPV6ADDR:
871 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
872 librad_log("failed to parse IPv6 address "
873 "string \"%s\"", value);
876 vp->length = 16; /* length of IPv6 address */
877 vp->vp_strvalue[vp->length] = '\0';
882 case PW_TYPE_IPV6PREFIX:
883 p = strchr(value, '/');
884 if (!p || ((p - value) >= 256)) {
885 librad_log("invalid IPv6 prefix "
886 "string \"%s\"", value);
890 char buffer[256], *eptr;
892 memcpy(buffer, value, p - value);
893 buffer[p - value] = '\0';
895 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
896 librad_log("failed to parse IPv6 address "
897 "string \"%s\"", value);
901 prefix = strtoul(p + 1, &eptr, 10);
902 if ((prefix > 128) || *eptr) {
903 librad_log("failed to parse IPv6 address "
904 "string \"%s\"", value);
907 vp->vp_strvalue[1] = prefix;
909 vp->vp_strvalue[0] = '\0';
914 librad_log("unknown attribute type %d", vp->type);
922 * Create a VALUE_PAIR from an ASCII attribute and value,
923 * where the attribute name is in the form:
928 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
937 * Unknown attributes MUST be of type 'octets'
939 if (value && (strncasecmp(value, "0x", 2) != 0)) {
946 if (strncasecmp(attribute, "Attr-", 5) == 0) {
947 attr = atoi(attribute + 5);
949 p += strspn(p, "0123456789");
950 if (*p != 0) goto error;
956 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
959 vendor = atoi(attribute + 7);
960 if ((vendor == 0) || (vendor > 65535)) goto error;
963 p += strspn(p, "0123456789");
966 * Not Vendor-%d-Attr-%d
968 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
973 p += strspn(p, "0123456789");
974 if (*p != 0) goto error;
976 if ((attr == 0) || (attr > 65535)) goto error;
978 attr |= (vendor << 16);
983 } else if (((p = strchr(attribute, '-')) != NULL) &&
984 (strncasecmp(p, "-Attr-", 6) == 0)) {
988 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
990 memcpy(buffer, attribute, p - attribute);
991 buffer[p - attribute] = '\0';
993 vendor = dict_vendorbyname(buffer);
994 if (vendor == 0) goto error;
999 p += strspn(p, "0123456789");
1000 if (*p != 0) goto error;
1002 if ((attr == 0) || (attr > 65535)) goto error;
1004 attr |= (vendor << 16);
1006 } else { /* very much unknown: die */
1008 librad_log("Unknown attribute \"%s\"", attribute);
1013 * We've now parsed the attribute properly, and verified
1014 * it to have value 'octets'. Let's create it.
1016 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1017 librad_log("out of memory");
1020 memset(vp, 0, sizeof(VALUE_PAIR));
1021 vp->type = PW_TYPE_OCTETS;
1024 * It may not be valid hex characters. If not, die.
1026 if (pairparsevalue(vp, value) == NULL) {
1032 * Dictionary type over-rides what the caller says.
1033 * This "converts" the parsed value into the appropriate
1036 * Also, normalize the name of the attribute...
1038 * Much of this code is copied from paircreate()
1040 if ((da = dict_attrbyvalue(attr)) != NULL) {
1041 strcpy(vp->name, da->name);
1042 vp->type = da->type;
1043 vp->flags = da->flags;
1046 * Sanity check the type for length. We don't
1047 * want to look at attributes which are of the
1052 case PW_TYPE_INTEGER:
1053 case PW_TYPE_IPADDR: /* always kept in network byte order */
1054 if (vp->length != 4) {
1057 librad_log("Attribute has invalid length");
1060 memcpy(&vp->lvalue, vp->vp_strvalue, sizeof(vp->lvalue));
1064 if (vp->length != 8) goto length_error;
1067 case PW_TYPE_IPV6ADDR:
1068 if (vp->length != 16) goto length_error;
1071 #ifdef ASCEND_BINARY
1072 case PW_TYPE_ABINARY:
1073 if (vp->length != 32) goto length_error;
1076 default: /* string, octets, etc. */
1080 } else if (VENDOR(attr) == 0) {
1081 sprintf(vp->name, "Attr-%u", attr);
1083 sprintf(vp->name, "Vendor-%u-Attr-%u",
1084 VENDOR(attr), attr & 0xffff);
1087 vp->attribute = attr;
1088 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1096 * Create a VALUE_PAIR from an ASCII attribute and value.
1098 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1111 * Check for tags in 'Attribute:Tag' format.
1116 ts = strrchr( attribute, ':' );
1118 /* Colon found with something behind it */
1119 if (ts[1] == '*' && ts[2] == 0) {
1120 /* Wildcard tag for check items */
1123 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1124 /* It's not a wild card tag */
1125 tag = strtol(ts + 1, &tc, 0);
1126 if (tc && !*tc && TAG_VALID_ZERO(tag))
1130 librad_log("Invalid tag for attribute %s", attribute);
1137 * It's not found in the dictionary, so we use
1138 * another method to create the attribute.
1140 if ((da = dict_attrbyname(attribute)) == NULL) {
1141 return pairmake_any(attribute, value, operator);
1144 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1145 librad_log("out of memory");
1149 memset(vp, 0, sizeof(VALUE_PAIR));
1150 vp->attribute = da->attr;
1151 vp->type = da->type;
1152 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1153 strcpy(vp->name, da->name);
1154 vp->flags = da->flags;
1157 /* Check for a tag in the 'Merit' format of:
1158 * :Tag:Value. Print an error if we already found
1159 * a tag in the Attribute.
1162 if (value && (*value == ':' && da->flags.has_tag)) {
1163 /* If we already found a tag, this is invalid */
1166 librad_log("Duplicate tag %s for attribute %s",
1168 DEBUG("Duplicate tag %s for attribute %s\n",
1173 /* Colon found and attribute allows a tag */
1174 if (value[1] == '*' && value[2] == ':') {
1175 /* Wildcard tag for check items */
1180 tag = strtol(value + 1, &tc, 0);
1181 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1189 vp->flags.tag = tag;
1192 switch (vp->operator) {
1197 * For =* and !* operators, the value is irrelevant
1201 case T_OP_CMP_FALSE:
1202 vp->vp_strvalue[0] = '\0';
1208 * Regular expression comparison of integer attributes
1209 * does a STRING comparison of the names of their
1210 * integer attributes.
1212 case T_OP_REG_EQ: /* =~ */
1213 case T_OP_REG_NE: /* !~ */
1214 if (vp->type == PW_TYPE_INTEGER) {
1219 * Regular expression match with no regular
1220 * expression is wrong.
1227 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1231 regerror(res, &cre, msg, sizeof(msg));
1232 librad_log("Illegal regular expression in attribute: %s: %s",
1239 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1247 * FIXME: if (strcasecmp(attriobute, vp->name) != 0)
1248 * then the user MAY have typed in the attribute name
1249 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1251 * We probably want to fix pairparsevalue to accept
1252 * octets as values for any attribute.
1254 if (value && (pairparsevalue(vp, value) == NULL)) {
1263 * Read a valuepair from a buffer, and advance pointer.
1264 * Sets *eol to T_EOL if end of line was encountered.
1266 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1272 LRAD_TOKEN token, t, xlat;
1275 *eol = T_OP_INVALID;
1277 /* Get attribute. */
1278 token = gettoken(ptr, attr, sizeof(attr));
1280 /* If it's a comment, then exit, as we haven't read a pair */
1281 if (token == T_HASH) {
1283 librad_log("Read a comment instead of a token");
1287 /* It's not a comment, so it MUST be an attribute */
1288 if ((token == T_EOL) ||
1290 librad_log("No token read where we expected an attribute name");
1294 /* Now we should have an '=' here. */
1295 token = gettoken(ptr, buf, sizeof(buf));
1296 if (token < T_EQSTART || token > T_EQEND) {
1297 librad_log("expecting '='");
1301 /* Read value. Note that empty string values are allowed */
1302 xlat = gettoken(ptr, value, sizeof(value));
1303 if (xlat == T_EOL) {
1304 librad_log("failed to get value");
1309 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1312 t = gettoken(&p, buf, sizeof(buf));
1313 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1314 librad_log("Expected end of line or comma");
1325 * Make the full pair now.
1328 vp = pairmake(attr, value, token);
1334 case T_DOUBLE_QUOTED_STRING:
1335 p = strchr(value, '%');
1336 if (p && (p[1] == '{')) {
1337 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1338 librad_log("Value too long");
1341 vp = pairmake(attr, NULL, token);
1343 *eol = T_OP_INVALID;
1347 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1348 vp->flags.do_xlat = 1;
1351 vp = pairmake(attr, value, token);
1357 * Mark the pair to be allocated later.
1359 case T_BACK_QUOTED_STRING:
1360 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1361 librad_log("Value too long");
1365 vp = pairmake(attr, NULL, token);
1367 *eol = T_OP_INVALID;
1371 vp->flags.do_xlat = 1;
1372 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1381 * Read one line of attribute/value pairs. This might contain
1382 * multiple pairs seperated by comma's.
1384 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1388 LRAD_TOKEN last_token = T_OP_INVALID;
1389 LRAD_TOKEN previous_token;
1392 * We allow an empty line.
1399 previous_token = last_token;
1400 if ((vp = pairread(&p, &last_token)) == NULL) {
1403 pairadd(first_pair, vp);
1404 } while (*p && (last_token == T_COMMA));
1407 * Don't tell the caller that there was a comment.
1409 if (last_token == T_HASH) {
1410 return previous_token;
1414 * And return the last token which we read.
1420 * Read valuepairs from the fp up to End-Of-File.
1422 * Hmm... this function is only used by radclient..
1424 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1427 LRAD_TOKEN last_token = T_EOL;
1434 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1436 * If we get a '\n' by itself, we assume that's
1437 * the end of that VP
1439 if ((buf[0] == '\n') && (list)) {
1442 if ((buf[0] == '\n') && (!list)) {
1447 * Comments get ignored
1449 if (buf[0] == '#') continue;
1452 * Read all of the attributes on the current line.
1455 last_token = userparse(buf, &vp);
1457 if (last_token != T_EOL) {
1458 librad_perror("%s", errprefix);
1469 if (error) pairfree(&list);
1473 return error ? NULL: list;
1479 * Compare two pairs, using the operator from "one".
1481 * i.e. given two attributes, it does:
1483 * (two->data) (one->operator) (one->data)
1485 * e.g. "foo" != "bar"
1487 * Returns true (comparison is true), or false (comparison is not true);
1489 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1493 switch (one->operator) {
1495 return (two != NULL);
1497 case T_OP_CMP_FALSE:
1498 return (two == NULL);
1501 * One is a regex, compile it, print two to a string,
1502 * and then do string comparisons.
1506 #ifndef HAVE_REGEX_H
1511 char buffer[MAX_STRING_LEN * 4 + 1];
1513 compare = regcomp(®, one->vp_strvalue,
1516 regerror(compare, ®, buffer, sizeof(buffer));
1517 librad_log("Illegal regular expression in attribute: %s: %s",
1522 vp_prints_value(buffer, sizeof(buffer), two, 0);
1525 * Don't care about substring matches,
1528 compare = regexec(®, buffer, 0, NULL, 0);
1531 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1532 return (compare != 0);
1536 default: /* we're OK */
1541 * After doing the previous check for special comparisons,
1542 * do the per-type comparison here.
1544 switch (one->type) {
1545 case PW_TYPE_ABINARY:
1546 case PW_TYPE_OCTETS:
1549 const uint8_t *p, *q;
1551 if (one->length < two->length) {
1552 length = one->length;
1554 length = two->length;
1560 compare = ((int) *p) - ((int) *q);
1561 if (compare != 0) goto type_switch;
1565 * Contents are the same. The return code
1566 * is therefore the difference in lengths.
1568 * i.e. "0x00" is smaller than "0x0000"
1570 compare = two->length - one->length;
1574 case PW_TYPE_STRING:
1575 if (one->flags.caseless) {
1576 compare = strcasecmp(two->vp_strvalue,
1579 compare = strcmp(two->vp_strvalue,
1584 case PW_TYPE_INTEGER:
1586 compare = two->lvalue - one->lvalue;
1589 case PW_TYPE_IPADDR:
1590 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1593 case PW_TYPE_IPV6ADDR:
1594 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1595 sizeof(two->vp_ipv6addr));
1598 case PW_TYPE_IPV6PREFIX:
1599 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1600 sizeof(two->vp_ipv6prefix));
1604 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1605 sizeof(two->vp_ifid));
1609 return 0; /* unknown type */
1613 * Now do the operator comparison.
1616 switch (one->operator) {
1618 return (compare == 0);
1621 return (compare != 0);
1624 return (compare < 0);
1627 return (compare > 0);
1630 return (compare <= 0);
1633 return (compare >= 0);