📄 valuepair.c
字号:
return NULL; } size = strlen(value + 2); /* * We may be reading something like Attr-5. i.e. * who-ever wrote the text didn't understand it, but we * do. */ switch (vp->type) { default: if (size == (vp->length * 2)) break; vp->type = PW_TYPE_OCTETS; /* FALL-THROUGH */ case PW_TYPE_STRING: case PW_TYPE_OCTETS: case PW_TYPE_ABINARY: vp->length = size >> 1; break; } if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) { librad_log("Invalid hex string"); free(vp); return NULL; } /* * Move contents around based on type. This is * to work around the historical use of "lvalue". */ switch (vp->type) { case PW_TYPE_DATE: case PW_TYPE_IPADDR: case PW_TYPE_INTEGER: memcpy(&vp->lvalue, vp->vp_octets, sizeof(vp->lvalue)); vp->vp_strvalue[0] = '\0'; break; default: break; } vp->operator = (operator == 0) ? T_OP_EQ : operator; return vp;}/* * Create a VALUE_PAIR from an ASCII attribute and value. */VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator){ DICT_ATTR *da; VALUE_PAIR *vp; char *tc, *ts; signed char tag; int found_tag;#ifdef HAVE_REGEX_H int res; regex_t cre;#endif char buffer[64]; const char *attrname = attribute; /* * Check for tags in 'Attribute:Tag' format. */ found_tag = 0; tag = 0; ts = strrchr(attribute, ':'); if (ts && !ts[1]) { librad_log("Invalid tag for attribute %s", attribute); return NULL; } if (ts && ts[1]) { strlcpy(buffer, attribute, sizeof(buffer)); attrname = buffer; ts = strrchr(attrname, ':'); /* Colon found with something behind it */ if (ts[1] == '*' && ts[2] == 0) { /* Wildcard tag for check items */ tag = TAG_ANY; *ts = 0; } else if ((ts[1] >= '0') && (ts[1] <= '9')) { /* It's not a wild card tag */ tag = strtol(ts + 1, &tc, 0); if (tc && !*tc && TAG_VALID_ZERO(tag)) *ts = 0; else tag = 0; } else { librad_log("Invalid tag for attribute %s", attribute); return NULL; } found_tag = 1; } /* * It's not found in the dictionary, so we use * another method to create the attribute. */ if ((da = dict_attrbyname(attrname)) == NULL) { return pairmake_any(attrname, value, operator); } if ((vp = pairalloc(da)) == NULL) { librad_log("out of memory"); return NULL; } vp->operator = (operator == 0) ? T_OP_EQ : operator; /* Check for a tag in the 'Merit' format of: * :Tag:Value. Print an error if we already found * a tag in the Attribute. */ if (value && (*value == ':' && da->flags.has_tag)) { /* If we already found a tag, this is invalid */ if(found_tag) { pairbasicfree(vp); librad_log("Duplicate tag %s for attribute %s", value, vp->name); DEBUG("Duplicate tag %s for attribute %s\n", value, vp->name); return NULL; } /* Colon found and attribute allows a tag */ if (value[1] == '*' && value[2] == ':') { /* Wildcard tag for check items */ tag = TAG_ANY; value += 3; } else { /* Real tag */ tag = strtol(value + 1, &tc, 0); if (tc && *tc==':' && TAG_VALID_ZERO(tag)) value = tc + 1; else tag = 0; } found_tag = 1; } if (found_tag) { vp->flags.tag = tag; } switch (vp->operator) { default: break; /* * For =* and !* operators, the value is irrelevant * so we return now. */ case T_OP_CMP_TRUE: case T_OP_CMP_FALSE: vp->vp_strvalue[0] = '\0'; vp->length = 0; return vp; break; /* * Regular expression comparison of integer attributes * does a STRING comparison of the names of their * integer attributes. */ case T_OP_REG_EQ: /* =~ */ case T_OP_REG_NE: /* !~ */ if (vp->type == PW_TYPE_INTEGER) { return vp; }#ifdef HAVE_REGEX_H /* * Regular expression match with no regular * expression is wrong. */ if (!value) { pairfree(&vp); return NULL; } res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB); if (res != 0) { char msg[128]; regerror(res, &cre, msg, sizeof(msg)); librad_log("Illegal regular expression in attribute: %s: %s", vp->name, msg); pairbasicfree(vp); return NULL; } regfree(&cre);#else librad_log("Regular expressions not enabled in this build, error in attribute %s", vp->name); pairbasicfree(vp); return NULL;#endif } /* * FIXME: if (strcasecmp(attribute, vp->name) != 0) * then the user MAY have typed in the attribute name * as Vendor-%d-Attr-%d, and the value MAY be octets. * * We probably want to fix pairparsevalue to accept * octets as values for any attribute. */ if (value && (pairparsevalue(vp, value) == NULL)) { pairbasicfree(vp); return NULL; } return vp;}/* * [a-zA-Z0-9_-:]+ */static const int valid_attr_name[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* * Read a valuepair from a buffer, and advance pointer. * Sets *eol to T_EOL if end of line was encountered. */VALUE_PAIR *pairread(const char **ptr, FR_TOKEN *eol){ char buf[64]; char attr[64]; char value[512], *q; const char *p; FR_TOKEN token, t, xlat; VALUE_PAIR *vp; size_t len; *eol = T_OP_INVALID; p = *ptr; while ((*p == ' ') || (*p == '\t')) p++; if (!*p) { *eol = T_OP_INVALID; librad_log("No token read where we expected an attribute name"); return NULL; } if (*p == '#') { *eol = T_HASH; librad_log("Read a comment instead of a token"); return NULL; } q = attr; for (len = 0; len < sizeof(attr); len++) { if (valid_attr_name[(int)*p]) { *q++ = *p++; continue; } break; } if (len == sizeof(attr)) { *eol = T_OP_INVALID; librad_log("Attribute name is too long"); return NULL; } /* * We may have Foo-Bar:= stuff, so back up. */ if (attr[len - 1] == ':') { p--; len--; } attr[len] = '\0'; *ptr = p; /* Now we should have an operator here. */ token = gettoken(ptr, buf, sizeof(buf)); if (token < T_EQSTART || token > T_EQEND) { librad_log("expecting operator"); return NULL; } /* Read value. Note that empty string values are allowed */ xlat = gettoken(ptr, value, sizeof(value)); if (xlat == T_EOL) { librad_log("failed to get value"); return NULL; } /* * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH */ p = *ptr; t = gettoken(&p, buf, sizeof(buf)); if (t != T_EOL && t != T_COMMA && t != T_HASH) { librad_log("Expected end of line or comma"); return NULL; } *eol = t; if (t == T_COMMA) { *ptr = p; } vp = NULL; switch (xlat) { /* * Make the full pair now. */ default: vp = pairmake(attr, value, token); break; /* * Perhaps do xlat's */ case T_DOUBLE_QUOTED_STRING: p = strchr(value, '%'); if (p && (p[1] == '{')) { if (strlen(value) >= sizeof(vp->vp_strvalue)) { librad_log("Value too long"); return NULL; } vp = pairmake(attr, NULL, token); if (!vp) { *eol = T_OP_INVALID; return NULL; } strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue)); vp->flags.do_xlat = 1; vp->length = 0; } else { vp = pairmake(attr, value, token); } break; /* * Mark the pair to be allocated later. */ case T_BACK_QUOTED_STRING: if (strlen(value) >= sizeof(vp->vp_strvalue)) { librad_log("Value too long"); return NULL; } vp = pairmake(attr, NULL, token); if (!vp) { *eol = T_OP_INVALID; return NULL; } vp->flags.do_xlat = 1; strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue)); vp->length = 0; break; } /* * If we didn't make a pair, return an error. */ if (!vp) { *eol = T_OP_INVALID; return NULL; } return vp;}/* * Read one line of attribute/value pairs. This might contain * multiple pairs seperated by comma's. */FR_TOKEN userparse(const char *buffer, VALUE_PAIR **first_pair){ VALUE_PAIR *vp; const char *p; FR_TOKEN last_token = T_OP_INVALID; FR_TOKEN previous_token; /* * We allow an empty line. */ if (buffer[0] == 0) return T_EOL; p = buffer; do { previous_token = last_token; if ((vp = pairread(&p, &last_token)) == NULL) { return last_token; } pairadd(first_pair, vp); } while (*p && (last_token == T_COMMA)); /* * Don't tell the caller that there was a comment. */ if (last_token == T_HASH) { return previous_token; } /* * And return the last token which we read. */ return last_token;}/* * Read valuepairs from the fp up to End-Of-File. * * Hmm... this function is only used by radclient.. */VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix){ char buf[8192]; FR_TOKEN last_token = T_EOL; VALUE_PAIR *vp; VALUE_PAIR *list; int error = 0; list = NULL; while (!error && fgets(buf, sizeof(buf), fp) != NULL) { /* * If we get a '\n' by itself, we assume that's * the end of that VP */ if ((buf[0] == '\n') && (list)) { return list; } if ((buf[0] == '\n') && (!list)) { continue; } /* * Comments get ignored */ if (buf[0] == '#') continue; /* * Read all of the attributes on the current line. */ vp = NULL; last_token = userparse(buf, &vp); if (!vp) { if (last_token != T_EOL) { librad_perror("%s", errprefix); error = 1; break; } break; } pairadd(&list, vp); buf[0] = '\0'; } if (error) pairfree(&list); *pfiledone = 1; return error ? NULL: list;}/* * Compare two pairs, using the operator from "one". * * i.e. given two attributes, it does: * * (two->data) (one->operator) (one->data) * * e.g. "foo" != "bar" * * Returns true (comparison is true), or false (comparison is not true); */int paircmp(VALUE_PAIR *one, VALUE_PAIR *two){ int compare; switch (one->operator) { case T_OP_CMP_TRUE: return (two != NULL); case T_OP_CMP_FALSE: return (two == NULL); /* * One is a regex, compile it, print two to a string, * and then do string comparisons. */ case T_OP_REG_EQ: case T_OP_REG_NE:#ifndef HAVE_REGEX_H return -1;#else { regex_t reg; char buffer[MAX_STRING_LEN * 4 + 1]; compare = regcomp(®, one->vp_strvalue, REG_EXTENDED); if (compare != 0) { regerror(compare, ®, buffer, sizeof(buffer)); librad_log("Illegal regular expression in attribute: %s: %s", one->name, buffer); return -1; } vp_prints_value(buffer, sizeof(buffer), two, 0); /* * Don't care about substring matches, * oh well... */ compare = regexec(®, buffer, 0, NULL, 0); regfree(®); if (one->operator == T_OP_REG_EQ) return (compare == 0); return (compare != 0); }#endif default: /* we're OK */ break; } /* * After doing the previous check for special comparisons, * do the per-type comparison here. */ switch (one->type) { case PW_TYPE_ABINARY: case PW_TYPE_OCTETS: { size_t length; if (one->length < two->length) { length = one->length; } else { length = two->length; } if (length) { compare = memcmp(two->vp_octets, one->vp_octets, length); if (compare != 0) break; } /* * Contents are the same. The return code * is therefore the difference in lengths. * * i.e. "0x00" is smaller than "0x0000" */ compare = two->length - one->length; } break; case PW_TYPE_STRING: compare = strcmp(two->vp_strvalue, one->vp_strvalue); break; case PW_TYPE_BYTE: case PW_TYPE_SHORT: case PW_TYPE_INTEGER: case PW_TYPE_DATE: compare = two->vp_integer - one->vp_integer; break; case PW_TYPE_IPADDR: compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr); break; case PW_TYPE_IPV6ADDR: compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr, sizeof(two->vp_ipv6addr)); break; case PW_TYPE_IPV6PREFIX: compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix, sizeof(two->vp_ipv6prefix)); break; case PW_TYPE_IFID: compare = memcmp(&two->vp_ifid, &one->vp_ifid, sizeof(two->vp_ifid)); break; default: return 0; /* unknown type */ } /* * Now do the operator comparison. */ switch (one->operator) { case T_OP_CMP_EQ: return (compare == 0); case T_OP_NE: return (compare != 0); case T_OP_LT: return (compare < 0); case T_OP_GT: return (compare > 0); case T_OP_LE: return (compare <= 0); case T_OP_GE: return (compare >= 0); default: return 0; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -