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);
104 vp->length = sizeof(vp->vp_ifid);
107 case PW_TYPE_IPV6ADDR:
108 vp->length = sizeof(vp->vp_ipv6addr);
111 case PW_TYPE_IPV6PREFIX:
112 vp->length = sizeof(vp->vp_ipv6prefix);
124 * release the memory used by a single attribute-value pair
125 * just a wrapper around free() for now.
127 void pairbasicfree(VALUE_PAIR *pair)
129 /* clear the memory here */
130 memset(pair, 0, sizeof(*pair));
135 * Release the memory used by a list of attribute-value
136 * pairs, and sets the pair pointer to NULL.
138 void pairfree(VALUE_PAIR **pair_ptr)
140 VALUE_PAIR *next, *pair;
142 if (!pair_ptr) return;
145 while (pair != NULL) {
156 * Find the pair with the matching attribute
158 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
160 while(first && first->attribute != attr)
167 * Delete the pair(s) with the matching attribute
169 void pairdelete(VALUE_PAIR **first, int attr)
171 VALUE_PAIR *i, *next;
172 VALUE_PAIR **last = first;
174 for(i = *first; i; i = next) {
176 if (i->attribute == attr) {
186 * Add a pair at the end of a VALUE_PAIR list.
188 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
194 if (*first == NULL) {
198 for(i = *first; i->next; i = i->next)
204 * Add or replace a pair at the end of a VALUE_PAIR list.
206 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
208 VALUE_PAIR *i, *next;
209 VALUE_PAIR **prev = first;
211 if (*first == NULL) {
217 * Not an empty list, so find item if it is there, and
218 * replace it. Note, we always replace the first one, and
219 * we ignore any others that might exist.
221 for(i = *first; i; i = next) {
225 * Found the first attribute, replace it,
228 if (i->attribute == replace->attribute) {
232 * Should really assert that replace->next == NULL
234 replace->next = next;
240 * Point to where the attribute should go.
246 * If we got here, we didn't find anything to replace, so
247 * stopped at the last item, which we just append to.
253 * Copy just a certain type of pairs.
255 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
257 VALUE_PAIR *first, *n, **last;
263 if (attr >= 0 && vp->attribute != attr) {
267 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
268 librad_log("out of memory");
271 memcpy(n, vp, sizeof(VALUE_PAIR));
284 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
286 return paircopy2(vp, -1);
291 * Move attributes from one list to the other
292 * if not already present.
294 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
296 VALUE_PAIR **tailto, *i, *j, *next;
297 VALUE_PAIR *tailfrom = NULL;
299 int has_password = 0;
302 * First, see if there are any passwords here, and
303 * point "tailto" to the end of the "to" list.
306 for(i = *to; i; i = i->next) {
307 if (i->attribute == PW_USER_PASSWORD ||
308 i->attribute == PW_CRYPT_PASSWORD)
314 * Loop over the "from" list.
316 for(i = *from; i; i = next) {
320 * If there was a password in the "to" list,
321 * do not move any other password from the
322 * "from" to the "to" list.
325 (i->attribute == PW_USER_PASSWORD ||
326 i->attribute == PW_CRYPT_PASSWORD)) {
331 switch (i->operator) {
333 * These are COMPARISON attributes
334 * from a check list, and are not
335 * supposed to be copied!
353 * If the attribute is already present in "to",
354 * do not move it from "from" to "to". We make
355 * an exception for "Hint" which can appear multiple
356 * times, and we never move "Fall-Through".
358 if (i->attribute == PW_FALL_THROUGH ||
359 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
361 found = pairfind(*to, i->attribute);
362 switch (i->operator) {
365 * If matching attributes are found,
368 case T_OP_SUB: /* -= */
370 if (!i->vp_strvalue[0] ||
371 (strcmp((char *)found->vp_strvalue,
372 (char *)i->vp_strvalue) == 0)){
373 pairdelete(to, found->attribute);
376 * 'tailto' may have been
380 for(j = *to; j; j = j->next) {
389 /* really HAVE_REGEX_H */
392 * Attr-Name =~ "s/find/replace/"
394 * Very bad code. Barely working,
400 (i->vp_strvalue[0] == 's')) {
407 p = i->vp_strvalue + 1;
408 q = strchr(p + 1, *p);
409 if (!q || (q[strlen(q) - 1] != *p)) {
413 str = strdup(i->vp_strvalue + 2);
416 q[strlen(q) - 1] = '\0';
418 regcomp(®, str, 0);
419 if (regexec(®, found->vp_strvalue,
421 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
422 found->vp_strvalue, match[0].rm_so,
429 tailfrom = i; /* don't copy it over */
433 case T_OP_EQ: /* = */
435 * FIXME: Tunnel attributes with
436 * different tags are different
441 continue; /* with the loop */
446 * If a similar attribute is found,
447 * replace it with the new one. Otherwise,
448 * add the new one to the list.
450 case T_OP_SET: /* := */
452 VALUE_PAIR *mynext = found->next;
455 * Do NOT call pairdelete()
456 * here, due to issues with
457 * re-writing "request->username".
459 * Everybody calls pairmove,
460 * and expects it to work.
461 * We can't update request->username
462 * here, so instead we over-write
463 * the vp that it's pointing to.
465 memcpy(found, i, sizeof(*found));
466 found->next = mynext;
468 pairdelete(&found->next, found->attribute);
471 * 'tailto' may have been
474 for(j = found; j; j = j->next) {
482 * Add the new element to the list, even
483 * if similar ones already exist.
486 case T_OP_ADD: /* += */
491 tailfrom->next = next;
496 * If ALL of the 'to' attributes have been deleted,
497 * then ensure that the 'tail' is updated to point
512 * Move one kind of attributes from one list to the other
514 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
516 VALUE_PAIR *to_tail, *i, *next;
517 VALUE_PAIR *iprev = NULL;
520 * Find the last pair in the "to" list and put it in "to_tail".
524 for(i = *to; i; i = i->next)
529 for(i = *from; i; i = next) {
534 * If the attribute to move is NOT a VSA, then it
535 * ignores any attributes which do not match exactly.
537 if ((attr != PW_VENDOR_SPECIFIC) &&
538 (i->attribute != attr)) {
544 * If the attribute to move IS a VSA, then it ignores
545 * any non-VSA attribute.
547 if ((attr == PW_VENDOR_SPECIFIC) &&
548 (VENDOR(i->attribute) == 0)) {
554 * Remove the attribute from the "from" list.
562 * Add the attribute to the "to" list.
575 * Sort of strtok/strsep function.
577 static char *mystrtok(char **ptr, const char *sep)
583 while (**ptr && strchr(sep, **ptr))
588 while (**ptr && strchr(sep, **ptr) == NULL)
596 * Turn printable string into time_t
597 * Returns -1 on error, 0 on OK.
599 static int gettime(const char *valstr, time_t *lvalue)
610 * Test for unix timestamp date
612 *lvalue = strtoul(valstr, &tail, 10);
618 memset(tm, 0, sizeof(*tm));
619 tm->tm_isdst = -1; /* don't know, and don't care about DST */
621 strNcpy(buf, valstr, sizeof(buf));
624 f[0] = mystrtok(&p, " \t");
625 f[1] = mystrtok(&p, " \t");
626 f[2] = mystrtok(&p, " \t");
627 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
628 if (!f[0] || !f[1] || !f[2]) return -1;
631 * The time has a colon, where nothing else does.
632 * So if we find it, bubble it to the back of the list.
635 for (i = 0; i < 3; i++) {
636 if (strchr(f[i], ':')) {
646 * The month is text, which allows us to find it easily.
649 for (i = 0; i < 3; i++) {
650 if (isalpha( (int) *f[i])) {
652 * Bubble the month to the front of the list
658 for (i = 0; i < 12; i++) {
659 if (strncasecmp(months[i], f[0], 3) == 0) {
667 /* month not found? */
668 if (tm->tm_mon == 12) return -1;
671 * The year may be in f[1], or in f[2]
673 tm->tm_year = atoi(f[1]);
674 tm->tm_mday = atoi(f[2]);
676 if (tm->tm_year >= 1900) {
681 * We can't use 2-digit years any more, they make it
682 * impossible to tell what's the day, and what's the year.
684 if (tm->tm_mday < 1900) return -1;
687 * Swap the year and the day.
690 tm->tm_year = tm->tm_mday - 1900;
695 * If the day is out of range, die.
697 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
702 * There may be %H:%M:%S. Parse it in a hacky way.
705 f[0] = f[3]; /* HH */
706 f[1] = strchr(f[0], ':'); /* find : separator */
707 if (!f[1]) return -1;
709 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
711 f[2] = strchr(f[1], ':'); /* find : separator */
713 *(f[2]++) = '\0'; /* nuke it, and point to SS */
715 strcpy(f[2], "0"); /* assignment would discard const */
718 tm->tm_hour = atoi(f[0]);
719 tm->tm_min = atoi(f[1]);
720 tm->tm_sec = atoi(f[2]);
724 * Returns -1 on error.
727 if (t == (time_t) -1) return -1;
736 * Parse a string value into a given VALUE_PAIR
738 * FIXME: we probably want to fix this function to accept
739 * octets as values for any type of attribute. We should then
740 * double-check the parsed value, to be sure it's legal for that
741 * type (length, etc.)
743 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
750 * Even for integers, dates and ip addresses we
751 * keep the original string in vp->vp_strvalue.
753 strNcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
754 vp->length = strlen(vp->vp_strvalue);
759 * Already handled above.
765 * It's a comparison, not a real IP.
767 if ((vp->operator == T_OP_REG_EQ) ||
768 (vp->operator == T_OP_REG_NE)) {
773 * FIXME: complain if hostname
774 * cannot be resolved, or resolve later!
776 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
777 cs = s = strdup(value);
780 vp->flags.addport = 1;
787 lrad_ipaddr_t ipaddr;
789 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
790 librad_log("Failed to find IP address for %s", cs);
794 vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
802 * Note that ALL integers are unsigned!
804 if (isdigit((int) value[0]) &&
805 (strspn(value, "0123456789") == strlen(value))) {
806 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
807 if (vp->lvalue > 255) {
808 librad_log("Byte value \"%s\" is larger than 255", value);
815 * Look for the named value for the given
818 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
819 librad_log("Unknown value %s for attribute %s",
823 vp->lvalue = dval->value;
830 * Note that ALL integers are unsigned!
832 if (isdigit((int) value[0]) &&
833 (strspn(value, "0123456789") == strlen(value))) {
834 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
835 if (vp->lvalue > 65535) {
836 librad_log("Byte value \"%s\" is larger than 65535", value);
843 * Look for the named value for the given
846 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
847 librad_log("Unknown value %s for attribute %s",
851 vp->lvalue = dval->value;
856 case PW_TYPE_INTEGER:
858 * Note that ALL integers are unsigned!
860 if (isdigit((int) value[0]) &&
861 (strspn(value, "0123456789") == strlen(value))) {
862 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
867 * Look for the named value for the given
870 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
871 librad_log("Unknown value %s for attribute %s",
875 vp->lvalue = dval->value;
881 if (gettime(value, (time_t *)&vp->lvalue) < 0) {
882 librad_log("failed to parse time string "
888 case PW_TYPE_ABINARY:
890 if (strncasecmp(value, "0x", 2) == 0) {
891 vp->type = PW_TYPE_OCTETS;
895 if (ascend_parse_filter(vp) < 0 ) {
896 librad_log("failed to parse Ascend binary attribute: %s",
903 * If Ascend binary is NOT defined,
904 * then fall through to raw octets, so that
905 * the user can at least make them by hand...
909 /* raw octets: 0x01020304... */
911 if (strncasecmp(value, "0x", 2) == 0) {
914 us = vp->vp_strvalue;
919 * There is only one character,
922 if ((strlen(cp) & 0x01) != 0) {
923 librad_log("Hex string is not an even length string.");
928 while (*cp && vp->length < MAX_STRING_LEN) {
931 if (sscanf(cp, "%02x", &tmp) != 1) {
932 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
945 if (ifid_aton(value, vp->vp_strvalue) == NULL) {
946 librad_log("failed to parse interface-id "
947 "string \"%s\"", value);
951 vp->vp_strvalue[vp->length] = '\0';
954 case PW_TYPE_IPV6ADDR:
955 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
956 librad_log("failed to parse IPv6 address "
957 "string \"%s\"", value);
960 vp->length = 16; /* length of IPv6 address */
961 vp->vp_strvalue[vp->length] = '\0';
966 case PW_TYPE_IPV6PREFIX:
967 p = strchr(value, '/');
968 if (!p || ((p - value) >= 256)) {
969 librad_log("invalid IPv6 prefix "
970 "string \"%s\"", value);
974 char buffer[256], *eptr;
976 memcpy(buffer, value, p - value);
977 buffer[p - value] = '\0';
979 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
980 librad_log("failed to parse IPv6 address "
981 "string \"%s\"", value);
985 prefix = strtoul(p + 1, &eptr, 10);
986 if ((prefix > 128) || *eptr) {
987 librad_log("failed to parse IPv6 address "
988 "string \"%s\"", value);
991 vp->vp_strvalue[1] = prefix;
993 vp->vp_strvalue[0] = '\0';
998 librad_log("unknown attribute type %d", vp->type);
1006 * Create a VALUE_PAIR from an ASCII attribute and value,
1007 * where the attribute name is in the form:
1012 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1020 * Unknown attributes MUST be of type 'octets'
1022 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1029 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1030 attr = atoi(attribute + 5);
1032 p += strspn(p, "0123456789");
1033 if (*p != 0) goto error;
1038 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1041 vendor = atoi(attribute + 7);
1042 if ((vendor == 0) || (vendor > 65535)) goto error;
1045 p += strspn(p, "0123456789");
1048 * Not Vendor-%d-Attr-%d
1050 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1055 p += strspn(p, "0123456789");
1056 if (*p != 0) goto error;
1058 if ((attr == 0) || (attr > 65535)) goto error;
1060 attr |= (vendor << 16);
1063 * VendorName-Attr-%d
1065 } else if (((p = strchr(attribute, '-')) != NULL) &&
1066 (strncasecmp(p, "-Attr-", 6) == 0)) {
1070 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1072 memcpy(buffer, attribute, p - attribute);
1073 buffer[p - attribute] = '\0';
1075 vendor = dict_vendorbyname(buffer);
1076 if (vendor == 0) goto error;
1081 p += strspn(p, "0123456789");
1082 if (*p != 0) goto error;
1084 if ((attr == 0) || (attr > 65535)) goto error;
1086 attr |= (vendor << 16);
1088 } else { /* very much unknown: die */
1090 librad_log("Unknown attribute \"%s\"", attribute);
1095 * We've now parsed the attribute properly, and verified
1096 * it to have value 'octets'. Let's create it.
1098 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1099 librad_log("out of memory");
1102 memset(vp, 0, sizeof(VALUE_PAIR));
1103 vp->type = PW_TYPE_OCTETS;
1106 * It may not be valid hex characters. If not, die.
1108 if (pairparsevalue(vp, value) == NULL) {
1113 if (VENDOR(attr) == 0) {
1114 sprintf(vp->name, "Attr-%u", attr);
1116 sprintf(vp->name, "Vendor-%u-Attr-%u",
1117 VENDOR(attr), attr & 0xffff);
1120 vp->attribute = attr;
1121 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1129 * Create a VALUE_PAIR from an ASCII attribute and value.
1131 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1144 * Check for tags in 'Attribute:Tag' format.
1149 ts = strrchr(attribute, ':');
1151 librad_log("Invalid tag for attribute %s", attribute);
1156 /* Colon found with something behind it */
1157 if (ts[1] == '*' && ts[2] == 0) {
1158 /* Wildcard tag for check items */
1161 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1162 /* It's not a wild card tag */
1163 tag = strtol(ts + 1, &tc, 0);
1164 if (tc && !*tc && TAG_VALID_ZERO(tag))
1168 librad_log("Invalid tag for attribute %s", attribute);
1175 * It's not found in the dictionary, so we use
1176 * another method to create the attribute.
1178 if ((da = dict_attrbyname(attribute)) == NULL) {
1179 return pairmake_any(attribute, value, operator);
1182 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1183 librad_log("out of memory");
1187 memset(vp, 0, sizeof(VALUE_PAIR));
1188 vp->attribute = da->attr;
1189 vp->type = da->type;
1190 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1191 strcpy(vp->name, da->name);
1192 vp->flags = da->flags;
1195 /* Check for a tag in the 'Merit' format of:
1196 * :Tag:Value. Print an error if we already found
1197 * a tag in the Attribute.
1200 if (value && (*value == ':' && da->flags.has_tag)) {
1201 /* If we already found a tag, this is invalid */
1204 librad_log("Duplicate tag %s for attribute %s",
1206 DEBUG("Duplicate tag %s for attribute %s\n",
1211 /* Colon found and attribute allows a tag */
1212 if (value[1] == '*' && value[2] == ':') {
1213 /* Wildcard tag for check items */
1218 tag = strtol(value + 1, &tc, 0);
1219 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1227 vp->flags.tag = tag;
1230 switch (vp->operator) {
1235 * For =* and !* operators, the value is irrelevant
1239 case T_OP_CMP_FALSE:
1240 vp->vp_strvalue[0] = '\0';
1246 * Regular expression comparison of integer attributes
1247 * does a STRING comparison of the names of their
1248 * integer attributes.
1250 case T_OP_REG_EQ: /* =~ */
1251 case T_OP_REG_NE: /* !~ */
1252 if (vp->type == PW_TYPE_INTEGER) {
1257 * Regular expression match with no regular
1258 * expression is wrong.
1265 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1269 regerror(res, &cre, msg, sizeof(msg));
1270 librad_log("Illegal regular expression in attribute: %s: %s",
1277 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1285 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1286 * then the user MAY have typed in the attribute name
1287 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1289 * We probably want to fix pairparsevalue to accept
1290 * octets as values for any attribute.
1292 if (value && (pairparsevalue(vp, value) == NULL)) {
1304 static const int valid_attr_name[256] = {
1305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 1, 0, 0,
1308 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
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, 1,
1311 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1312 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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,
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
1324 * Read a valuepair from a buffer, and advance pointer.
1325 * Sets *eol to T_EOL if end of line was encountered.
1327 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1333 LRAD_TOKEN token, t, xlat;
1337 *eol = T_OP_INVALID;
1340 while ((*p == ' ') || (*p == '\t')) p++;
1343 *eol = T_OP_INVALID;
1344 librad_log("No token read where we expected an attribute name");
1350 librad_log("Read a comment instead of a token");
1355 for (len = 0; len < sizeof(attr); len++) {
1356 if (valid_attr_name[(int)*p]) {
1363 if (len == sizeof(attr)) {
1364 *eol = T_OP_INVALID;
1365 librad_log("Attribute name is too long");
1370 * We may have Foo-Bar:= stuff, so back up.
1372 if (attr[len - 1] == ':') {
1380 /* Now we should have an operator here. */
1381 token = gettoken(ptr, buf, sizeof(buf));
1382 if (token < T_EQSTART || token > T_EQEND) {
1383 librad_log("expecting operator");
1387 /* Read value. Note that empty string values are allowed */
1388 xlat = gettoken(ptr, value, sizeof(value));
1389 if (xlat == T_EOL) {
1390 librad_log("failed to get value");
1395 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1398 t = gettoken(&p, buf, sizeof(buf));
1399 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1400 librad_log("Expected end of line or comma");
1412 * Make the full pair now.
1415 vp = pairmake(attr, value, token);
1421 case T_DOUBLE_QUOTED_STRING:
1422 p = strchr(value, '%');
1423 if (p && (p[1] == '{')) {
1424 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1425 librad_log("Value too long");
1428 vp = pairmake(attr, NULL, token);
1430 *eol = T_OP_INVALID;
1434 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1435 vp->flags.do_xlat = 1;
1438 vp = pairmake(attr, value, token);
1444 * Mark the pair to be allocated later.
1446 case T_BACK_QUOTED_STRING:
1447 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1448 librad_log("Value too long");
1452 vp = pairmake(attr, NULL, token);
1454 *eol = T_OP_INVALID;
1458 vp->flags.do_xlat = 1;
1459 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1465 * If we didn't make a pair, return an error.
1468 *eol = T_OP_INVALID;
1476 * Read one line of attribute/value pairs. This might contain
1477 * multiple pairs seperated by comma's.
1479 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1483 LRAD_TOKEN last_token = T_OP_INVALID;
1484 LRAD_TOKEN previous_token;
1487 * We allow an empty line.
1494 previous_token = last_token;
1495 if ((vp = pairread(&p, &last_token)) == NULL) {
1498 pairadd(first_pair, vp);
1499 } while (*p && (last_token == T_COMMA));
1502 * Don't tell the caller that there was a comment.
1504 if (last_token == T_HASH) {
1505 return previous_token;
1509 * And return the last token which we read.
1515 * Read valuepairs from the fp up to End-Of-File.
1517 * Hmm... this function is only used by radclient..
1519 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1522 LRAD_TOKEN last_token = T_EOL;
1529 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1531 * If we get a '\n' by itself, we assume that's
1532 * the end of that VP
1534 if ((buf[0] == '\n') && (list)) {
1537 if ((buf[0] == '\n') && (!list)) {
1542 * Comments get ignored
1544 if (buf[0] == '#') continue;
1547 * Read all of the attributes on the current line.
1550 last_token = userparse(buf, &vp);
1552 if (last_token != T_EOL) {
1553 librad_perror("%s", errprefix);
1564 if (error) pairfree(&list);
1568 return error ? NULL: list;
1574 * Compare two pairs, using the operator from "one".
1576 * i.e. given two attributes, it does:
1578 * (two->data) (one->operator) (one->data)
1580 * e.g. "foo" != "bar"
1582 * Returns true (comparison is true), or false (comparison is not true);
1584 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1588 switch (one->operator) {
1590 return (two != NULL);
1592 case T_OP_CMP_FALSE:
1593 return (two == NULL);
1596 * One is a regex, compile it, print two to a string,
1597 * and then do string comparisons.
1601 #ifndef HAVE_REGEX_H
1606 char buffer[MAX_STRING_LEN * 4 + 1];
1608 compare = regcomp(®, one->vp_strvalue,
1611 regerror(compare, ®, buffer, sizeof(buffer));
1612 librad_log("Illegal regular expression in attribute: %s: %s",
1617 vp_prints_value(buffer, sizeof(buffer), two, 0);
1620 * Don't care about substring matches,
1623 compare = regexec(®, buffer, 0, NULL, 0);
1626 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1627 return (compare != 0);
1631 default: /* we're OK */
1636 * After doing the previous check for special comparisons,
1637 * do the per-type comparison here.
1639 switch (one->type) {
1640 case PW_TYPE_ABINARY:
1641 case PW_TYPE_OCTETS:
1644 const uint8_t *p, *q;
1646 if (one->length < two->length) {
1647 length = one->length;
1649 length = two->length;
1655 compare = ((int) *p) - ((int) *q);
1656 if (compare != 0) goto type_switch;
1660 * Contents are the same. The return code
1661 * is therefore the difference in lengths.
1663 * i.e. "0x00" is smaller than "0x0000"
1665 compare = two->length - one->length;
1669 case PW_TYPE_STRING:
1670 if (one->flags.caseless) {
1671 compare = strcasecmp(two->vp_strvalue,
1674 compare = strcmp(two->vp_strvalue,
1681 case PW_TYPE_INTEGER:
1683 compare = two->lvalue - one->lvalue;
1686 case PW_TYPE_IPADDR:
1687 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1690 case PW_TYPE_IPV6ADDR:
1691 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1692 sizeof(two->vp_ipv6addr));
1695 case PW_TYPE_IPV6PREFIX:
1696 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1697 sizeof(two->vp_ipv6prefix));
1701 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1702 sizeof(two->vp_ifid));
1706 return 0; /* unknown type */
1710 * Now do the operator comparison.
1713 switch (one->operator) {
1715 return (compare == 0);
1718 return (compare != 0);
1721 return (compare < 0);
1724 return (compare > 0);
1727 return (compare <= 0);
1730 return (compare >= 0);