static VALUE_PAIR *rlm_ldap_map_getvalue(REQUEST *request, value_pair_map_t const *map, void *ctx) { rlm_ldap_result_t *self = ctx; VALUE_PAIR *head = NULL, *vp; vp_cursor_t out; int i; paircursor(&out, &head); /* * Iterate over all the retrieved values, * don't try and be clever about changing operators * just use whatever was set in the attribute map. */ for (i = 0; i < self->count; i++) { vp = pairalloc(request, map->dst->da); rad_assert(vp); if (!pairparsevalue(vp, self->values[i])) { RDEBUG("Failed parsing value for \"%s\"", map->dst->da->name); pairbasicfree(vp); continue; } vp->op = map->op; pairinsert(&out, vp); } return head; }
static void cleanresp(RADIUS_PACKET *resp) { VALUE_PAIR *vpnext, *vp, **last; /* * maybe should just copy things we care about, or keep * a copy of the original input and start from there again? */ pairdelete(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY); pairdelete(&resp->vps, ATTRIBUTE_EAP_BASE+PW_EAP_IDENTITY, 0, TAG_ANY); last = &resp->vps; for(vp = *last; vp != NULL; vp = vpnext) { vpnext = vp->next; if((vp->da->attribute > ATTRIBUTE_EAP_BASE && vp->da->attribute <= ATTRIBUTE_EAP_BASE+256) || (vp->da->attribute > ATTRIBUTE_EAP_SIM_BASE && vp->da->attribute <= ATTRIBUTE_EAP_SIM_BASE+256)) { *last = vpnext; pairbasicfree(vp); } else { last = &vp->next; } } }
/** Replace all matching VPs * * Walks over 'first', and replaces the first VP that matches 'replace'. * * @note Memory used by the VP being replaced will be freed. * @note Will not work with unknown attributes. * * @param[in,out] first VP in linked list. Will search and replace in this list. * @param[in] replace VP to replace. * @return a copy of the input vp */ void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace) { VALUE_PAIR *i, *next; VALUE_PAIR **prev = first; VERIFY(replace); if (*first == NULL) { *first = replace; return; } /* * Not an empty list, so find item if it is there, and * replace it. Note, we always replace the first one, and * we ignore any others that might exist. */ for(i = *first; i; i = next) { VERIFY(i); next = i->next; /* * Found the first attribute, replace it, * and return. */ if ((i->da == replace->da) && (!i->da->flags.has_tag || (i->tag == replace->tag)) ) { *prev = replace; /* * Should really assert that replace->next == NULL */ replace->next = next; pairbasicfree(i); return; } /* * Point to where the attribute should go. */ prev = &i->next; } /* * If we got here, we didn't find anything to replace, so * stopped at the last item, which we just append to. */ *prev = replace; }
/* * Delete the pair(s) with the matching attribute */ void pairdelete(VALUE_PAIR **first, int attr) { VALUE_PAIR *i, *next; VALUE_PAIR **last = first; for(i = *first; i; i = next) { next = i->next; if (i->attribute == attr) { *last = next; pairbasicfree(i); } else { last = &i->next; } } }
/* * Release the memory used by a list of attribute-value * pairs, and sets the pair pointer to NULL. */ void pairfree(VALUE_PAIR **pair_ptr) { VALUE_PAIR *next, *pair; if (!pair_ptr) return; pair = *pair_ptr; while (pair != NULL) { next = pair->next; pairbasicfree(pair); pair = next; } *pair_ptr = NULL; }
/* * Delete the pair(s) with the matching attribute */ void pairdelete(VALUE_PAIR **first, unsigned int attr, unsigned int vendor) { VALUE_PAIR *i, *next; VALUE_PAIR **last = first; for(i = *first; i; i = next) { next = i->next; if ((i->attribute == attr) && (i->vendor == vendor)) { *last = next; pairbasicfree(i); } else { last = &i->next; } } }
/** Copy a single valuepair * * Allocate a new valuepair and copy the da from the old vp. * * @param[in] ctx for talloc * @param[in] vp to copy. * @return a copy of the input VP or NULL on error. */ VALUE_PAIR *paircopyvp(TALLOC_CTX *ctx, VALUE_PAIR const *vp) { VALUE_PAIR *n; if (!vp) return NULL; VERIFY(vp); n = pairalloc(ctx, vp->da); if (!n) { fr_strerror_printf("out of memory"); return NULL; } memcpy(n, vp, sizeof(*n)); /* * Now copy the value */ if (vp->type == VT_XLAT) { n->value.xlat = talloc_strdup(n, n->value.xlat); } n->da = dict_attr_copy(vp->da, true); if (!n->da) { pairbasicfree(n); return NULL; } n->next = NULL; if ((n->da->type == PW_TYPE_TLV) || (n->da->type == PW_TYPE_OCTETS)) { if (n->vp_octets != NULL) { n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length); } } else if (n->da->type == PW_TYPE_STRING) { if (n->vp_strvalue != NULL) { /* * Equivalent to, and faster than strdup. */ n->vp_strvalue = talloc_memdup(n, vp->vp_octets, n->length + 1); } } return n; }
/** Free memory used by a valuepair list. * * @todo TLV: needs to free all dependents of each VP freed. */ void pairfree(VALUE_PAIR **vps) { VALUE_PAIR *next, *vp; if (!vps) return; vp = *vps; while (vp) { VERIFY(vp); next = vp->next; pairbasicfree(vp); vp = next; } *vps = NULL; }
/** Delete matching pairs * * Delete matching pairs from the attribute list. * * @param[in+out] vp which is head of the list. * @param[in] attr to match. * @param[in] vendor to match. * @param[in] tag to match, only used if > 0. */ void pairdelete(VALUE_PAIR **first, unsigned int attr, unsigned int vendor, int8_t tag) { VALUE_PAIR *i, *next; VALUE_PAIR **last = first; for(i = *first; i; i = next) { next = i->next; if ((i->attribute == attr) && (i->vendor == vendor) && ((tag < 0) || (i->flags.has_tag && (i->flags.tag == tag)))) { *last = next; pairbasicfree(i); } else { last = &i->next; } } }
/* * 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; 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]) { fr_strerror_printf("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 { fr_strerror_printf("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) { fr_strerror_printf("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) { fr_strerror_printf("Duplicate tag %s for attribute %s", value, vp->name); DEBUG("Duplicate tag %s for attribute %s\n", value, vp->name); pairbasicfree(vp); 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 (!value) { fr_strerror_printf("No regular expression found in %s", vp->name); pairbasicfree(vp); return NULL; } strlcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue)); vp->length = strlen(vp->vp_strvalue); /* * If anything goes wrong, this is a run-time error, * not a compile-time error. */ return vp; } /* * 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; }
static int do_attr_rewrite(void *instance, REQUEST *request) { rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance; int ret = RLM_MODULE_NOOP; VALUE_PAIR *attr_vp = NULL; VALUE_PAIR *tmp = NULL; regex_t preg; regmatch_t pmatch[9]; int cflags = 0; int err = 0; char done_xlat = 0; unsigned int len = 0; char err_msg[MAX_STRING_LEN]; unsigned int i = 0; unsigned int j = 0; unsigned int counter = 0; char new_str[MAX_STRING_LEN]; char *ptr, *ptr2; char search_STR[MAX_STRING_LEN]; char replace_STR[MAX_STRING_LEN]; if ((attr_vp = pairfind(request->config_items, PW_REWRITE_RULE)) != NULL){ if (data->name == NULL || strcmp(data->name,attr_vp->vp_strvalue)) return RLM_MODULE_NOOP; } if (data->new_attr){ /* new_attribute = yes */ if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) { DEBUG2("%s: xlat on replace string failed.", data->name); return ret; } attr_vp = pairmake(data->attribute,replace_STR,0); if (attr_vp == NULL){ DEBUG2("%s: Could not add new attribute %s with value '%s'", data->name, data->attribute,replace_STR); return ret; } switch(data->searchin){ case RLM_REGEX_INPACKET: pairadd(&request->packet->vps,attr_vp); break; case RLM_REGEX_INCONFIG: pairadd(&request->config_items,attr_vp); break; case RLM_REGEX_INREPLY: pairadd(&request->reply->vps,attr_vp); break; case RLM_REGEX_INPROXY: if (!request->proxy) { pairbasicfree(attr_vp); return RLM_MODULE_NOOP; } pairadd(&request->proxy->vps, attr_vp); break; case RLM_REGEX_INPROXYREPLY: if (!request->proxy_reply) { pairbasicfree(attr_vp); return RLM_MODULE_NOOP; } pairadd(&request->proxy_reply->vps, attr_vp); break; default: radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name); data->searchin = RLM_REGEX_INPACKET; pairadd(&request->packet->vps,attr_vp); break; } DEBUG2("%s: Added attribute %s with value '%s'", data->name,data->attribute,replace_STR); ret = RLM_MODULE_OK; } else { int replace_len = 0; /* new_attribute = no */ switch (data->searchin) { case RLM_REGEX_INPACKET: if (data->attr_num == PW_USER_NAME) attr_vp = request->username; else if (data->attr_num == PW_USER_PASSWORD) attr_vp = request->password; else tmp = request->packet->vps; break; case RLM_REGEX_INCONFIG: tmp = request->config_items; break; case RLM_REGEX_INREPLY: tmp = request->reply->vps; break; case RLM_REGEX_INPROXYREPLY: if (!request->proxy_reply) return RLM_MODULE_NOOP; tmp = request->proxy_reply->vps; break; case RLM_REGEX_INPROXY: if (!request->proxy) return RLM_MODULE_NOOP; tmp = request->proxy->vps; break; default: radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name); data->searchin = RLM_REGEX_INPACKET; attr_vp = pairfind(request->packet->vps, data->attr_num); break; } do_again: if (tmp != NULL) attr_vp = pairfind(tmp, data->attr_num); if (attr_vp == NULL) { DEBUG2("%s: Could not find value pair for attribute %s", data->name,data->attribute); return ret; } if (attr_vp->vp_strvalue == NULL || attr_vp->length == 0){ DEBUG2("%s: Attribute %s string value NULL or of zero length", data->name,data->attribute); return ret; } cflags |= REG_EXTENDED; if (data->nocase) cflags |= REG_ICASE; if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL) && data->search_len != 0) { DEBUG2("%s: xlat on search string failed.", data->name); return ret; } if ((err = regcomp(&preg,search_STR,cflags))) { regerror(err, &preg, err_msg, MAX_STRING_LEN); DEBUG2("%s: regcomp() returned error: %s", data->name,err_msg); return ret; } if ((attr_vp->type == PW_TYPE_IPADDR) && (attr_vp->vp_strvalue[0] == '\0')) { inet_ntop(AF_INET, &(attr_vp->vp_ipaddr), attr_vp->vp_strvalue, sizeof(attr_vp->vp_strvalue)); } ptr = new_str; ptr2 = attr_vp->vp_strvalue; counter = 0; for ( i = 0 ;i < (unsigned)data->num_matches; i++) { err = regexec(&preg, ptr2, REQUEST_MAX_REGEX, pmatch, 0); if (err == REG_NOMATCH) { if (i == 0) { DEBUG2("%s: Does not match: %s = %s", data->name, data->attribute, attr_vp->vp_strvalue); regfree(&preg); goto to_do_again; } else break; } if (err != 0) { regfree(&preg); radlog(L_ERR, "%s: match failure for attribute %s with value '%s'", data->name, data->attribute, attr_vp->vp_strvalue); return ret; } if (pmatch[0].rm_so == -1) break; len = pmatch[0].rm_so; if (data->append) { len = len + (pmatch[0].rm_eo - pmatch[0].rm_so); } counter += len; if (counter >= MAX_STRING_LEN) { regfree(&preg); DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name, data->attribute, attr_vp->vp_strvalue); return ret; } memcpy(ptr, ptr2,len); ptr += len; *ptr = '\0'; ptr2 += pmatch[0].rm_eo; if (i == 0){ /* * We only run on the first match, sorry */ for(j = 0; j <= REQUEST_MAX_REGEX; j++){ char *p; char buffer[sizeof(attr_vp->vp_strvalue)]; /* * Stolen from src/main/valuepair.c, paircompare() */ /* * Delete old matches if the corresponding match does not * exist in the current regex */ if (pmatch[j].rm_so == -1){ p = request_data_get(request,request,REQUEST_DATA_REGEX | j); if (p){ free(p); continue; } break; } memcpy(buffer, attr_vp->vp_strvalue + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so); buffer[pmatch[j].rm_eo - pmatch[j].rm_so] = '\0'; p = strdup(buffer); request_data_add(request,request,REQUEST_DATA_REGEX | j,p,free); } } if (!done_xlat){ if (data->replace_len != 0 && radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL) == 0) { DEBUG2("%s: xlat on replace string failed.", data->name); return ret; } replace_len = (data->replace_len != 0) ? strlen(replace_STR) : 0; done_xlat = 1; } counter += replace_len; if (counter >= MAX_STRING_LEN) { regfree(&preg); DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name, data->attribute, attr_vp->vp_strvalue); return ret; } if (replace_len){ memcpy(ptr, replace_STR, replace_len); ptr += replace_len; *ptr = '\0'; } } regfree(&preg); len = strlen(ptr2) + 1; /* We add the ending NULL */ counter += len; if (counter >= MAX_STRING_LEN){ DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name, data->attribute, attr_vp->vp_strvalue); return ret; } memcpy(ptr, ptr2, len); ptr[len] = '\0'; DEBUG2("%s: Changed value for attribute %s from '%s' to '%s'", data->name, data->attribute, attr_vp->vp_strvalue, new_str); if (pairparsevalue(attr_vp, new_str) == NULL) { DEBUG2("%s: Could not write value '%s' into attribute %s: %s", data->name, new_str, data->attribute, fr_strerror()); return ret; } to_do_again: ret = RLM_MODULE_OK; if (tmp != NULL){ tmp = attr_vp->next; if (tmp != NULL) goto do_again; } } return ret; }
/** Print out attribute info * * Prints out all instances of a current attribute, or all attributes in a list. * * At higher debugging levels, also prints out alternative decodings of the same * value. This is helpful to determine types for unknown attributes of long * passed vendors, or just crazy/broken NAS. * * It's also useful for exposing issues in the packet decoding functions, as in * some cases they get fed random garbage data. * * This expands to a zero length string. */ static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, UNUSED size_t outlen) { VALUE_PAIR *vp, **vps; value_pair_tmpl_t vpt; vp_cursor_t cursor; char buffer[1024]; if (!RDEBUG_ENABLED2) { *out = '\0'; return -1; } while (isspace((int) *fmt)) fmt++; if (*fmt == '&') fmt++; if (radius_parse_attr(fmt, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) { return -1; } vps = radius_list(request, vpt.list); if (!vps) { return -2; } RIDEBUG("Attributes matching \"%s\"", fmt); vp = paircursor(&cursor, vps); if (vpt.da) { vp = pairfindnext(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY); } while (vp) { DICT_ATTR *dac = NULL; DICT_VENDOR *dv; VALUE_PAIR *vpc = NULL; FR_NAME_NUMBER const *type; vp_prints_value(buffer, sizeof(buffer), vp, '\''); if (vp->da->flags.has_tag) { RIDEBUG2("\t%s:%s:%i %s %s", fr_int2str(pair_lists, vpt.list, "<INVALID>"), vp->da->name, vp->tag, fr_int2str(fr_tokens, vp->op, "<INVALID>"), buffer); } else { RIDEBUG2("\t%s:%s %s %s", fr_int2str(pair_lists, vpt.list, "<INVALID>"), vp->da->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), buffer); } if (!RDEBUG_ENABLED3) { goto next_vp; } if (vp->da->vendor) { dv = dict_vendorbyvalue(vp->da->vendor); RDEBUG3("\t\tvendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown"); } RDEBUG3("\t\ttype : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>")); RDEBUG3("\t\tlength : %zu", vp->length); dac = talloc_memdup(request, vp->da, sizeof(DICT_ATTR)); if (!dac) { return -1; } dac->flags.vp_free = 0; if (!RDEBUG_ENABLED4) { goto next_vp; } type = dict_attr_types; while (type->name) { int pad; ssize_t len; uint8_t *data = NULL; vpc = NULL; if ((PW_TYPE) type->number == vp->da->type) { goto next_type; } switch (type->number) { case PW_TYPE_INVALID: /* Not real type */ case PW_TYPE_MAX: /* Not real type */ case PW_TYPE_EXTENDED: /* Not safe/appropriate */ case PW_TYPE_LONG_EXTENDED: /* Not safe/appropriate */ case PW_TYPE_TLV: /* Not safe/appropriate */ case PW_TYPE_VSA: /* @fixme We need special behaviour for these */ goto next_type; default: break; } dac->type = type->number; data = talloc_array(request, uint8_t , vp->length); len = rad_vp2data(vp, data, vp->length); if (data2vp(NULL, NULL, NULL, dac, data, len, len, &vpc) < 0) { goto next_type; } /* * data2vp has knowledge of expected format lengths, if the length * from rad_vp2data doesn't match, it encodes the attribute * as raw octets. This results in many useless debug lines with * the same hex string. */ if ((type->number != PW_TYPE_OCTETS) && (vpc->da->type == PW_TYPE_OCTETS)) { goto next_type; } if (!vp_prints_value(buffer, sizeof(buffer), vpc, '\'')) { goto next_type; } if ((pad = (11 - strlen(type->name))) < 0) { pad = 0; } /* * @fixme: if the value happens to decode as a VSA * (someone put a VSA into a VSA?), we probably to print * extended info for that/reparse */ RDEBUG4("\t\tas %s%*s: %s", type->name, pad, " ", buffer); next_type: talloc_free(data); pairbasicfree(vpc); type++; } next_vp: talloc_free(dac); if (vpt.da) { vp = pairfindnext(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY); } else { vp = pairnext(&cursor); } } *out = '\0'; return 0; }
/* * *presult is "did comparison match or not" */ static int radius_do_cmp(REQUEST *request, int *presult, FR_TOKEN lt, const char *pleft, FR_TOKEN token, UNUSED FR_TOKEN rt, const char *pright, #ifdef HAVE_REGEX_H int cflags, #else UNUSED int cflags, #endif int modreturn) { int result; uint32_t lint, rint; VALUE_PAIR *vp = NULL; #ifdef HAVE_REGEX_H char buffer[8192]; #endif if (lt == T_BARE_WORD) { /* * Maybe check the last return code. */ if (token == T_OP_CMP_TRUE) { int isreturn; /* * Looks like a return code, treat is as such. */ isreturn = fr_str2int(modreturn_table, pleft, -1); if (isreturn != -1) { *presult = (modreturn == isreturn); return TRUE; } } /* * Bare words on the left can be attribute names. */ if (!(radius_get_vp(request, pleft, &vp) < 0)) { VALUE_PAIR *myvp; /* * VP exists, and that's all we're looking for. */ if (token == T_OP_CMP_TRUE) { *presult = (vp != NULL); return TRUE; } if (!vp) { const DICT_ATTR *da; /* * The attribute on the LHS may * have been a dynamically * registered callback. i.e. it * doesn't exist as a VALUE_PAIR. * If so, try looking for it. */ da = dict_attrbyname(pleft); if (da && (da->vendor == 0) && radius_find_compare(da->attr)) { VALUE_PAIR *check; check = pairmake(request, NULL, pleft, pright, token); *presult = (radius_callback_compare(request, NULL, check, NULL, NULL) == 0); RDEBUG3(" Callback returns %d", *presult); pairfree(&check); return TRUE; } RDEBUG2(" (Attribute %s was not found)", pleft); *presult = 0; return TRUE; } #ifdef HAVE_REGEX_H /* * Regex comparisons treat everything as * strings. */ if ((token == T_OP_REG_EQ) || (token == T_OP_REG_NE)) { vp_prints_value(buffer, sizeof(buffer), vp, 0); pleft = buffer; goto do_checks; } #endif myvp = paircopyvp(request, vp); if (!pairparsevalue(myvp, pright)) { pairbasicfree(myvp); RDEBUG2("Failed parsing \"%s\": %s", pright, fr_strerror()); return FALSE; } myvp->op = token; *presult = paircmp(myvp, vp); pairbasicfree(myvp); RDEBUG3(" paircmp -> %d", *presult); return TRUE; } /* else it's not a VP in a list */ } #ifdef HAVE_REGEX_H do_checks: #endif switch (token) { case T_OP_GE: case T_OP_GT: case T_OP_LE: case T_OP_LT: if (!all_digits(pright)) { RDEBUG2(" (Right field is not a number at: %s)", pright); return FALSE; } rint = strtoul(pright, NULL, 0); if (!all_digits(pleft)) { RDEBUG2(" (Left field is not a number at: %s)", pleft); return FALSE; } lint = strtoul(pleft, NULL, 0); break; default: lint = rint = 0; /* quiet the compiler */ break; } switch (token) { case T_OP_CMP_TRUE: /* * Check for truth or falsehood. */ if (all_digits(pleft)) { lint = strtoul(pleft, NULL, 0); result = (lint != 0); } else { result = (*pleft != '\0'); } break; case T_OP_CMP_EQ: result = (strcmp(pleft, pright) == 0); break; case T_OP_NE: result = (strcmp(pleft, pright) != 0); break; case T_OP_GE: result = (lint >= rint); break; case T_OP_GT: result = (lint > rint); break; case T_OP_LE: result = (lint <= rint); break; case T_OP_LT: result = (lint < rint); break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: { int i, compare; regex_t reg; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* * Include substring matches. */ compare = regcomp(®, pright, cflags); if (compare != 0) { if (debug_flag) { char errbuf[128]; regerror(compare, ®, errbuf, sizeof(errbuf)); DEBUGE("Failed compiling regular expression: %s", errbuf); } return FALSE; } compare = regexec(®, pleft, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); /* * Add new %{0}, %{1}, etc. */ if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) { char *r; free(request_data_get(request, request, REQUEST_DATA_REGEX | i)); /* * No %{i}, skip it. * We MAY have %{2} without %{1}. */ if (rxmatch[i].rm_so == -1) continue; /* * Copy substring into allocated buffer */ r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1); memcpy(r, pleft + rxmatch[i].rm_so, rxmatch[i].rm_eo - rxmatch[i].rm_so); r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; request_data_add(request, request, REQUEST_DATA_REGEX | i, r, free); } result = (compare == 0); } break; case T_OP_REG_NE: { int compare; regex_t reg; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* * Include substring matches. */ compare = regcomp(®, pright, cflags); if (compare != 0) { if (debug_flag) { char errbuf[128]; regerror(compare, ®, errbuf, sizeof(errbuf)); DEBUGE("Failed compiling regular expression: %s", errbuf); } return FALSE; } compare = regexec(®, pleft, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); result = (compare != 0); } break; #endif default: DEBUGE("Comparison operator %s is not supported", fr_token_name(token)); result = FALSE; break; } *presult = result; return TRUE; }
/************************************************************************* * * Function: sql_userparse * * Purpose: Read entries from the database and fill VALUE_PAIR structures * *************************************************************************/ int sql_userparse(TALLOC_CTX *ctx, VALUE_PAIR **head, rlm_sql_row_t row) { VALUE_PAIR *vp; char const *ptr, *value; char buf[MAX_STRING_LEN]; char do_xlat = 0; FR_TOKEN token, operator = T_EOL; /* * Verify the 'Attribute' field */ if (!row[2] || row[2][0] == '\0') { ERROR("rlm_sql: The 'Attribute' field is empty or NULL, skipping the entire row"); return -1; } /* * Verify the 'op' field */ if (row[4] != NULL && row[4][0] != '\0') { ptr = row[4]; operator = gettoken(&ptr, buf, sizeof(buf)); if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) { ERROR("rlm_sql: Invalid operator \"%s\" for attribute %s", row[4], row[2]); return -1; } } else { /* * Complain about empty or invalid 'op' field */ operator = T_OP_CMP_EQ; ERROR("rlm_sql: The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]); ERROR("rlm_sql: You MUST FIX THIS if you want the configuration to behave as you expect"); } /* * The 'Value' field may be empty or NULL */ value = row[3]; /* * If we have a new-style quoted string, where the * *entire* string is quoted, do xlat's. */ if (row[3] != NULL && ((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) && (row[3][0] == row[3][strlen(row[3])-1])) { token = gettoken(&value, buf, sizeof(buf)); switch (token) { /* * Take the unquoted string. */ case T_SINGLE_QUOTED_STRING: case T_DOUBLE_QUOTED_STRING: value = buf; break; /* * Mark the pair to be allocated later. */ case T_BACK_QUOTED_STRING: value = NULL; do_xlat = 1; break; /* * Keep the original string. */ default: value = row[3]; break; } } /* * Create the pair */ vp = pairmake(ctx, NULL, row[2], NULL, operator); if (!vp) { ERROR("rlm_sql: Failed to create the pair: %s", fr_strerror()); return -1; } if (do_xlat) { if (pairmark_xlat(vp, value) < 0) { ERROR("rlm_sql: Error marking pair for xlat"); pairbasicfree(vp); return -1; } } else { if (!pairparsevalue(vp, value)) { ERROR("rlm_sql: Error parsing value"); pairbasicfree(vp); return -1; } } /* * Add the pair into the packet */ pairadd(head, vp); return 0; }