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;
308 * First, see if there are any passwords here, and
309 * point "tailto" to the end of the "to" list.
312 for(i = *to; i; i = i->next) {
313 if (i->attribute == PW_PASSWORD ||
314 i->attribute == PW_CRYPT_PASSWORD)
320 * Loop over the "from" list.
322 for(i = *from; i; i = next) {
325 * If there was a password in the "to" list,
326 * do not move any other password from the
327 * "from" to the "to" list.
330 (i->attribute == PW_PASSWORD ||
331 i->attribute == PW_CRYPT_PASSWORD)) {
336 * If the attribute is already present in "to",
337 * do not move it from "from" to "to". We make
338 * an exception for "Hint" which can appear multiple
339 * times, and we never move "Fall-Through".
341 if (i->attribute == PW_FALL_THROUGH ||
342 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
344 found = pairfind(*to, i->attribute);
345 switch (i->operator) {
348 * If matching attributes are found,
351 case T_OP_SUB: /* -= */
353 if (!i->vp_strvalue[0] ||
354 (strcmp((char *)found->vp_strvalue,
355 (char *)i->vp_strvalue) == 0)){
356 pairdelete(to, found->attribute);
359 * 'tailto' may have been
363 for(j = *to; j; j = j->next) {
372 /* really HAVE_REGEX_H */
375 * Attr-Name =~ "s/find/replace/"
377 * Very bad code. Barely working,
383 (i->vp_strvalue[0] == 's')) {
390 p = i->vp_strvalue + 1;
391 q = strchr(p + 1, *p);
392 if (!q || (q[strlen(q) - 1] != *p)) {
396 str = strdup(i->vp_strvalue + 2);
399 q[strlen(q) - 1] = '\0';
401 regcomp(®, str, 0);
402 if (regexec(®, found->vp_strvalue,
404 fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
405 found->vp_strvalue, match[0].rm_so,
412 tailfrom = i; /* don't copy it over */
416 case T_OP_EQ: /* = */
418 * FIXME: Tunnel attributes with
419 * different tags are different
424 continue; /* with the loop */
429 * If a similar attribute is found,
430 * replace it with the new one. Otherwise,
431 * add the new one to the list.
433 case T_OP_SET: /* := */
435 VALUE_PAIR *mynext = found->next;
438 * Do NOT call pairdelete()
439 * here, due to issues with
440 * re-writing "request->username".
442 * Everybody calls pairmove,
443 * and expects it to work.
444 * We can't update request->username
445 * here, so instead we over-write
446 * the vp that it's pointing to.
448 memcpy(found, i, sizeof(*found));
449 found->next = mynext;
451 pairdelete(&found->next, found->attribute);
454 * 'tailto' may have been
457 for(j = found; j; j = j->next) {
465 * Add the new element to the list, even
466 * if similar ones already exist.
469 case T_OP_ADD: /* += */
474 tailfrom->next = next;
479 * If ALL of the 'to' attributes have been deleted,
480 * then ensure that the 'tail' is updated to point
495 * Move one kind of attributes from one list to the other
497 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
499 VALUE_PAIR *to_tail, *i, *next;
500 VALUE_PAIR *iprev = NULL;
503 * Find the last pair in the "to" list and put it in "to_tail".
507 for(i = *to; i; i = i->next)
512 for(i = *from; i; i = next) {
517 * If the attribute to move is NOT a VSA, then it
518 * ignores any attributes which do not match exactly.
520 if ((attr != PW_VENDOR_SPECIFIC) &&
521 (i->attribute != attr)) {
527 * If the attribute to move IS a VSA, then it ignores
528 * any non-VSA attribute.
530 if ((attr == PW_VENDOR_SPECIFIC) &&
531 (VENDOR(i->attribute) == 0)) {
537 * Remove the attribute from the "from" list.
545 * Add the attribute to the "to" list.
558 * Sort of strtok/strsep function.
560 static char *mystrtok(char **ptr, const char *sep)
566 while (**ptr && strchr(sep, **ptr))
571 while (**ptr && strchr(sep, **ptr) == NULL)
579 * Turn printable string into time_t
580 * Returns -1 on error, 0 on OK.
582 static int gettime(const char *valstr, time_t *lvalue)
593 * Test for unix timestamp date
595 *lvalue = strtoul(valstr, &tail, 10);
601 memset(tm, 0, sizeof(*tm));
602 tm->tm_isdst = -1; /* don't know, and don't care about DST */
604 strNcpy(buf, valstr, sizeof(buf));
607 f[0] = mystrtok(&p, " \t");
608 f[1] = mystrtok(&p, " \t");
609 f[2] = mystrtok(&p, " \t");
610 f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
611 if (!f[0] || !f[1] || !f[2]) return -1;
614 * The time has a colon, where nothing else does.
615 * So if we find it, bubble it to the back of the list.
618 for (i = 0; i < 3; i++) {
619 if (strchr(f[i], ':')) {
629 * The month is text, which allows us to find it easily.
632 for (i = 0; i < 3; i++) {
633 if (isalpha( (int) *f[i])) {
635 * Bubble the month to the front of the list
641 for (i = 0; i < 12; i++) {
642 if (strncasecmp(months[i], f[0], 3) == 0) {
650 /* month not found? */
651 if (tm->tm_mon == 12) return -1;
654 * The year may be in f[1], or in f[2]
656 tm->tm_year = atoi(f[1]);
657 tm->tm_mday = atoi(f[2]);
659 if (tm->tm_year >= 1900) {
664 * We can't use 2-digit years any more, they make it
665 * impossible to tell what's the day, and what's the year.
667 if (tm->tm_mday < 1900) return -1;
670 * Swap the year and the day.
673 tm->tm_year = tm->tm_mday - 1900;
678 * If the day is out of range, die.
680 if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
685 * There may be %H:%M:%S. Parse it in a hacky way.
688 f[0] = f[3]; /* HH */
689 f[1] = strchr(f[0], ':'); /* find : separator */
690 if (!f[1]) return -1;
692 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
694 f[2] = strchr(f[1], ':'); /* find : separator */
696 *(f[2]++) = '\0'; /* nuke it, and point to SS */
698 strcpy(f[2], "0"); /* assignment would discard const */
701 tm->tm_hour = atoi(f[0]);
702 tm->tm_min = atoi(f[1]);
703 tm->tm_sec = atoi(f[2]);
707 * Returns -1 on error.
710 if (t == (time_t) -1) return -1;
719 * Parse a string value into a given VALUE_PAIR
721 * FIXME: we probably want to fix this function to accept
722 * octets as values for any type of attribute. We should then
723 * double-check the parsed value, to be sure it's legal for that
724 * type (length, etc.)
726 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
733 * Even for integers, dates and ip addresses we
734 * keep the original string in vp->vp_strvalue.
736 strNcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
737 vp->length = strlen(vp->vp_strvalue);
742 * Already handled above.
748 * It's a comparison, not a real IP.
750 if ((vp->operator == T_OP_REG_EQ) ||
751 (vp->operator == T_OP_REG_NE)) {
756 * FIXME: complain if hostname
757 * cannot be resolved, or resolve later!
759 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
760 cs = s = strdup(value);
763 vp->flags.addport = 1;
770 lrad_ipaddr_t ipaddr;
772 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
773 librad_log("Failed to find IP address for %s", cs);
777 vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
785 * Note that ALL integers are unsigned!
787 if (isdigit((int) value[0]) &&
788 (strspn(value, "0123456789") == strlen(value))) {
789 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
790 if (vp->lvalue > 255) {
791 librad_log("Byte value \"%s\" is larger than 255", value);
798 * Look for the named value for the given
801 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
802 librad_log("Unknown value %s for attribute %s",
806 vp->lvalue = dval->value;
813 * Note that ALL integers are unsigned!
815 if (isdigit((int) value[0]) &&
816 (strspn(value, "0123456789") == strlen(value))) {
817 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
818 if (vp->lvalue > 65535) {
819 librad_log("Byte value \"%s\" is larger than 65535", value);
826 * Look for the named value for the given
829 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
830 librad_log("Unknown value %s for attribute %s",
834 vp->lvalue = dval->value;
839 case PW_TYPE_INTEGER:
841 * Note that ALL integers are unsigned!
843 if (isdigit((int) value[0]) &&
844 (strspn(value, "0123456789") == strlen(value))) {
845 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
850 * Look for the named value for the given
853 else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
854 librad_log("Unknown value %s for attribute %s",
858 vp->lvalue = dval->value;
864 if (gettime(value, (time_t *)&vp->lvalue) < 0) {
865 librad_log("failed to parse time string "
871 case PW_TYPE_ABINARY:
873 if (strncasecmp(value, "0x", 2) == 0) {
874 vp->type = PW_TYPE_OCTETS;
878 if (ascend_parse_filter(vp) < 0 ) {
879 librad_log("failed to parse Ascend binary attribute: %s",
886 * If Ascend binary is NOT defined,
887 * then fall through to raw octets, so that
888 * the user can at least make them by hand...
892 /* raw octets: 0x01020304... */
894 if (strncasecmp(value, "0x", 2) == 0) {
897 us = vp->vp_strvalue;
902 * There is only one character,
905 if ((strlen(cp) & 0x01) != 0) {
906 librad_log("Hex string is not an even length string.");
911 while (*cp && vp->length < MAX_STRING_LEN) {
914 if (sscanf(cp, "%02x", &tmp) != 1) {
915 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
928 if (ifid_aton(value, vp->vp_strvalue) == NULL) {
929 librad_log("failed to parse interface-id "
930 "string \"%s\"", value);
934 vp->vp_strvalue[vp->length] = '\0';
937 case PW_TYPE_IPV6ADDR:
938 if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
939 librad_log("failed to parse IPv6 address "
940 "string \"%s\"", value);
943 vp->length = 16; /* length of IPv6 address */
944 vp->vp_strvalue[vp->length] = '\0';
949 case PW_TYPE_IPV6PREFIX:
950 p = strchr(value, '/');
951 if (!p || ((p - value) >= 256)) {
952 librad_log("invalid IPv6 prefix "
953 "string \"%s\"", value);
957 char buffer[256], *eptr;
959 memcpy(buffer, value, p - value);
960 buffer[p - value] = '\0';
962 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
963 librad_log("failed to parse IPv6 address "
964 "string \"%s\"", value);
968 prefix = strtoul(p + 1, &eptr, 10);
969 if ((prefix > 128) || *eptr) {
970 librad_log("failed to parse IPv6 address "
971 "string \"%s\"", value);
974 vp->vp_strvalue[1] = prefix;
976 vp->vp_strvalue[0] = '\0';
981 librad_log("unknown attribute type %d", vp->type);
989 * Create a VALUE_PAIR from an ASCII attribute and value,
990 * where the attribute name is in the form:
995 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
1003 * Unknown attributes MUST be of type 'octets'
1005 if (value && (strncasecmp(value, "0x", 2) != 0)) {
1012 if (strncasecmp(attribute, "Attr-", 5) == 0) {
1013 attr = atoi(attribute + 5);
1015 p += strspn(p, "0123456789");
1016 if (*p != 0) goto error;
1021 } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1024 vendor = atoi(attribute + 7);
1025 if ((vendor == 0) || (vendor > 65535)) goto error;
1028 p += strspn(p, "0123456789");
1031 * Not Vendor-%d-Attr-%d
1033 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1038 p += strspn(p, "0123456789");
1039 if (*p != 0) goto error;
1041 if ((attr == 0) || (attr > 65535)) goto error;
1043 attr |= (vendor << 16);
1046 * VendorName-Attr-%d
1048 } else if (((p = strchr(attribute, '-')) != NULL) &&
1049 (strncasecmp(p, "-Attr-", 6) == 0)) {
1053 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1055 memcpy(buffer, attribute, p - attribute);
1056 buffer[p - attribute] = '\0';
1058 vendor = dict_vendorbyname(buffer);
1059 if (vendor == 0) goto error;
1064 p += strspn(p, "0123456789");
1065 if (*p != 0) goto error;
1067 if ((attr == 0) || (attr > 65535)) goto error;
1069 attr |= (vendor << 16);
1071 } else { /* very much unknown: die */
1073 librad_log("Unknown attribute \"%s\"", attribute);
1078 * We've now parsed the attribute properly, and verified
1079 * it to have value 'octets'. Let's create it.
1081 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1082 librad_log("out of memory");
1085 memset(vp, 0, sizeof(VALUE_PAIR));
1086 vp->type = PW_TYPE_OCTETS;
1089 * It may not be valid hex characters. If not, die.
1091 if (pairparsevalue(vp, value) == NULL) {
1096 if (VENDOR(attr) == 0) {
1097 sprintf(vp->name, "Attr-%u", attr);
1099 sprintf(vp->name, "Vendor-%u-Attr-%u",
1100 VENDOR(attr), attr & 0xffff);
1103 vp->attribute = attr;
1104 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1112 * Create a VALUE_PAIR from an ASCII attribute and value.
1114 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1127 * Check for tags in 'Attribute:Tag' format.
1132 ts = strrchr(attribute, ':');
1134 librad_log("Invalid tag for attribute %s", attribute);
1139 /* Colon found with something behind it */
1140 if (ts[1] == '*' && ts[2] == 0) {
1141 /* Wildcard tag for check items */
1144 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1145 /* It's not a wild card tag */
1146 tag = strtol(ts + 1, &tc, 0);
1147 if (tc && !*tc && TAG_VALID_ZERO(tag))
1151 librad_log("Invalid tag for attribute %s", attribute);
1158 * It's not found in the dictionary, so we use
1159 * another method to create the attribute.
1161 if ((da = dict_attrbyname(attribute)) == NULL) {
1162 return pairmake_any(attribute, value, operator);
1165 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1166 librad_log("out of memory");
1170 memset(vp, 0, sizeof(VALUE_PAIR));
1171 vp->attribute = da->attr;
1172 vp->type = da->type;
1173 vp->operator = (operator == 0) ? T_OP_EQ : operator;
1174 strcpy(vp->name, da->name);
1175 vp->flags = da->flags;
1178 /* Check for a tag in the 'Merit' format of:
1179 * :Tag:Value. Print an error if we already found
1180 * a tag in the Attribute.
1183 if (value && (*value == ':' && da->flags.has_tag)) {
1184 /* If we already found a tag, this is invalid */
1187 librad_log("Duplicate tag %s for attribute %s",
1189 DEBUG("Duplicate tag %s for attribute %s\n",
1194 /* Colon found and attribute allows a tag */
1195 if (value[1] == '*' && value[2] == ':') {
1196 /* Wildcard tag for check items */
1201 tag = strtol(value + 1, &tc, 0);
1202 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1210 vp->flags.tag = tag;
1213 switch (vp->operator) {
1218 * For =* and !* operators, the value is irrelevant
1222 case T_OP_CMP_FALSE:
1223 vp->vp_strvalue[0] = '\0';
1229 * Regular expression comparison of integer attributes
1230 * does a STRING comparison of the names of their
1231 * integer attributes.
1233 case T_OP_REG_EQ: /* =~ */
1234 case T_OP_REG_NE: /* !~ */
1235 if (vp->type == PW_TYPE_INTEGER) {
1240 * Regular expression match with no regular
1241 * expression is wrong.
1248 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1252 regerror(res, &cre, msg, sizeof(msg));
1253 librad_log("Illegal regular expression in attribute: %s: %s",
1260 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1268 * FIXME: if (strcasecmp(attribute, vp->name) != 0)
1269 * then the user MAY have typed in the attribute name
1270 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1272 * We probably want to fix pairparsevalue to accept
1273 * octets as values for any attribute.
1275 if (value && (pairparsevalue(vp, value) == NULL)) {
1287 static const int valid_attr_name[256] = {
1288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1292 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1293 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1294 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1307 * Read a valuepair from a buffer, and advance pointer.
1308 * Sets *eol to T_EOL if end of line was encountered.
1310 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1316 LRAD_TOKEN token, t, xlat;
1320 *eol = T_OP_INVALID;
1323 while ((*p == ' ') || (*p == '\t')) p++;
1326 *eol = T_OP_INVALID;
1327 librad_log("No token read where we expected an attribute name");
1333 librad_log("Read a comment instead of a token");
1338 for (len = 0; len < sizeof(attr); len++) {
1339 if (valid_attr_name[(int)*p]) {
1346 if (len == sizeof(attr)) {
1347 *eol = T_OP_INVALID;
1348 librad_log("Attribute name is too long");
1353 * We may have Foo-Bar:= stuff, so back up.
1355 if (attr[len - 1] == ':') {
1363 /* Now we should have an operator here. */
1364 token = gettoken(ptr, buf, sizeof(buf));
1365 if (token < T_EQSTART || token > T_EQEND) {
1366 librad_log("expecting operator");
1370 /* Read value. Note that empty string values are allowed */
1371 xlat = gettoken(ptr, value, sizeof(value));
1372 if (xlat == T_EOL) {
1373 librad_log("failed to get value");
1378 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1381 t = gettoken(&p, buf, sizeof(buf));
1382 if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1383 librad_log("Expected end of line or comma");
1395 * Make the full pair now.
1398 vp = pairmake(attr, value, token);
1404 case T_DOUBLE_QUOTED_STRING:
1405 p = strchr(value, '%');
1406 if (p && (p[1] == '{')) {
1407 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1408 librad_log("Value too long");
1411 vp = pairmake(attr, NULL, token);
1413 *eol = T_OP_INVALID;
1417 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1418 vp->flags.do_xlat = 1;
1421 vp = pairmake(attr, value, token);
1427 * Mark the pair to be allocated later.
1429 case T_BACK_QUOTED_STRING:
1430 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1431 librad_log("Value too long");
1435 vp = pairmake(attr, NULL, token);
1437 *eol = T_OP_INVALID;
1441 vp->flags.do_xlat = 1;
1442 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1448 * If we didn't make a pair, return an error.
1451 *eol = T_OP_INVALID;
1459 * Read one line of attribute/value pairs. This might contain
1460 * multiple pairs seperated by comma's.
1462 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1466 LRAD_TOKEN last_token = T_OP_INVALID;
1467 LRAD_TOKEN previous_token;
1470 * We allow an empty line.
1477 previous_token = last_token;
1478 if ((vp = pairread(&p, &last_token)) == NULL) {
1481 pairadd(first_pair, vp);
1482 } while (*p && (last_token == T_COMMA));
1485 * Don't tell the caller that there was a comment.
1487 if (last_token == T_HASH) {
1488 return previous_token;
1492 * And return the last token which we read.
1498 * Read valuepairs from the fp up to End-Of-File.
1500 * Hmm... this function is only used by radclient..
1502 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1505 LRAD_TOKEN last_token = T_EOL;
1512 while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1514 * If we get a '\n' by itself, we assume that's
1515 * the end of that VP
1517 if ((buf[0] == '\n') && (list)) {
1520 if ((buf[0] == '\n') && (!list)) {
1525 * Comments get ignored
1527 if (buf[0] == '#') continue;
1530 * Read all of the attributes on the current line.
1533 last_token = userparse(buf, &vp);
1535 if (last_token != T_EOL) {
1536 librad_perror("%s", errprefix);
1547 if (error) pairfree(&list);
1551 return error ? NULL: list;
1557 * Compare two pairs, using the operator from "one".
1559 * i.e. given two attributes, it does:
1561 * (two->data) (one->operator) (one->data)
1563 * e.g. "foo" != "bar"
1565 * Returns true (comparison is true), or false (comparison is not true);
1567 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1571 switch (one->operator) {
1573 return (two != NULL);
1575 case T_OP_CMP_FALSE:
1576 return (two == NULL);
1579 * One is a regex, compile it, print two to a string,
1580 * and then do string comparisons.
1584 #ifndef HAVE_REGEX_H
1589 char buffer[MAX_STRING_LEN * 4 + 1];
1591 compare = regcomp(®, one->vp_strvalue,
1594 regerror(compare, ®, buffer, sizeof(buffer));
1595 librad_log("Illegal regular expression in attribute: %s: %s",
1600 vp_prints_value(buffer, sizeof(buffer), two, 0);
1603 * Don't care about substring matches,
1606 compare = regexec(®, buffer, 0, NULL, 0);
1609 if (one->operator == T_OP_REG_EQ) return (compare == 0);
1610 return (compare != 0);
1614 default: /* we're OK */
1619 * After doing the previous check for special comparisons,
1620 * do the per-type comparison here.
1622 switch (one->type) {
1623 case PW_TYPE_ABINARY:
1624 case PW_TYPE_OCTETS:
1627 const uint8_t *p, *q;
1629 if (one->length < two->length) {
1630 length = one->length;
1632 length = two->length;
1638 compare = ((int) *p) - ((int) *q);
1639 if (compare != 0) goto type_switch;
1643 * Contents are the same. The return code
1644 * is therefore the difference in lengths.
1646 * i.e. "0x00" is smaller than "0x0000"
1648 compare = two->length - one->length;
1652 case PW_TYPE_STRING:
1653 if (one->flags.caseless) {
1654 compare = strcasecmp(two->vp_strvalue,
1657 compare = strcmp(two->vp_strvalue,
1664 case PW_TYPE_INTEGER:
1666 compare = two->lvalue - one->lvalue;
1669 case PW_TYPE_IPADDR:
1670 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1673 case PW_TYPE_IPV6ADDR:
1674 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1675 sizeof(two->vp_ipv6addr));
1678 case PW_TYPE_IPV6PREFIX:
1679 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1680 sizeof(two->vp_ipv6prefix));
1684 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1685 sizeof(two->vp_ifid));
1689 return 0; /* unknown type */
1693 * Now do the operator comparison.
1696 switch (one->operator) {
1698 return (compare == 0);
1701 return (compare != 0);
1704 return (compare < 0);
1707 return (compare > 0);
1710 return (compare <= 0);
1713 return (compare >= 0);