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, time_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 strNcpy(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 strNcpy((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 if (isdigit((int) value[0]) &&
806 (strspn(value, "0123456789") == strlen(value))) {
807 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
808 if (vp->lvalue > 255) {
809 librad_log("Byte value \"%s\" is larger than 255", value);
816 * Look for the named value for the given
819 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
820 librad_log("Unknown value %s for attribute %s",
824 vp->lvalue = dval->value;
831 * Note that ALL integers are unsigned!
833 if (isdigit((int) value[0]) &&
834 (strspn(value, "0123456789") == strlen(value))) {
835 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
836 if (vp->lvalue > 65535) {
837 librad_log("Byte value \"%s\" is larger than 65535", value);
844 * Look for the named value for the given
847 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
848 librad_log("Unknown value %s for attribute %s",
852 vp->lvalue = dval->value;
857 case PW_TYPE_INTEGER:
859 * Note that ALL integers are unsigned!
861 if (isdigit((int) value[0]) &&
862 (strspn(value, "0123456789") == strlen(value))) {
863 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
868 * Look for the named value for the given
871 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
872 librad_log("Unknown value %s for attribute %s",
876 vp->lvalue = dval->value;
882 if (gettime(value, (time_t *)&vp->lvalue) < 0) {
883 librad_log("failed to parse time string "
889 case PW_TYPE_ABINARY:
891 if (strncasecmp(value, "0x", 2) == 0) {
892 vp->type = PW_TYPE_OCTETS;
896 if (ascend_parse_filter(vp) < 0 ) {
897 librad_log("failed to parse Ascend binary attribute: %s",
904 * If Ascend binary is NOT defined,
905 * then fall through to raw octets, so that
906 * the user can at least make them by hand...
910 /* raw octets: 0x01020304... */
912 if (strncasecmp(value, "0x", 2) == 0) {
915 us = vp->vp_strvalue;
920 * There is only one character,
923 if ((strlen(cp) & 0x01) != 0) {
924 librad_log("Hex string is not an even length string.");
929 while (*cp && vp->length < MAX_STRING_LEN) {
932 if (sscanf(cp, "%02x", &tmp) != 1) {
933 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
946 if (ifid_aton(value, vp->vp_strvalue) == NULL) {
947 librad_log("failed to parse interface-id "
948 "string \"%s\"", value);
952 vp->vp_strvalue[vp->length] = '\0';
955 case PW_TYPE_IPV6ADDR:
956 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
957 librad_log("failed to parse IPv6 address "
958 "string \"%s\"", value);
961 vp->length = 16; /* length of IPv6 address */
962 vp->vp_strvalue[vp->length] = '\0';
967 case PW_TYPE_IPV6PREFIX:
968 p = strchr(value, '/');
969 if (!p || ((p - value) >= 256)) {
970 librad_log("invalid IPv6 prefix "
971 "string \"%s\"", value);
975 char buffer[256], *eptr;
977 memcpy(buffer, value, p - value);
978 buffer[p - value] = '\0';
980 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
981 librad_log("failed to parse IPv6 address "
982 "string \"%s\"", value);
986 prefix = strtoul(p + 1, &eptr, 10);
987 if ((prefix > 128) || *eptr) {
988 librad_log("failed to parse IPv6 address "
989 "string \"%s\"", value);
992 vp->vp_strvalue[1] = prefix;
994 vp->vp_strvalue[0] = '\0';
999 librad_log("unknown attribute type %d", vp->type);
1007 * Create a VALUE_PAIR from an ASCII attribute and value,
1008 * where the attribute name is in the form:
1013 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1021 * Unknown attributes MUST be of type 'octets'
1023 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1030 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1031 attr = atoi(attribute + 5);
1033 p += strspn(p, "0123456789");
1034 if (*p != 0) goto error;
1039 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1042 vendor = atoi(attribute + 7);
1043 if ((vendor == 0) || (vendor > 65535)) goto error;
1046 p += strspn(p, "0123456789");
1049 * Not Vendor-%d-Attr-%d
1051 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1056 p += strspn(p, "0123456789");
1057 if (*p != 0) goto error;
1059 if ((attr == 0) || (attr > 65535)) goto error;
1061 attr |= (vendor << 16);
1064 * VendorName-Attr-%d
1066 } else if (((p = strchr(attribute, '-')) != NULL) &&
1067 (strncasecmp(p, "-Attr-", 6) == 0)) {
1071 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1073 memcpy(buffer, attribute, p - attribute);
1074 buffer[p - attribute] = '\0';
1076 vendor = dict_vendorbyname(buffer);
1077 if (vendor == 0) goto error;
1082 p += strspn(p, "0123456789");
1083 if (*p != 0) goto error;
1085 if ((attr == 0) || (attr > 65535)) goto error;
1087 attr |= (vendor << 16);
1089 } else { /* very much unknown: die */
1091 librad_log("Unknown attribute \"%s\"", attribute);
1096 * We've now parsed the attribute properly, and verified
1097 * it to have value 'octets'. Let's create it.
1099 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1100 librad_log("out of memory");
1103 memset(vp, 0, sizeof(VALUE_PAIR));
1104 vp->type = PW_TYPE_OCTETS;
1107 * It may not be valid hex characters. If not, die.
1109 if (pairparsevalue(vp, value) == NULL) {
1114 if (VENDOR(attr) == 0) {
1115 sprintf(vp->name, "Attr-%u", attr);
1117 sprintf(vp->name, "Vendor-%u-Attr-%u",
1118 VENDOR(attr), attr & 0xffff);
1121 vp->attribute = attr;
1122 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1130 * Create a VALUE_PAIR from an ASCII attribute and value.
1132 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1145 * Check for tags in 'Attribute:Tag' format.
1150 ts = strrchr(attribute, ':');
1152 librad_log("Invalid tag for attribute %s", attribute);
1157 /* Colon found with something behind it */
1158 if (ts[1] == '*' && ts[2] == 0) {
1159 /* Wildcard tag for check items */
1162 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1163 /* It's not a wild card tag */
1164 tag = strtol(ts + 1, &tc, 0);
1165 if (tc && !*tc && TAG_VALID_ZERO(tag))
1169 librad_log("Invalid tag for attribute %s", attribute);
1176 * It's not found in the dictionary, so we use
1177 * another method to create the attribute.
1179 if ((da = dict_attrbyname(attribute)) == NULL) {
1180 return pairmake_any(attribute, value, operator);
1183 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1184 librad_log("out of memory");
1188 memset(vp, 0, sizeof(VALUE_PAIR));
1189 vp->attribute = da->attr;
1190 vp->type = da->type;
1191 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1192 strcpy(vp->name, da->name);
1193 vp->flags = da->flags;
1196 /* Check for a tag in the 'Merit' format of:
1197 * :Tag:Value. Print an error if we already found
1198 * a tag in the Attribute.
1201 if (value && (*value == ':' && da->flags.has_tag)) {
1202 /* If we already found a tag, this is invalid */
1205 librad_log("Duplicate tag %s for attribute %s",
1207 DEBUG("Duplicate tag %s for attribute %s\n",
1212 /* Colon found and attribute allows a tag */
1213 if (value[1] == '*' && value[2] == ':') {
1214 /* Wildcard tag for check items */
1219 tag = strtol(value + 1, &tc, 0);
1220 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1228 vp->flags.tag = tag;
1231 switch (vp->operator) {
1236 * For =* and !* operators, the value is irrelevant
1240 case T_OP_CMP_FALSE:
1241 vp->vp_strvalue[0] = '\0';
1247 * Regular expression comparison of integer attributes
1248 * does a STRING comparison of the names of their
1249 * integer attributes.
1251 case T_OP_REG_EQ: /* =~ */
1252 case T_OP_REG_NE: /* !~ */
1253 if (vp->type == PW_TYPE_INTEGER) {
1258 * Regular expression match with no regular
1259 * expression is wrong.
1266 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1270 regerror(res, &cre, msg, sizeof(msg));
1271 librad_log("Illegal regular expression in attribute: %s: %s",
1278 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1286 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1287 * then the user MAY have typed in the attribute name
1288 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1290 * We probably want to fix pairparsevalue to accept
1291 * octets as values for any attribute.
1293 if (value && (pairparsevalue(vp, value) == NULL)) {
1305 static const int valid_attr_name[256] = {
1306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1309 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1310 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1311 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1312 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1313 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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,
1319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1320 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1325 * Read a valuepair from a buffer, and advance pointer.
1326 * Sets *eol to T_EOL if end of line was encountered.
1328 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1334 LRAD_TOKEN token, t, xlat;
1338 *eol = T_OP_INVALID;
1341 while ((*p == ' ') || (*p == '\t')) p++;
1344 *eol = T_OP_INVALID;
1345 librad_log("No token read where we expected an attribute name");
1351 librad_log("Read a comment instead of a token");
1356 for (len = 0; len < sizeof(attr); len++) {
1357 if (valid_attr_name[(int)*p]) {
1364 if (len == sizeof(attr)) {
1365 *eol = T_OP_INVALID;
1366 librad_log("Attribute name is too long");
1371 * We may have Foo-Bar:= stuff, so back up.
1373 if (attr[len - 1] == ':') {
1381 /* Now we should have an operator here. */
1382 token = gettoken(ptr, buf, sizeof(buf));
1383 if (token < T_EQSTART || token > T_EQEND) {
1384 librad_log("expecting operator");
1388 /* Read value. Note that empty string values are allowed */
1389 xlat = gettoken(ptr, value, sizeof(value));
1390 if (xlat == T_EOL) {
1391 librad_log("failed to get value");
1396 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1399 t = gettoken(&p, buf, sizeof(buf));
1400 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1401 librad_log("Expected end of line or comma");
1413 * Make the full pair now.
1416 vp = pairmake(attr, value, token);
1422 case T_DOUBLE_QUOTED_STRING:
1423 p = strchr(value, '%');
1424 if (p && (p[1] == '{')) {
1425 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1426 librad_log("Value too long");
1429 vp = pairmake(attr, NULL, token);
1431 *eol = T_OP_INVALID;
1435 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1436 vp->flags.do_xlat = 1;
1439 vp = pairmake(attr, value, token);
1445 * Mark the pair to be allocated later.
1447 case T_BACK_QUOTED_STRING:
1448 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1449 librad_log("Value too long");
1453 vp = pairmake(attr, NULL, token);
1455 *eol = T_OP_INVALID;
1459 vp->flags.do_xlat = 1;
1460 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1466 * If we didn't make a pair, return an error.
1469 *eol = T_OP_INVALID;
1477 * Read one line of attribute/value pairs. This might contain
1478 * multiple pairs seperated by comma's.
1480 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1484 LRAD_TOKEN last_token = T_OP_INVALID;
1485 LRAD_TOKEN previous_token;
1488 * We allow an empty line.
1495 previous_token = last_token;
1496 if ((vp = pairread(&p, &last_token)) == NULL) {
1499 pairadd(first_pair, vp);
1500 } while (*p && (last_token == T_COMMA));
1503 * Don't tell the caller that there was a comment.
1505 if (last_token == T_HASH) {
1506 return previous_token;
1510 * And return the last token which we read.
1516 * Read valuepairs from the fp up to End-Of-File.
1518 * Hmm... this function is only used by radclient..
1520 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1523 LRAD_TOKEN last_token = T_EOL;
1530 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1532 * If we get a '\n' by itself, we assume that's
1533 * the end of that VP
1535 if ((buf[0] == '\n') && (list)) {
1538 if ((buf[0] == '\n') && (!list)) {
1543 * Comments get ignored
1545 if (buf[0] == '#') continue;
1548 * Read all of the attributes on the current line.
1551 last_token = userparse(buf, &vp);
1553 if (last_token != T_EOL) {
1554 librad_perror("%s", errprefix);
1565 if (error) pairfree(&list);
1569 return error ? NULL: list;
1575 * Compare two pairs, using the operator from "one".
1577 * i.e. given two attributes, it does:
1579 * (two->data) (one->operator) (one->data)
1581 * e.g. "foo" != "bar"
1583 * Returns true (comparison is true), or false (comparison is not true);
1585 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1589 switch (one->operator) {
1591 return (two != NULL);
1593 case T_OP_CMP_FALSE:
1594 return (two == NULL);
1597 * One is a regex, compile it, print two to a string,
1598 * and then do string comparisons.
1602 #ifndef HAVE_REGEX_H
1607 char buffer[MAX_STRING_LEN * 4 + 1];
1609 compare = regcomp(®, one->vp_strvalue,
1612 regerror(compare, ®, buffer, sizeof(buffer));
1613 librad_log("Illegal regular expression in attribute: %s: %s",
1618 vp_prints_value(buffer, sizeof(buffer), two, 0);
1621 * Don't care about substring matches,
1624 compare = regexec(®, buffer, 0, NULL, 0);
1627 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1628 return (compare != 0);
1632 default: /* we're OK */
1637 * After doing the previous check for special comparisons,
1638 * do the per-type comparison here.
1640 switch (one->type) {
1641 case PW_TYPE_ABINARY:
1642 case PW_TYPE_OCTETS:
1645 const uint8_t *p, *q;
1647 if (one->length < two->length) {
1648 length = one->length;
1650 length = two->length;
1656 compare = ((int) *p) - ((int) *q);
1657 if (compare != 0) goto type_switch;
1661 * Contents are the same. The return code
1662 * is therefore the difference in lengths.
1664 * i.e. "0x00" is smaller than "0x0000"
1666 compare = two->length - one->length;
1670 case PW_TYPE_STRING:
1671 if (one->flags.caseless) {
1672 compare = strcasecmp(two->vp_strvalue,
1675 compare = strcmp(two->vp_strvalue,
1682 case PW_TYPE_INTEGER:
1684 compare = two->lvalue - one->lvalue;
1687 case PW_TYPE_IPADDR:
1688 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1691 case PW_TYPE_IPV6ADDR:
1692 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1693 sizeof(two->vp_ipv6addr));
1696 case PW_TYPE_IPV6PREFIX:
1697 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1698 sizeof(two->vp_ipv6prefix));
1702 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1703 sizeof(two->vp_ifid));
1707 return 0; /* unknown type */
1711 * Now do the operator comparison.
1714 switch (one->operator) {
1716 return (compare == 0);
1719 return (compare != 0);
1722 return (compare < 0);
1725 return (compare > 0);
1728 return (compare <= 0);
1731 return (compare >= 0);