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 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 */
690 strcpy(f[2], "0"); /* assignment would discard const */
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 * Note that ALL integers are unsigned!
778 if (isdigit((int) value[0]) &&
779 (strspn(value, "0123456789") == strlen(value))) {
780 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
785 * Look for the named value for the given
788 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
789 librad_log("Unknown value %s for attribute %s",
793 vp->lvalue = dval->value;
799 if (gettime(value, (time_t *)&vp->lvalue) < 0) {
800 librad_log("failed to parse time string "
806 case PW_TYPE_ABINARY:
808 if (strncasecmp(value, "0x", 2) == 0) {
809 vp->type = PW_TYPE_OCTETS;
813 if (ascend_parse_filter(vp) < 0 ) {
814 librad_log("failed to parse Ascend binary attribute: %s",
821 * If Ascend binary is NOT defined,
822 * then fall through to raw octets, so that
823 * the user can at least make them by hand...
827 /* raw octets: 0x01020304... */
829 if (strncasecmp(value, "0x", 2) == 0) {
832 us = vp->vp_strvalue;
837 * There is only one character,
840 if ((strlen(cp) & 0x01) != 0) {
841 librad_log("Hex string is not an even length string.");
846 while (*cp && vp->length < MAX_STRING_LEN) {
849 if (sscanf(cp, "%02x", &tmp) != 1) {
850 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
863 if (ifid_aton(value, vp->vp_strvalue) == NULL) {
864 librad_log("failed to parse interface-id "
865 "string \"%s\"", value);
869 vp->vp_strvalue[vp->length] = '\0';
872 case PW_TYPE_IPV6ADDR:
873 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
874 librad_log("failed to parse IPv6 address "
875 "string \"%s\"", value);
878 vp->length = 16; /* length of IPv6 address */
879 vp->vp_strvalue[vp->length] = '\0';
884 case PW_TYPE_IPV6PREFIX:
885 p = strchr(value, '/');
886 if (!p || ((p - value) >= 256)) {
887 librad_log("invalid IPv6 prefix "
888 "string \"%s\"", value);
892 char buffer[256], *eptr;
894 memcpy(buffer, value, p - value);
895 buffer[p - value] = '\0';
897 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
898 librad_log("failed to parse IPv6 address "
899 "string \"%s\"", value);
903 prefix = strtoul(p + 1, &eptr, 10);
904 if ((prefix > 128) || *eptr) {
905 librad_log("failed to parse IPv6 address "
906 "string \"%s\"", value);
909 vp->vp_strvalue[1] = prefix;
911 vp->vp_strvalue[0] = '\0';
916 librad_log("unknown attribute type %d", vp->type);
924 * Create a VALUE_PAIR from an ASCII attribute and value,
925 * where the attribute name is in the form:
930 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
938 * Unknown attributes MUST be of type 'octets'
940 if (value && (strncasecmp(value, "0x", 2) != 0)) {
947 if (strncasecmp(attribute, "Attr-", 5) == 0) {
948 attr = atoi(attribute + 5);
950 p += strspn(p, "0123456789");
951 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) {
1031 if (VENDOR(attr) == 0) {
1032 sprintf(vp->name, "Attr-%u", attr);
1034 sprintf(vp->name, "Vendor-%u-Attr-%u",
1035 VENDOR(attr), attr & 0xffff);
1038 vp->attribute = attr;
1039 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1047 * Create a VALUE_PAIR from an ASCII attribute and value.
1049 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1062 * Check for tags in 'Attribute:Tag' format.
1067 ts = strrchr(attribute, ':');
1069 librad_log("Invalid tag for attribute %s", attribute);
1074 /* Colon found with something behind it */
1075 if (ts[1] == '*' && ts[2] == 0) {
1076 /* Wildcard tag for check items */
1079 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1080 /* It's not a wild card tag */
1081 tag = strtol(ts + 1, &tc, 0);
1082 if (tc && !*tc && TAG_VALID_ZERO(tag))
1086 librad_log("Invalid tag for attribute %s", attribute);
1093 * It's not found in the dictionary, so we use
1094 * another method to create the attribute.
1096 if ((da = dict_attrbyname(attribute)) == NULL) {
1097 return pairmake_any(attribute, value, operator);
1100 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1101 librad_log("out of memory");
1105 memset(vp, 0, sizeof(VALUE_PAIR));
1106 vp->attribute = da->attr;
1107 vp->type = da->type;
1108 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1109 strcpy(vp->name, da->name);
1110 vp->flags = da->flags;
1113 /* Check for a tag in the 'Merit' format of:
1114 * :Tag:Value. Print an error if we already found
1115 * a tag in the Attribute.
1118 if (value && (*value == ':' && da->flags.has_tag)) {
1119 /* If we already found a tag, this is invalid */
1122 librad_log("Duplicate tag %s for attribute %s",
1124 DEBUG("Duplicate tag %s for attribute %s\n",
1129 /* Colon found and attribute allows a tag */
1130 if (value[1] == '*' && value[2] == ':') {
1131 /* Wildcard tag for check items */
1136 tag = strtol(value + 1, &tc, 0);
1137 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1145 vp->flags.tag = tag;
1148 switch (vp->operator) {
1153 * For =* and !* operators, the value is irrelevant
1157 case T_OP_CMP_FALSE:
1158 vp->vp_strvalue[0] = '\0';
1164 * Regular expression comparison of integer attributes
1165 * does a STRING comparison of the names of their
1166 * integer attributes.
1168 case T_OP_REG_EQ: /* =~ */
1169 case T_OP_REG_NE: /* !~ */
1170 if (vp->type == PW_TYPE_INTEGER) {
1175 * Regular expression match with no regular
1176 * expression is wrong.
1183 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1187 regerror(res, &cre, msg, sizeof(msg));
1188 librad_log("Illegal regular expression in attribute: %s: %s",
1195 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1203 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1204 * then the user MAY have typed in the attribute name
1205 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1207 * We probably want to fix pairparsevalue to accept
1208 * octets as values for any attribute.
1210 if (value && (pairparsevalue(vp, value) == NULL)) {
1222 static const int valid_attr_name[256] = {
1223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1224 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1226 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1227 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1228 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1229 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1230 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1238 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1242 * Read a valuepair from a buffer, and advance pointer.
1243 * Sets *eol to T_EOL if end of line was encountered.
1245 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1251 LRAD_TOKEN token, t, xlat;
1255 *eol = T_OP_INVALID;
1258 while ((*p == ' ') || (*p == '\t')) p++;
1261 *eol = T_OP_INVALID;
1262 librad_log("No token read where we expected an attribute name");
1268 librad_log("Read a comment instead of a token");
1273 for (len = 0; len < sizeof(attr); len++) {
1274 if (valid_attr_name[(int)*p]) {
1281 if (len == sizeof(attr)) {
1282 *eol = T_OP_INVALID;
1283 librad_log("Attribute name is too long");
1288 * We may have Foo-Bar:= stuff, so back up.
1290 if (attr[len - 1] == ':') {
1298 /* Now we should have an operator here. */
1299 token = gettoken(ptr, buf, sizeof(buf));
1300 if (token < T_EQSTART || token > T_EQEND) {
1301 librad_log("expecting operator");
1305 /* Read value. Note that empty string values are allowed */
1306 xlat = gettoken(ptr, value, sizeof(value));
1307 if (xlat == T_EOL) {
1308 librad_log("failed to get value");
1313 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1316 t = gettoken(&p, buf, sizeof(buf));
1317 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1318 librad_log("Expected end of line or comma");
1330 * Make the full pair now.
1333 vp = pairmake(attr, value, token);
1339 case T_DOUBLE_QUOTED_STRING:
1340 p = strchr(value, '%');
1341 if (p && (p[1] == '{')) {
1342 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1343 librad_log("Value too long");
1346 vp = pairmake(attr, NULL, token);
1348 *eol = T_OP_INVALID;
1352 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1353 vp->flags.do_xlat = 1;
1356 vp = pairmake(attr, value, token);
1362 * Mark the pair to be allocated later.
1364 case T_BACK_QUOTED_STRING:
1365 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1366 librad_log("Value too long");
1370 vp = pairmake(attr, NULL, token);
1372 *eol = T_OP_INVALID;
1376 vp->flags.do_xlat = 1;
1377 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1383 * If we didn't make a pair, return an error.
1386 *eol = T_OP_INVALID;
1394 * Read one line of attribute/value pairs. This might contain
1395 * multiple pairs seperated by comma's.
1397 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1401 LRAD_TOKEN last_token = T_OP_INVALID;
1402 LRAD_TOKEN previous_token;
1405 * We allow an empty line.
1412 previous_token = last_token;
1413 if ((vp = pairread(&p, &last_token)) == NULL) {
1416 pairadd(first_pair, vp);
1417 } while (*p && (last_token == T_COMMA));
1420 * Don't tell the caller that there was a comment.
1422 if (last_token == T_HASH) {
1423 return previous_token;
1427 * And return the last token which we read.
1433 * Read valuepairs from the fp up to End-Of-File.
1435 * Hmm... this function is only used by radclient..
1437 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1440 LRAD_TOKEN last_token = T_EOL;
1447 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1449 * If we get a '\n' by itself, we assume that's
1450 * the end of that VP
1452 if ((buf[0] == '\n') && (list)) {
1455 if ((buf[0] == '\n') && (!list)) {
1460 * Comments get ignored
1462 if (buf[0] == '#') continue;
1465 * Read all of the attributes on the current line.
1468 last_token = userparse(buf, &vp);
1470 if (last_token != T_EOL) {
1471 librad_perror("%s", errprefix);
1482 if (error) pairfree(&list);
1486 return error ? NULL: list;
1492 * Compare two pairs, using the operator from "one".
1494 * i.e. given two attributes, it does:
1496 * (two->data) (one->operator) (one->data)
1498 * e.g. "foo" != "bar"
1500 * Returns true (comparison is true), or false (comparison is not true);
1502 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1506 switch (one->operator) {
1508 return (two != NULL);
1510 case T_OP_CMP_FALSE:
1511 return (two == NULL);
1514 * One is a regex, compile it, print two to a string,
1515 * and then do string comparisons.
1519 #ifndef HAVE_REGEX_H
1524 char buffer[MAX_STRING_LEN * 4 + 1];
1526 compare = regcomp(®, one->vp_strvalue,
1529 regerror(compare, ®, buffer, sizeof(buffer));
1530 librad_log("Illegal regular expression in attribute: %s: %s",
1535 vp_prints_value(buffer, sizeof(buffer), two, 0);
1538 * Don't care about substring matches,
1541 compare = regexec(®, buffer, 0, NULL, 0);
1544 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1545 return (compare != 0);
1549 default: /* we're OK */
1554 * After doing the previous check for special comparisons,
1555 * do the per-type comparison here.
1557 switch (one->type) {
1558 case PW_TYPE_ABINARY:
1559 case PW_TYPE_OCTETS:
1562 const uint8_t *p, *q;
1564 if (one->length < two->length) {
1565 length = one->length;
1567 length = two->length;
1573 compare = ((int) *p) - ((int) *q);
1574 if (compare != 0) goto type_switch;
1578 * Contents are the same. The return code
1579 * is therefore the difference in lengths.
1581 * i.e. "0x00" is smaller than "0x0000"
1583 compare = two->length - one->length;
1587 case PW_TYPE_STRING:
1588 if (one->flags.caseless) {
1589 compare = strcasecmp(two->vp_strvalue,
1592 compare = strcmp(two->vp_strvalue,
1597 case PW_TYPE_INTEGER:
1599 compare = two->lvalue - one->lvalue;
1602 case PW_TYPE_IPADDR:
1603 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1606 case PW_TYPE_IPV6ADDR:
1607 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1608 sizeof(two->vp_ipv6addr));
1611 case PW_TYPE_IPV6PREFIX:
1612 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1613 sizeof(two->vp_ipv6prefix));
1617 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1618 sizeof(two->vp_ifid));
1622 return 0; /* unknown type */
1626 * Now do the operator comparison.
1629 switch (one->operator) {
1631 return (compare == 0);
1634 return (compare != 0);
1637 return (compare < 0);
1640 return (compare > 0);
1643 return (compare <= 0);
1646 return (compare >= 0);