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/autoconf.h>
28 #include <sys/types.h>
43 #include <freeradius-devel/missing.h>
44 #include <freeradius-devel/libradius.h>
46 static const char *months[] = {
47 "jan", "feb", "mar", "apr", "may", "jun",
48 "jul", "aug", "sep", "oct", "nov", "dec" };
52 * Create a new valuepair.
54 VALUE_PAIR *paircreate(int attr, int type)
59 if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
60 librad_log("out of memory");
63 memset(vp, 0, sizeof(VALUE_PAIR));
65 vp->operator = T_OP_EQ;
69 * Dictionary type over-rides what the caller says.
71 if ((da = dict_attrbyvalue(attr)) != NULL) {
72 strcpy(vp->name, da->name);
74 vp->flags = da->flags;
75 } else if (VENDOR(attr) == 0) {
76 sprintf(vp->name, "Attr-%u", attr);
80 v = dict_vendorbyvalue(VENDOR(attr));
82 sprintf(vp->name, "%s-Attr-%u",
83 v->name, attr & 0xffff);
85 sprintf(vp->name, "Vendor-%u-Attr-%u",
86 VENDOR(attr), attr & 0xffff);
105 vp->length = sizeof(vp->vp_ifid);
108 case PW_TYPE_IPV6ADDR:
109 vp->length = sizeof(vp->vp_ipv6addr);
112 case PW_TYPE_IPV6PREFIX:
113 vp->length = sizeof(vp->vp_ipv6prefix);
125 * release the memory used by a single attribute-value pair
126 * just a wrapper around free() for now.
128 void pairbasicfree(VALUE_PAIR *pair)
130 /* clear the memory here */
131 memset(pair, 0, sizeof(*pair));
136 * Release the memory used by a list of attribute-value
137 * pairs, and sets the pair pointer to NULL.
139 void pairfree(VALUE_PAIR **pair_ptr)
141 VALUE_PAIR *next, *pair;
143 if (!pair_ptr) return;
146 while (pair != NULL) {
157 * Find the pair with the matching attribute
159 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
161 while(first && first->attribute != attr)
168 * Delete the pair(s) with the matching attribute
170 void pairdelete(VALUE_PAIR **first, int attr)
172 VALUE_PAIR *i, *next;
173 VALUE_PAIR **last = first;
175 for(i = *first; i; i = next) {
177 if (i->attribute == attr) {
187 * Add a pair at the end of a VALUE_PAIR list.
189 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
195 if (*first == NULL) {
199 for(i = *first; i->next; i = i->next)
205 * Add or replace a pair at the end of a VALUE_PAIR list.
207 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
209 VALUE_PAIR *i, *next;
210 VALUE_PAIR **prev = first;
212 if (*first == NULL) {
218 * Not an empty list, so find item if it is there, and
219 * replace it. Note, we always replace the first one, and
220 * we ignore any others that might exist.
222 for(i = *first; i; i = next) {
226 * Found the first attribute, replace it,
229 if (i->attribute == replace->attribute) {
233 * Should really assert that replace->next == NULL
235 replace->next = next;
241 * Point to where the attribute should go.
247 * If we got here, we didn't find anything to replace, so
248 * stopped at the last item, which we just append to.
254 * Copy just a certain type of pairs.
256 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
258 VALUE_PAIR *first, *n, **last;
264 if (attr >= 0 && vp->attribute != attr) {
268 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
269 librad_log("out of memory");
272 memcpy(n, vp, sizeof(VALUE_PAIR));
285 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
287 return paircopy2(vp, -1);
292 * Move attributes from one list to the other
293 * if not already present.
295 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
297 VALUE_PAIR **tailto, *i, *j, *next;
298 VALUE_PAIR *tailfrom = NULL;
300 int has_password = 0;
303 * First, see if there are any passwords here, and
304 * point "tailto" to the end of the "to" list.
307 for(i = *to; i; i = i->next) {
308 if (i->attribute == PW_USER_PASSWORD ||
309 i->attribute == PW_CRYPT_PASSWORD)
315 * Loop over the "from" list.
317 for(i = *from; i; i = next) {
321 * If there was a password in the "to" list,
322 * do not move any other password from the
323 * "from" to the "to" list.
326 (i->attribute == PW_USER_PASSWORD ||
327 i->attribute == PW_CRYPT_PASSWORD)) {
332 switch (i->operator) {
334 * These are COMPARISON attributes
335 * from a check list, and are not
336 * supposed to be copied!
354 * If the attribute is already present in "to",
355 * do not move it from "from" to "to". We make
356 * an exception for "Hint" which can appear multiple
357 * times, and we never move "Fall-Through".
359 if (i->attribute == PW_FALL_THROUGH ||
360 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
362 found = pairfind(*to, i->attribute);
363 switch (i->operator) {
366 * If matching attributes are found,
369 case T_OP_SUB: /* -= */
371 if (!i->vp_strvalue[0] ||
372 (strcmp((char *)found->vp_strvalue,
373 (char *)i->vp_strvalue) == 0)){
374 pairdelete(to, found->attribute);
377 * 'tailto' may have been
381 for(j = *to; j; j = j->next) {
390 /* really HAVE_REGEX_H */
393 * Attr-Name =~ "s/find/replace/"
395 * Very bad code. Barely working,
401 (i->vp_strvalue[0] == 's')) {
408 p = i->vp_strvalue + 1;
409 q = strchr(p + 1, *p);
410 if (!q || (q[strlen(q) - 1] != *p)) {
414 str = strdup(i->vp_strvalue + 2);
417 q[strlen(q) - 1] = '\0';
419 regcomp(®, str, 0);
420 if (regexec(®, found->vp_strvalue,
422 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
423 found->vp_strvalue, match[0].rm_so,
430 tailfrom = i; /* don't copy it over */
434 case T_OP_EQ: /* = */
436 * FIXME: Tunnel attributes with
437 * different tags are different
442 continue; /* with the loop */
447 * If a similar attribute is found,
448 * replace it with the new one. Otherwise,
449 * add the new one to the list.
451 case T_OP_SET: /* := */
453 VALUE_PAIR *mynext = found->next;
456 * Do NOT call pairdelete()
457 * here, due to issues with
458 * re-writing "request->username".
460 * Everybody calls pairmove,
461 * and expects it to work.
462 * We can't update request->username
463 * here, so instead we over-write
464 * the vp that it's pointing to.
466 memcpy(found, i, sizeof(*found));
467 found->next = mynext;
469 pairdelete(&found->next, found->attribute);
472 * 'tailto' may have been
475 for(j = found; j; j = j->next) {
483 * Add the new element to the list, even
484 * if similar ones already exist.
487 case T_OP_ADD: /* += */
492 tailfrom->next = next;
497 * If ALL of the 'to' attributes have been deleted,
498 * then ensure that the 'tail' is updated to point
513 * Move one kind of attributes from one list to the other
515 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
517 VALUE_PAIR *to_tail, *i, *next;
518 VALUE_PAIR *iprev = NULL;
521 * Find the last pair in the "to" list and put it in "to_tail".
525 for(i = *to; i; i = i->next)
530 for(i = *from; i; i = next) {
535 * If the attribute to move is NOT a VSA, then it
536 * ignores any attributes which do not match exactly.
538 if ((attr != PW_VENDOR_SPECIFIC) &&
539 (i->attribute != attr)) {
545 * If the attribute to move IS a VSA, then it ignores
546 * any non-VSA attribute.
548 if ((attr == PW_VENDOR_SPECIFIC) &&
549 (VENDOR(i->attribute) == 0)) {
555 * Remove the attribute from the "from" list.
563 * Add the attribute to the "to" list.
576 * Sort of strtok/strsep function.
578 static char *mystrtok(char **ptr, const char *sep)
584 while (**ptr && strchr(sep, **ptr))
589 while (**ptr && strchr(sep, **ptr) == NULL)
597 * Turn printable string into time_t
598 * Returns -1 on error, 0 on OK.
600 static int gettime(const char *valstr, uint32_t *lvalue)
611 * Test for unix timestamp date
613 *lvalue = strtoul(valstr, &tail, 10);
619 memset(tm, 0, sizeof(*tm));
620 tm->tm_isdst = -1; /* don't know, and don't care about DST */
622 strlcpy(buf, valstr, sizeof(buf));
625 f[0] = mystrtok(&p, " \t");
626 f[1] = mystrtok(&p, " \t");
627 f[2] = mystrtok(&p, " \t");
628 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
629 if (!f[0] || !f[1] || !f[2]) return -1;
632 * The time has a colon, where nothing else does.
633 * So if we find it, bubble it to the back of the list.
636 for (i = 0; i < 3; i++) {
637 if (strchr(f[i], ':')) {
647 * The month is text, which allows us to find it easily.
650 for (i = 0; i < 3; i++) {
651 if (isalpha( (int) *f[i])) {
653 * Bubble the month to the front of the list
659 for (i = 0; i < 12; i++) {
660 if (strncasecmp(months[i], f[0], 3) == 0) {
668 /* month not found? */
669 if (tm->tm_mon == 12) return -1;
672 * The year may be in f[1], or in f[2]
674 tm->tm_year = atoi(f[1]);
675 tm->tm_mday = atoi(f[2]);
677 if (tm->tm_year >= 1900) {
682 * We can't use 2-digit years any more, they make it
683 * impossible to tell what's the day, and what's the year.
685 if (tm->tm_mday < 1900) return -1;
688 * Swap the year and the day.
691 tm->tm_year = tm->tm_mday - 1900;
696 * If the day is out of range, die.
698 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
703 * There may be %H:%M:%S. Parse it in a hacky way.
706 f[0] = f[3]; /* HH */
707 f[1] = strchr(f[0], ':'); /* find : separator */
708 if (!f[1]) return -1;
710 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
712 f[2] = strchr(f[1], ':'); /* find : separator */
714 *(f[2]++) = '\0'; /* nuke it, and point to SS */
716 strcpy(f[2], "0"); /* assignment would discard const */
719 tm->tm_hour = atoi(f[0]);
720 tm->tm_min = atoi(f[1]);
721 tm->tm_sec = atoi(f[2]);
725 * Returns -1 on error.
728 if (t == (time_t) -1) return -1;
737 * Parse a string value into a given VALUE_PAIR
739 * FIXME: we probably want to fix this function to accept
740 * octets as values for any type of attribute. We should then
741 * double-check the parsed value, to be sure it's legal for that
742 * type (length, etc.)
744 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
751 * Even for integers, dates and ip addresses we
752 * keep the original string in vp->vp_strvalue.
754 strlcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
755 vp->length = strlen(vp->vp_strvalue);
760 * Already handled above.
766 * It's a comparison, not a real IP.
768 if ((vp->operator == T_OP_REG_EQ) ||
769 (vp->operator == T_OP_REG_NE)) {
774 * FIXME: complain if hostname
775 * cannot be resolved, or resolve later!
777 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
778 cs = s = strdup(value);
781 vp->flags.addport = 1;
788 lrad_ipaddr_t ipaddr;
790 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
791 librad_log("Failed to find IP address for %s", cs);
795 vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
803 * Note that ALL integers are unsigned!
805 vp->lvalue = (uint32_t) strtoul(value, &p, 10);
807 if (vp->lvalue > 255) {
808 librad_log("Byte value \"%s\" is larger than 255", value);
816 * Look for the named value for the given
819 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
820 librad_log("Unknown value %s for attribute %s",
824 vp->lvalue = dval->value;
830 * Note that ALL integers are unsigned!
832 vp->lvalue = (uint32_t) strtoul(value, &p, 10);
834 if (vp->lvalue > 65535) {
835 librad_log("Byte value \"%s\" is larger than 65535", value);
843 * Look for the named value for the given
846 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
847 librad_log("Unknown value %s for attribute %s",
851 vp->lvalue = dval->value;
855 case PW_TYPE_INTEGER:
857 * Note that ALL integers are unsigned!
859 vp->lvalue = (uint32_t) strtoul(value, &p, 10);
866 * Look for the named value for the given
869 if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
870 librad_log("Unknown value %s for attribute %s",
874 vp->lvalue = dval->value;
879 if (gettime(value, &vp->lvalue) < 0) {
880 librad_log("failed to parse time string "
886 case PW_TYPE_ABINARY:
888 if (strncasecmp(value, "0x", 2) == 0) {
889 vp->type = PW_TYPE_OCTETS;
893 if (ascend_parse_filter(vp) < 0 ) {
894 librad_log("failed to parse Ascend binary attribute: %s",
901 * If Ascend binary is NOT defined,
902 * then fall through to raw octets, so that
903 * the user can at least make them by hand...
907 /* raw octets: 0x01020304... */
909 if (strncasecmp(value, "0x", 2) == 0) {
917 * There is only one character,
920 if ((strlen(cp) & 0x01) != 0) {
921 librad_log("Hex string is not an even length string.");
927 (vp->length < MAX_STRING_LEN)) {
930 if (sscanf(cp, "%02x", &tmp) != 1) {
931 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
943 if (ifid_aton(value, (unsigned char *) vp->vp_strvalue) == NULL) {
944 librad_log("failed to parse interface-id "
945 "string \"%s\"", value);
949 vp->vp_strvalue[vp->length] = '\0';
952 case PW_TYPE_IPV6ADDR:
953 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
954 librad_log("failed to parse IPv6 address "
955 "string \"%s\"", value);
958 vp->length = 16; /* length of IPv6 address */
959 vp->vp_strvalue[vp->length] = '\0';
964 case PW_TYPE_IPV6PREFIX:
965 p = strchr(value, '/');
966 if (!p || ((p - value) >= 256)) {
967 librad_log("invalid IPv6 prefix "
968 "string \"%s\"", value);
972 char buffer[256], *eptr;
974 memcpy(buffer, value, p - value);
975 buffer[p - value] = '\0';
977 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
978 librad_log("failed to parse IPv6 address "
979 "string \"%s\"", value);
983 prefix = strtoul(p + 1, &eptr, 10);
984 if ((prefix > 128) || *eptr) {
985 librad_log("failed to parse IPv6 address "
986 "string \"%s\"", value);
989 vp->vp_strvalue[1] = prefix;
991 vp->vp_strvalue[0] = '\0';
996 librad_log("unknown attribute type %d", vp->type);
1004 * Create a VALUE_PAIR from an ASCII attribute and value,
1005 * where the attribute name is in the form:
1010 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1018 * Unknown attributes MUST be of type 'octets'
1020 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1027 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1028 attr = atoi(attribute + 5);
1030 p += strspn(p, "0123456789");
1031 if (*p != 0) goto error;
1036 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1039 vendor = atoi(attribute + 7);
1040 if ((vendor == 0) || (vendor > 65535)) goto error;
1043 p += strspn(p, "0123456789");
1046 * Not Vendor-%d-Attr-%d
1048 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1053 p += strspn(p, "0123456789");
1054 if (*p != 0) goto error;
1056 if ((attr == 0) || (attr > 65535)) goto error;
1058 attr |= (vendor << 16);
1061 * VendorName-Attr-%d
1063 } else if (((p = strchr(attribute, '-')) != NULL) &&
1064 (strncasecmp(p, "-Attr-", 6) == 0)) {
1068 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1070 memcpy(buffer, attribute, p - attribute);
1071 buffer[p - attribute] = '\0';
1073 vendor = dict_vendorbyname(buffer);
1074 if (vendor == 0) goto error;
1079 p += strspn(p, "0123456789");
1080 if (*p != 0) goto error;
1082 if ((attr == 0) || (attr > 65535)) goto error;
1084 attr |= (vendor << 16);
1086 } else { /* very much unknown: die */
1088 librad_log("Unknown attribute \"%s\"", attribute);
1093 * We've now parsed the attribute properly, and verified
1094 * it to have value 'octets'. Let's create it.
1096 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1097 librad_log("out of memory");
1100 memset(vp, 0, sizeof(VALUE_PAIR));
1101 vp->type = PW_TYPE_OCTETS;
1104 * It may not be valid hex characters. If not, die.
1106 if (pairparsevalue(vp, value) == NULL) {
1111 if (VENDOR(attr) == 0) {
1112 sprintf(vp->name, "Attr-%u", attr);
1114 sprintf(vp->name, "Vendor-%u-Attr-%u",
1115 VENDOR(attr), attr & 0xffff);
1118 vp->attribute = attr;
1119 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1127 * Create a VALUE_PAIR from an ASCII attribute and value.
1129 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1142 * Check for tags in 'Attribute:Tag' format.
1147 ts = strrchr(attribute, ':');
1149 librad_log("Invalid tag for attribute %s", attribute);
1154 /* Colon found with something behind it */
1155 if (ts[1] == '*' && ts[2] == 0) {
1156 /* Wildcard tag for check items */
1159 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1160 /* It's not a wild card tag */
1161 tag = strtol(ts + 1, &tc, 0);
1162 if (tc && !*tc && TAG_VALID_ZERO(tag))
1166 librad_log("Invalid tag for attribute %s", attribute);
1173 * It's not found in the dictionary, so we use
1174 * another method to create the attribute.
1176 if ((da = dict_attrbyname(attribute)) == NULL) {
1177 return pairmake_any(attribute, value, operator);
1180 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1181 librad_log("out of memory");
1185 memset(vp, 0, sizeof(VALUE_PAIR));
1186 vp->attribute = da->attr;
1187 vp->type = da->type;
1188 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1189 strcpy(vp->name, da->name);
1190 vp->flags = da->flags;
1193 /* Check for a tag in the 'Merit' format of:
1194 * :Tag:Value. Print an error if we already found
1195 * a tag in the Attribute.
1198 if (value && (*value == ':' && da->flags.has_tag)) {
1199 /* If we already found a tag, this is invalid */
1202 librad_log("Duplicate tag %s for attribute %s",
1204 DEBUG("Duplicate tag %s for attribute %s\n",
1209 /* Colon found and attribute allows a tag */
1210 if (value[1] == '*' && value[2] == ':') {
1211 /* Wildcard tag for check items */
1216 tag = strtol(value + 1, &tc, 0);
1217 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1225 vp->flags.tag = tag;
1228 switch (vp->operator) {
1233 * For =* and !* operators, the value is irrelevant
1237 case T_OP_CMP_FALSE:
1238 vp->vp_strvalue[0] = '\0';
1244 * Regular expression comparison of integer attributes
1245 * does a STRING comparison of the names of their
1246 * integer attributes.
1248 case T_OP_REG_EQ: /* =~ */
1249 case T_OP_REG_NE: /* !~ */
1250 if (vp->type == PW_TYPE_INTEGER) {
1255 * Regular expression match with no regular
1256 * expression is wrong.
1263 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1267 regerror(res, &cre, msg, sizeof(msg));
1268 librad_log("Illegal regular expression in attribute: %s: %s",
1275 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1283 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1284 * then the user MAY have typed in the attribute name
1285 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1287 * We probably want to fix pairparsevalue to accept
1288 * octets as values for any attribute.
1290 if (value && (pairparsevalue(vp, value) == NULL)) {
1302 static const int valid_attr_name[256] = {
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, 1, 0, 0,
1306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1307 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1308 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1309 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1310 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1313 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1315 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1316 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1322 * Read a valuepair from a buffer, and advance pointer.
1323 * Sets *eol to T_EOL if end of line was encountered.
1325 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1331 LRAD_TOKEN token, t, xlat;
1335 *eol = T_OP_INVALID;
1338 while ((*p == ' ') || (*p == '\t')) p++;
1341 *eol = T_OP_INVALID;
1342 librad_log("No token read where we expected an attribute name");
1348 librad_log("Read a comment instead of a token");
1353 for (len = 0; len < sizeof(attr); len++) {
1354 if (valid_attr_name[(int)*p]) {
1361 if (len == sizeof(attr)) {
1362 *eol = T_OP_INVALID;
1363 librad_log("Attribute name is too long");
1368 * We may have Foo-Bar:= stuff, so back up.
1370 if (attr[len - 1] == ':') {
1378 /* Now we should have an operator here. */
1379 token = gettoken(ptr, buf, sizeof(buf));
1380 if (token < T_EQSTART || token > T_EQEND) {
1381 librad_log("expecting operator");
1385 /* Read value. Note that empty string values are allowed */
1386 xlat = gettoken(ptr, value, sizeof(value));
1387 if (xlat == T_EOL) {
1388 librad_log("failed to get value");
1393 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1396 t = gettoken(&p, buf, sizeof(buf));
1397 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1398 librad_log("Expected end of line or comma");
1410 * Make the full pair now.
1413 vp = pairmake(attr, value, token);
1419 case T_DOUBLE_QUOTED_STRING:
1420 p = strchr(value, '%');
1421 if (p && (p[1] == '{')) {
1422 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1423 librad_log("Value too long");
1426 vp = pairmake(attr, NULL, token);
1428 *eol = T_OP_INVALID;
1432 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1433 vp->flags.do_xlat = 1;
1436 vp = pairmake(attr, value, token);
1442 * Mark the pair to be allocated later.
1444 case T_BACK_QUOTED_STRING:
1445 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1446 librad_log("Value too long");
1450 vp = pairmake(attr, NULL, token);
1452 *eol = T_OP_INVALID;
1456 vp->flags.do_xlat = 1;
1457 strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1463 * If we didn't make a pair, return an error.
1466 *eol = T_OP_INVALID;
1474 * Read one line of attribute/value pairs. This might contain
1475 * multiple pairs seperated by comma's.
1477 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1481 LRAD_TOKEN last_token = T_OP_INVALID;
1482 LRAD_TOKEN previous_token;
1485 * We allow an empty line.
1492 previous_token = last_token;
1493 if ((vp = pairread(&p, &last_token)) == NULL) {
1496 pairadd(first_pair, vp);
1497 } while (*p && (last_token == T_COMMA));
1500 * Don't tell the caller that there was a comment.
1502 if (last_token == T_HASH) {
1503 return previous_token;
1507 * And return the last token which we read.
1513 * Read valuepairs from the fp up to End-Of-File.
1515 * Hmm... this function is only used by radclient..
1517 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1520 LRAD_TOKEN last_token = T_EOL;
1527 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1529 * If we get a '\n' by itself, we assume that's
1530 * the end of that VP
1532 if ((buf[0] == '\n') && (list)) {
1535 if ((buf[0] == '\n') && (!list)) {
1540 * Comments get ignored
1542 if (buf[0] == '#') continue;
1545 * Read all of the attributes on the current line.
1548 last_token = userparse(buf, &vp);
1550 if (last_token != T_EOL) {
1551 librad_perror("%s", errprefix);
1562 if (error) pairfree(&list);
1566 return error ? NULL: list;
1572 * Compare two pairs, using the operator from "one".
1574 * i.e. given two attributes, it does:
1576 * (two->data) (one->operator) (one->data)
1578 * e.g. "foo" != "bar"
1580 * Returns true (comparison is true), or false (comparison is not true);
1582 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1586 switch (one->operator) {
1588 return (two != NULL);
1590 case T_OP_CMP_FALSE:
1591 return (two == NULL);
1594 * One is a regex, compile it, print two to a string,
1595 * and then do string comparisons.
1599 #ifndef HAVE_REGEX_H
1604 char buffer[MAX_STRING_LEN * 4 + 1];
1606 compare = regcomp(®, one->vp_strvalue,
1609 regerror(compare, ®, buffer, sizeof(buffer));
1610 librad_log("Illegal regular expression in attribute: %s: %s",
1615 vp_prints_value(buffer, sizeof(buffer), two, 0);
1618 * Don't care about substring matches,
1621 compare = regexec(®, buffer, 0, NULL, 0);
1624 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1625 return (compare != 0);
1629 default: /* we're OK */
1634 * After doing the previous check for special comparisons,
1635 * do the per-type comparison here.
1637 switch (one->type) {
1638 case PW_TYPE_ABINARY:
1639 case PW_TYPE_OCTETS:
1642 const uint8_t *p, *q;
1644 if (one->length < two->length) {
1645 length = one->length;
1647 length = two->length;
1653 compare = ((int) *p) - ((int) *q);
1654 if (compare != 0) goto type_switch;
1658 * Contents are the same. The return code
1659 * is therefore the difference in lengths.
1661 * i.e. "0x00" is smaller than "0x0000"
1663 compare = two->length - one->length;
1667 case PW_TYPE_STRING:
1668 if (one->flags.caseless) {
1669 compare = strcasecmp(two->vp_strvalue,
1672 compare = strcmp(two->vp_strvalue,
1679 case PW_TYPE_INTEGER:
1681 compare = two->lvalue - one->lvalue;
1684 case PW_TYPE_IPADDR:
1685 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1688 case PW_TYPE_IPV6ADDR:
1689 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1690 sizeof(two->vp_ipv6addr));
1693 case PW_TYPE_IPV6PREFIX:
1694 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1695 sizeof(two->vp_ipv6prefix));
1699 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1700 sizeof(two->vp_ifid));
1704 return 0; /* unknown type */
1708 * Now do the operator comparison.
1711 switch (one->operator) {
1713 return (compare == 0);
1716 return (compare != 0);
1719 return (compare < 0);
1722 return (compare > 0);
1725 return (compare <= 0);
1728 return (compare >= 0);