/* * Compare two pair lists except for the password information. * For every element in "check" at least one matching copy must * be present in "reply". * * Return 0 on match. */ int paircmp(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR **reply) { VALUE_PAIR *check_item; VALUE_PAIR *auth_item; int result = 0; int compare; int other; #ifdef HAVE_REGEX_H regex_t reg; #endif for (check_item = check; check_item != NULL; check_item = check_item->next) { /* * If the user is setting a configuration value, * then don't bother comparing it to any attributes * sent to us by the user. It ALWAYS matches. */ if ((check_item->operator == T_OP_SET) || (check_item->operator == T_OP_ADD)) { continue; } switch (check_item->attribute) { /* * Attributes we skip during comparison. * These are "server" check items. */ case PW_CRYPT_PASSWORD: case PW_AUTH_TYPE: case PW_AUTZ_TYPE: case PW_ACCT_TYPE: case PW_SESSION_TYPE: case PW_STRIP_USER_NAME: continue; break; /* * IF the password attribute exists, THEN * we can do comparisons against it. If not, * then the request did NOT contain a * User-Password attribute, so we CANNOT do * comparisons against it. * * This hack makes CHAP-Password work.. */ case PW_PASSWORD: if (pairfind(request, PW_PASSWORD) == NULL) { continue; } break; } /* * See if this item is present in the request. */ other = otherattr(check_item->attribute); auth_item = request; try_again: for (; auth_item != NULL; auth_item = auth_item->next) { if (auth_item->attribute == other || other == 0) break; } /* * Not found, it's not a match. */ if (auth_item == NULL) { /* * Didn't find it. If we were *trying* * to not find it, then we succeeded. */ if (check_item->operator == T_OP_CMP_FALSE) return 0; else return -1; } /* * Else we found it, but we were trying to not * find it, so we failed. */ if (check_item->operator == T_OP_CMP_FALSE) return -1; /* * We've got to xlat the string before doing * the comparison. */ if (check_item->flags.do_xlat) { int rcode; char buffer[sizeof(check_item->strvalue)]; check_item->flags.do_xlat = 0; rcode = radius_xlat(buffer, sizeof(buffer), check_item->strvalue, req, NULL); /* * Parse the string into a new value. */ pairparsevalue(check_item, buffer); } /* * OK it is present now compare them. */ compare = paircompare(req, auth_item, check_item, check, reply); switch (check_item->operator) { case T_OP_EQ: default: radlog(L_ERR, "Invalid operator for item %s: " "reverting to '=='", check_item->name); /*FALLTHRU*/ case T_OP_CMP_TRUE: /* compare always == 0 */ case T_OP_CMP_FALSE: /* compare always == 1 */ case T_OP_CMP_EQ: if (compare != 0) result = -1; break; case T_OP_NE: if (compare == 0) result = -1; break; case T_OP_LT: if (compare >= 0) result = -1; break; case T_OP_GT: if (compare <= 0) result = -1; break; case T_OP_LE: if (compare > 0) result = -1; break; case T_OP_GE: if (compare < 0) result = -1; break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: { int i; regmatch_t rxmatch[9]; /* * Include substring matches. */ regcomp(®, (char *)check_item->strvalue, REG_EXTENDED); compare = regexec(®, (char *)auth_item->strvalue, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); /* * Add %{0}, %{1}, etc. */ for (i = 0; i <= REQUEST_MAX_REGEX; i++) { char *p; char buffer[sizeof(check_item->strvalue)]; /* * Didn't match: delete old * match, if it existed. */ if ((compare != 0) || (rxmatch[i].rm_so == -1)) { p = request_data_get(req, req, REQUEST_DATA_REGEX | i); if (p) { free(p); continue; } /* * No previous match * to delete, stop. */ break; } /* * Copy substring into buffer. */ memcpy(buffer, auth_item->strvalue + rxmatch[i].rm_so, rxmatch[i].rm_eo - rxmatch[i].rm_so); buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; /* * Copy substring, and add it to * the request. * * Note that we don't check * for out of memory, which is * the only error we can get... */ p = strdup(buffer); request_data_add(req, req, REQUEST_DATA_REGEX | i, p, free); } } if (compare != 0) result = -1; break; case T_OP_REG_NE: regcomp(®, (char *)check_item->strvalue, REG_EXTENDED|REG_NOSUB); compare = regexec(®, (char *)auth_item->strvalue, 0, NULL, 0); regfree(®); if (compare == 0) result = -1; break; #endif } /* switch over the operator of the check item */ /* * This attribute didn't match, but maybe there's * another of the same attribute, which DOES match. */ if (result != 0) { auth_item = auth_item->next; result = 0; goto try_again; } } /* for every entry in the check item list */ return 0; /* it matched */ }
/** * @brief Compare two pair lists except for the password information. * * For every element in "check" at least one matching copy must * be present in "reply". * * @param req Current request * @param request request valuepairs * @param check check/control valuepairs * @param[in,out] reply reply value pairs * * @return 0 on match. */ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR **reply) { VALUE_PAIR *check_item; VALUE_PAIR *auth_item; int result = 0; int compare; int other; for (check_item = check; check_item != NULL; check_item = check_item->next) { /* * If the user is setting a configuration value, * then don't bother comparing it to any attributes * sent to us by the user. It ALWAYS matches. */ if ((check_item->operator == T_OP_SET) || (check_item->operator == T_OP_ADD)) { continue; } switch (check_item->attribute) { /* * Attributes we skip during comparison. * These are "server" check items. */ case PW_CRYPT_PASSWORD: case PW_AUTH_TYPE: case PW_AUTZ_TYPE: case PW_ACCT_TYPE: case PW_SESSION_TYPE: case PW_STRIP_USER_NAME: continue; break; /* * IF the password attribute exists, THEN * we can do comparisons against it. If not, * then the request did NOT contain a * User-Password attribute, so we CANNOT do * comparisons against it. * * This hack makes CHAP-Password work.. */ case PW_USER_PASSWORD: if (check_item->operator == T_OP_CMP_EQ) { DEBUG("WARNING: Found User-Password == \"...\"."); DEBUG("WARNING: Are you sure you don't mean Cleartext-Password?"); DEBUG("WARNING: See \"man rlm_pap\" for more information."); } if (pairfind(request, PW_USER_PASSWORD, 0) == NULL) { continue; } break; } /* * See if this item is present in the request. */ other = otherattr(check_item->attribute); auth_item = request; try_again: if (other >= 0) { for (; auth_item != NULL; auth_item = auth_item->next) { if (auth_item->attribute == (unsigned int) other || other == 0) break; } } /* * Not found, it's not a match. */ if (auth_item == NULL) { /* * Didn't find it. If we were *trying* * to not find it, then we succeeded. */ if (check_item->operator == T_OP_CMP_FALSE) continue; else return -1; } /* * Else we found it, but we were trying to not * find it, so we failed. */ if (check_item->operator == T_OP_CMP_FALSE) return -1; /* * We've got to xlat the string before doing * the comparison. */ if (check_item->flags.do_xlat) { int rcode; char buffer[sizeof(check_item->vp_strvalue)]; check_item->flags.do_xlat = 0; rcode = radius_xlat(buffer, sizeof(buffer), check_item->vp_strvalue, req, NULL); /* * Parse the string into a new value. */ pairparsevalue(check_item, buffer); } /* * OK it is present now compare them. */ compare = radius_callback_compare(req, auth_item, check_item, check, reply); switch (check_item->operator) { case T_OP_EQ: default: radlog(L_INFO, "Invalid operator for item %s: " "reverting to '=='", check_item->name); /*FALLTHRU*/ case T_OP_CMP_TRUE: /* compare always == 0 */ case T_OP_CMP_FALSE: /* compare always == 1 */ case T_OP_CMP_EQ: if (compare != 0) result = -1; break; case T_OP_NE: if (compare == 0) result = -1; break; case T_OP_LT: if (compare >= 0) result = -1; break; case T_OP_GT: if (compare <= 0) result = -1; break; case T_OP_LE: if (compare > 0) result = -1; break; case T_OP_GE: if (compare < 0) result = -1; break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: case T_OP_REG_NE: if (compare != 0) result = -1; break; #endif } /* switch over the operator of the check item */ /* * This attribute didn't match, but maybe there's * another of the same attribute, which DOES match. */ if ((result != 0) && (other >= 0)) { auth_item = auth_item->next; result = 0; goto try_again; } } /* for every entry in the check item list */ return result; }
/** Compare two pair lists except for the password information. * * For every element in "check" at least one matching copy must be present * in "reply". * * @param[in] request Current request. * @param[in] req_list request valuepairs. * @param[in] check Check/control valuepairs. * @param[in,out] rep_list Reply value pairs. * * @return 0 on match. */ int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check, VALUE_PAIR **rep_list) { vp_cursor_t cursor; VALUE_PAIR *check_item; VALUE_PAIR *auth_item; DICT_ATTR const *from; int result = 0; int compare; bool first_only; for (check_item = paircursor(&cursor, &check); check_item; check_item = pairnext(&cursor)) { /* * If the user is setting a configuration value, * then don't bother comparing it to any attributes * sent to us by the user. It ALWAYS matches. */ if ((check_item->op == T_OP_SET) || (check_item->op == T_OP_ADD)) { continue; } if (!check_item->da->vendor) switch (check_item->da->attr) { /* * Attributes we skip during comparison. * These are "server" check items. */ case PW_CRYPT_PASSWORD: case PW_AUTH_TYPE: case PW_AUTZ_TYPE: case PW_ACCT_TYPE: case PW_SESSION_TYPE: case PW_STRIP_USER_NAME: continue; break; /* * IF the password attribute exists, THEN * we can do comparisons against it. If not, * then the request did NOT contain a * User-Password attribute, so we CANNOT do * comparisons against it. * * This hack makes CHAP-Password work.. */ case PW_USER_PASSWORD: if (check_item->op == T_OP_CMP_EQ) { WDEBUG("Found User-Password == \"...\"."); WDEBUG("Are you sure you don't mean Cleartext-Password?"); WDEBUG("See \"man rlm_pap\" for more information"); } if (pairfind(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) { continue; } break; } /* * See if this item is present in the request. */ first_only = otherattr(check_item->da, &from); auth_item = req_list; try_again: if (!first_only) { while (auth_item != NULL) { if ((auth_item->da == from) || (!from)) { break; } auth_item = auth_item->next; } } /* * Not found, it's not a match. */ if (auth_item == NULL) { /* * Didn't find it. If we were *trying* * to not find it, then we succeeded. */ if (check_item->op == T_OP_CMP_FALSE) { continue; } else { return -1; } } /* * Else we found it, but we were trying to not * find it, so we failed. */ if (check_item->op == T_OP_CMP_FALSE) { return -1; } /* * We've got to xlat the string before doing * the comparison. */ radius_xlat_do(request, check_item); /* * OK it is present now compare them. */ compare = radius_callback_compare(request, auth_item, check_item, check, rep_list); switch (check_item->op) { case T_OP_EQ: default: INFO("Invalid operator for item %s: " "reverting to '=='", check_item->da->name); /* FALL-THROUGH */ case T_OP_CMP_TRUE: case T_OP_CMP_FALSE: case T_OP_CMP_EQ: if (compare != 0) result = -1; break; case T_OP_NE: if (compare == 0) result = -1; break; case T_OP_LT: if (compare >= 0) result = -1; break; case T_OP_GT: if (compare <= 0) result = -1; break; case T_OP_LE: if (compare > 0) result = -1; break; case T_OP_GE: if (compare < 0) result = -1; break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: case T_OP_REG_NE: if (compare != 0) result = -1; break; #endif } /* switch over the operator of the check item */ /* * This attribute didn't match, but maybe there's * another of the same attribute, which DOES match. */ if ((result != 0) && (!first_only)) { auth_item = auth_item->next; result = 0; goto try_again; } } /* for every entry in the check item list */ return result; }