📄 evaluate.c
字号:
radlog(L_ERR, "Unexpected trailing text at: %s", p); return FALSE; } } /* else it wasn't an opening brace */ while ((*p == ' ') || (*p == '\t')) p++; /* * More conditions, keep going. */ if ((*p == '(') || (p[0] == '!')) continue; DEBUG4(">>> LOOKING AT %s", p); start = p; /* * Look for common errors. */ if ((p[0] == '%') && (p[1] == '{')) { radlog(L_ERR, "Bare %%{...} is invalid in condition at: %s", p); return FALSE; } /* * Look for word == value */ lt = gettoken(&p, left, sizeof(left)); if ((lt != T_BARE_WORD) && (lt != T_DOUBLE_QUOTED_STRING) && (lt != T_SINGLE_QUOTED_STRING) && (lt != T_BACK_QUOTED_STRING)) { radlog(L_ERR, "Expected string or numbers at: %s", p); return FALSE; } pleft = left; if (evaluate_next_condition) { pleft = expand_string(xleft, sizeof(xleft), request, lt, left); if (!pleft) { radlog(L_ERR, "Failed expanding string at: %s", left); return FALSE; } } /* * Peek ahead. Maybe it's just a check for * existence. If so, there shouldn't be anything * else. */ q = p; while ((*q == ' ') || (*q == '\t')) q++; /* * End of condition, */ if (!*q || (*q == ')') || ((*q == '!') && (q[1] != '=') && (q[1] != '~')) || ((q[0] == '&') && (q[1] == '&')) || ((q[0] == '|') && (q[1] == '|'))) { /* * Simplify the code. */ token = T_OP_CMP_TRUE; rt = T_OP_INVALID; pright = NULL; goto do_cmp; } /* * Else it's a full "foo == bar" thingy. */ token = gettoken(&p, comp, sizeof(comp)); if ((token < T_OP_NE) || (token > T_OP_CMP_EQ) || (token == T_OP_CMP_TRUE) || (token == T_OP_CMP_FALSE)) { radlog(L_ERR, "Expected comparison at: %s", comp); return FALSE; } /* * Look for common errors. */ if ((p[0] == '%') && (p[1] == '{')) { radlog(L_ERR, "Bare %%{...} is invalid in condition at: %s", p); return FALSE; } /* * Validate strings. */#ifdef HAVE_REGEX_H if ((token == T_OP_REG_EQ) || (token == T_OP_REG_NE)) { rt = getregex(&p, right, sizeof(right), &cflags); if (rt != T_DOUBLE_QUOTED_STRING) { radlog(L_ERR, "Expected regular expression at: %s", p); return FALSE; } } else#endif rt = gettoken(&p, right, sizeof(right)); if ((rt != T_BARE_WORD) && (rt != T_DOUBLE_QUOTED_STRING) && (rt != T_SINGLE_QUOTED_STRING) && (rt != T_BACK_QUOTED_STRING)) { radlog(L_ERR, "Expected string or numbers at: %s", p); return FALSE; } pright = right; if (evaluate_next_condition) { pright = expand_string(xright, sizeof(xright), request, rt, right); if (!pright) { radlog(L_ERR, "Failed expanding string at: %s", right); return FALSE; } } DEBUG4(">>> %d:%s %d %d:%s", lt, pleft, token, rt, pright); do_cmp: if (evaluate_next_condition) { /* * More parse errors. */ if (!radius_do_cmp(request, &result, lt, pleft, token, rt, pright, cflags, modreturn)) { return FALSE; } DEBUG2("%.*s Evaluating %s(%.*s) -> %s", depth, filler, invert ? "!" : "", p - start, start, (result != FALSE) ? "TRUE" : "FALSE"); DEBUG4(">>> GOT result %d", result); /* * Not evaluating it. We may be just * parsing it. */ } else if (request) { DEBUG2("%.*s Skipping %s(%.*s)", depth, filler, invert ? "!" : "", p - start, start); } if (invert) { DEBUG4(">>> INVERTING result"); result = (result == FALSE); invert = FALSE; } /* * Don't evaluate it. */ DEBUG4(">>> EVALUATE %d ::%s::", evaluate_next_condition, p); while ((*p == ' ') || (*p == '\t')) p++; /* * Closing brace or EOL, return. */ if (!*p || (*p == ')') || ((*p == '!') && (p[1] != '=') && (p[1] != '~')) || ((p[0] == '&') && (p[1] == '&')) || ((p[0] == '|') && (p[1] == '|'))) { DEBUG4(">>> AT EOL2a"); *ptr = p; if (evaluate_next_condition) *presult = result; return TRUE; } } /* loop over the input condition */ DEBUG4(">>> AT EOL2b"); *ptr = p; if (evaluate_next_condition) *presult = result; return TRUE;}static void fix_up(REQUEST *request){ VALUE_PAIR *vp; request->username = NULL; request->password = NULL; for (vp = request->packet->vps; vp != NULL; vp = vp->next) { if ((vp->attribute == PW_USER_NAME) && !request->username) { request->username = vp; } else if (vp->attribute == PW_STRIPPED_USER_NAME) { request->username = vp; } else if (vp->attribute == PW_USER_PASSWORD) { request->password = vp; } }}/* * The pairmove() function in src/lib/valuepair.c does all sorts of * extra magic that we don't want here. * * FIXME: integrate this with the code calling it, so that we * only paircopy() those attributes that we're really going to * use. */void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from){ int i, j, count, from_count, to_count, tailto; VALUE_PAIR *vp, *next, **last; VALUE_PAIR **from_list, **to_list; int *edited = NULL; /* * Set up arrays for editing, to remove some of the * O(N^2) dependencies. This also makes it easier to * insert and remove attributes. * * It also means that the operators apply ONLY to the * attributes in the original list. With the previous * implementation of pairmove(), adding two attributes * via "+=" and then "=" would mean that the second one * wasn't added, because of the existence of the first * one in the "to" list. This implementation doesn't * have that bug. * * Also, the previous implementation did NOT implement * "-=" correctly. If two of the same attributes existed * in the "to" list, and you tried to subtract something * matching the *second* value, then the pairdelete() * function was called, and the *all* attributes of that * number were deleted. With this implementation, only * the matching attributes are deleted. */ count = 0; for (vp = from; vp != NULL; vp = vp->next) count++; from_list = rad_malloc(sizeof(*from_list) * count); for (vp = *to; vp != NULL; vp = vp->next) count++; to_list = rad_malloc(sizeof(*to_list) * count); /* * Move the lists to the arrays, and break the list * chains. */ from_count = 0; for (vp = from; vp != NULL; vp = next) { next = vp->next; from_list[from_count++] = vp; vp->next = NULL; } to_count = 0; for (vp = *to; vp != NULL; vp = next) { next = vp->next; to_list[to_count++] = vp; vp->next = NULL; } tailto = to_count; edited = rad_malloc(sizeof(*edited) * to_count); memset(edited, 0, sizeof(*edited) * to_count); DEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count); /* * Now that we have the lists initialized, start working * over them. */ for (i = 0; i < from_count; i++) { int found; DEBUG4("::: Examining %s", from_list[i]->name); /* * Attribute should be appended, OR the "to" list * is empty, and we're supposed to replace or * "add if not existing". */ if (from_list[i]->operator == T_OP_ADD) goto append; found = FALSE; for (j = 0; j < to_count; j++) { if (edited[j]) continue; /* * Attributes aren't the same, skip them. */ if (from_list[i]->attribute != to_list[j]->attribute) { continue; } /* * We don't use a "switch" statement here * because we want to break out of the * "for" loop over 'j' in most cases. */ /* * Over-write the FIRST instance of the * matching attribute name. We free the * one in the "to" list, and move over * the one in the "from" list. */ if (from_list[i]->operator == T_OP_SET) { DEBUG4("::: OVERWRITING %s FROM %d TO %d", to_list[j]->name, i, j); pairfree(&to_list[j]); to_list[j] = from_list[i]; from_list[i] = NULL; edited[j] = TRUE; break; } /* * Add the attribute only if it does not * exist... but it exists, so we stop * looking. */ if (from_list[i]->operator == T_OP_EQ) { found = TRUE; break; } /* * Delete all matching attributes from * "to" */ if ((from_list[i]->operator == T_OP_SUB) || (from_list[i]->operator == T_OP_CMP_EQ) || (from_list[i]->operator == T_OP_LE) || (from_list[i]->operator == T_OP_GE)) { int rcode; int old_op = from_list[i]->operator; /* * Check for equality. */ from_list[i]->operator = T_OP_CMP_EQ; /* * If equal, delete the one in * the "to" list. */ rcode = radius_compare_vps(NULL, from_list[i], to_list[j]); /* * We may want to do more * subtractions, so we re-set the * operator back to it's original * value. */ from_list[i]->operator = old_op; switch (old_op) { case T_OP_CMP_EQ: if (rcode != 0) goto delete; break; case T_OP_SUB: if (rcode == 0) { delete: DEBUG4("::: DELETING %s FROM %d TO %d", from_list[i]->name, i, j); pairfree(&to_list[j]); to_list[j] = NULL; } break; /* * Enforce <=. If it's * >, replace it. */ case T_OP_LE: if (rcode > 0) { DEBUG4("::: REPLACING %s FROM %d TO %d", from_list[i]->name, i, j); pairfree(&to_list[j]); to_list[j] = from_list[i]; from_list[i] = NULL; edited[j] = TRUE; } break; case T_OP_GE: if (rcode < 0) { DEBUG4("::: REPLACING %s FROM %d TO %d", from_list[i]->name, i, j); pairfree(&to_list[j]); to_list[j] = from_list[i]; from_list[i] = NULL; edited[j] = TRUE; } break; } continue; } rad_assert(0 == 1); /* panic! */ } /* * We were asked to add it if it didn't exist, * and it doesn't exist. Move it over to the * tail of the "to" list, UNLESS it was already * moved by another operator. */ if (!found && from_list[i]) { if ((from_list[i]->operator == T_OP_EQ) || (from_list[i]->operator == T_OP_LE) || (from_list[i]->operator == T_OP_GE) || (from_list[i]->operator == T_OP_SET)) { append: DEBUG4("::: APPENDING %s FROM %d TO %d", from_list[i]->name, i, tailto); to_list[tailto++] = from_list[i]; from_list[i] = NULL; } } } /* * Delete attributes in the "from" list. */ for (i = 0; i < from_count; i++) { if (!from_list[i]) continue; pairfree(&from_list[i]); } free(from_list); DEBUG4("::: TO in %d out %d", to_count, tailto); /* * Re-chain the "to" list. */ *to = NULL; last = to; for (i = 0; i < tailto; i++) { if (!to_list[i]) continue; DEBUG4("::: to[%d] = %s", i, to_list[i]->name); /* * Mash the operator to a simple '='. The * operators in the "to" list aren't used for * anything. BUT they're used in the "detail" * file and debug output, where we don't want to * see the operators. */ to_list[i]->operator = T_OP_EQ; *last = to_list[i]; last = &(*last)->next; } /* * Fix dumb cache issues */ if (to == &request->packet->vps) { fix_up(request); } else if (request->parent && (to == &request->parent->packet->vps)) { fix_up(request->parent); } free(to_list); free(edited);}/* * Copied shamelessly from conffile.c, to simplify the API for * now... */typedef enum conf_type { CONF_ITEM_INVALID = 0, CONF_ITEM_PAIR, CONF_ITEM_SECTION, CONF_ITEM_DATA} CONF_ITEM_TYPE;struct conf_item { struct conf_item *next; struct conf_part *parent; int lineno; const char *filename; CONF_ITEM_TYPE type;};struct conf_pair { CONF_ITEM item; char *attr; char *value; FR_TOKEN operator; FR_TOKEN value_type;};/* * Add attributes to a list. */int radius_update_attrlist(REQUEST *request, CONF_SECTION *cs, VALUE_PAIR *input_vps, const char *name){ CONF_ITEM *ci; VALUE_PAIR *newlist, *vp; VALUE_PAIR **output_vps = NULL; REQUEST *request_vps = request; if (!request || !cs) return RLM_MODULE_INVALID; /* * If we are an inner tunnel session, permit the * policy to update the outer lists directly. */ if (strncmp(name, "outer.", 6) == 0) { if (!request->parent) return RLM_MODULE_NOOP; request_vps = request->parent; name += 6; } if (strcmp(name, "request") == 0) { output_vps = &request_vps->packet->vps; } else if (strcmp(name, "reply") == 0) { output_vps = &request_vps->reply->vps; } else if (strcmp(name, "proxy-request") == 0) { if (request->proxy) output_vps = &request_vps->proxy->vps; } else if (strcmp(name, "proxy-reply") == 0) { if (request->proxy_reply) output_vps = &request->proxy_reply->vps; } else if (strcmp(name, "config") == 0) { output_vps = &request_vps->config_items; } else if (strcmp(name, "control") == 0) { output_vps = &request_vps->config_items; } else { return RLM_MODULE_INVALID; } if (!output_vps) return RLM_MODULE_NOOP; /* didn't update the list */ newlist = paircopy(input_vps); if (!newlist) { DEBUG2("Out of memory"); return RLM_MODULE_FAIL; } vp = newlist; for (ci=cf_item_find_next(cs, NULL); ci != NULL; ci=cf_item_find_next(cs, ci)) { CONF_PAIR *cp; /* * This should never happen. */ if (cf_item_is_section(ci)) { pairfree(&newlist); return RLM_MODULE_INVALID; } cp = cf_itemtopair(ci); /* * The VP && CF lists should be in sync. If they're * not, panic. */ if (vp->flags.do_xlat) { const char *value; char buffer[2048]; value = expand_string(buffer, sizeof(buffer), request, cp->value_type, cp->value); if (!value) { pairfree(&newlist); return RLM_MODULE_INVALID; } if (!pairparsevalue(vp, value)) { DEBUG2("ERROR: Failed parsing value \"%s\" for attribute %s: %s", value, vp->name, librad_errstr); pairfree(&newlist); return RLM_MODULE_FAIL; } vp->flags.do_xlat = 0; } vp = vp->next; } radius_pairmove(request, output_vps, newlist); return RLM_MODULE_UPDATED;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -