static void load_component_section(CONF_SECTION *cs, int comp, const char *filename) { modcallable *this; CONF_ITEM *modref; int modreflineno; int idx; indexed_modcallable *subcomp; const char *modname; char *visiblename; for (modref=cf_item_find_next(cs, NULL); modref != NULL; modref=cf_item_find_next(cs, modref)) { if (cf_item_is_section(modref)) { CONF_SECTION *scs; scs = cf_itemtosection(modref); if (strcmp(cf_section_name1(scs), subcomponent_names[comp]) == 0) { load_subcomponent_section(scs, comp, filename); continue; } /* * Allow old names, too. */ if (strcmp(cf_section_name1(scs), old_subcomponent_names[comp]) == 0) { load_subcomponent_section(scs, comp, filename); continue; } modreflineno = cf_section_lineno(scs); } else { CONF_PAIR *cp; cp = cf_itemtopair(modref); modreflineno = cf_pair_lineno(cp); } this = compile_modsingle(comp, modref, filename, &modname); if (comp == RLM_COMPONENT_AUTH) { DICT_VALUE *dval; dval = dict_valbyname(PW_AUTH_TYPE, modname); rad_assert(dval != NULL); idx = dval->value; } else { /* See the comment in new_sublist() for explanation * of the special index 0 */ idx = 0; } subcomp = new_sublist(comp, idx); if (subcomp == NULL) { radlog(L_ERR|L_CONS, "%s %s %s already configured - skipping", filename, subcomponent_names[comp], modname); modcallable_free(&this); continue; } /* If subcomp->modulelist is NULL, add_to_modcallable will * create it */ visiblename = cf_section_name2(cs); if (visiblename == NULL) visiblename = cf_section_name1(cs); add_to_modcallable(&subcomp->modulelist, this, comp, visiblename); } }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with talloc_free * * @param[in] ctx for talloc * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(TALLOC_CTX *ctx, CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; char const *attr; char const *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = talloc_zero(ctx, value_pair_map_t); attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def); if (!map->dst) { cf_log_err(ci, "Syntax error in attribute definition"); goto error; } /* * Bare words always mean attribute references. */ type = cf_pair_value_type(cp); if (type == T_BARE_WORD) { if (*value == '&') { map->src = radius_attr2tmpl(map, value + 1, src_request_def, src_list_def); } else { if (!isdigit((int) *value) && ((strchr(value, ':') != NULL) || (dict_attrbyname(value) != NULL))) { map->src = radius_attr2tmpl(map, value, src_request_def, src_list_def); } if (map->src) { WDEBUG("%s[%d]: Please add '&' for attribute reference '%s = &%s'", cf_pair_filename(cp), cf_pair_lineno(cp), attr, value); } else { map->src = radius_str2tmpl(map, value, type); } } } else { map->src = radius_str2tmpl(map, value, type); } if (!map->src) { goto error; } map->op = cf_pair_operator(cp); map->ci = ci; /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion, * except for "octets" */ if (map->dst->da && map->src->da && (map->src->da->type != map->dst->da->type) && (map->src->da->type != PW_TYPE_OCTETS) && (map->dst->da->type != PW_TYPE_OCTETS)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } /* * Can't copy an xlat expansion or literal into a list, * we don't know what type of attribute we'd need * to create */ if ((map->dst->type == VPT_TYPE_LIST) && ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) { cf_log_err(ci, "Can't copy value into list (we don't know which attribute to create)"); goto error; } /* * Depending on the attribute type, some operators are * disallowed. */ if (map->dst->type == VPT_TYPE_ATTR) { if ((map->op != T_OP_EQ) && (map->op != T_OP_CMP_EQ) && (map->op != T_OP_ADD) && (map->op != T_OP_SUB) && (map->op != T_OP_LE) && (map->op != T_OP_GE) && (map->op != T_OP_CMP_FALSE) && (map->op != T_OP_SET)) { cf_log_err(ci, "Invalid operator for attribute"); goto error; } } switch (map->src->type) { /* * Only += and -= operators are supported for list copy. */ case VPT_TYPE_LIST: switch (map->op) { case T_OP_SUB: case T_OP_ADD: break; default: cf_log_err(ci, "Operator \"%s\" not allowed " "for list copy", fr_int2str(fr_tokens, map->op, "<INVALID>")); goto error; } break; default: break; } return map; error: talloc_free(map); return NULL; }
/* * Apply a subsection to a request. * Returns permit/deny/error. */ static int apply_subsection(rlm_protocol_filter_t *inst, REQUEST *request, CONF_SECTION *cs, const char *name) { int sense; CONF_PAIR *cp; const char *value; char keybuf[256]; DEBUG2(" rlm_protocol_filter: Found subsection %s", name); cp = cf_pair_find(cs, "key"); if (!cp) { radlog(L_ERR, "rlm_protocol_filter: %s[%d]: No key defined in subsection %s", inst->filename, cf_section_lineno(cs), name); return RLM_MODULE_FAIL; } radius_xlat(keybuf, sizeof(keybuf), cf_pair_value(cp), request, NULL); if (!*keybuf) { DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, key is empty, doing nothing.", inst->filename, cf_section_lineno(cs), name); return RLM_MODULE_NOOP; } DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, using key %s", inst->filename, cf_section_lineno(cs), name, keybuf); /* * And repeat some of the above code. */ cp = cf_pair_find(cs, keybuf); if (!cp) { CONF_SECTION *subcs; /* * Maybe it has a subsection, too. */ subcs = cf_section_sub_find(cs, keybuf); if (subcs) { return apply_subsection(inst, request, subcs, keybuf); } /* it was a subsection */ DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, rule not found, doing nothing.", inst->filename, cf_section_lineno(cs), name); return RLM_MODULE_NOOP; } value = cf_pair_value(cp); sense = str2sense(value); if (sense < 0) { radlog(L_ERR, "rlm_protocol_filter: %s[%d]: Unknwn directive %s", inst->filename, cf_pair_lineno(cp), value); return RLM_MODULE_FAIL; } if (!sense) return RLM_MODULE_REJECT; return RLM_MODULE_OK; }
/* * Authorize the user. */ static int filter_authorize(void *instance, REQUEST *request) { int sense; VALUE_PAIR *vp; CONF_SECTION *cs; CONF_PAIR *cp; char keybuf[1024]; rlm_protocol_filter_t *inst = instance; radius_xlat(keybuf, sizeof(keybuf), inst->key, request, NULL); if (!*keybuf) { DEBUG2(" rlm_protocol_filter: key is empty"); return RLM_MODULE_NOOP; } DEBUG2(" rlm_protocol_filter: Using key %s", keybuf); cs = cf_section_sub_find(inst->cs, keybuf); if (!cs) { DEBUG2(" rlm_protocol_filter: No such key in %s", inst->filename); return RLM_MODULE_NOTFOUND; } /* * Walk through the list of attributes, seeing if they're * permitted/denied. */ for (vp = request->packet->vps; vp != NULL; vp = vp->next) { const char *value; CONF_SECTION *subcs; cp = cf_pair_find(cs, vp->name); if (cp) { value = cf_pair_value(cp); sense = str2sense(value); if (sense < 0) { radlog(L_ERR, "rlm_protocol_filter %s[%d]: Unknown directive %s", inst->filename, cf_pair_lineno(cp), value); return RLM_MODULE_FAIL; } if (!sense) return RLM_MODULE_REJECT; continue; /* was permitted */ } /* else no pair was found */ /* * Maybe it has a subsection */ subcs = cf_section_sub_find(cs, vp->name); if (subcs) { sense = apply_subsection(inst, request, subcs, vp->name); if ((sense == RLM_MODULE_OK) || (sense == RLM_MODULE_NOOP)) { continue; } return sense; } /* it was a subsection */ /* * Not found, must be "permit" */ } return RLM_MODULE_OK; }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with talloc_free * * @param[in] ctx for talloc * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(TALLOC_CTX *ctx, CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; char const *attr; char const *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = talloc_zero(ctx, value_pair_map_t); map->op = cf_pair_operator(cp); map->ci = ci; attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } /* * LHS must always be an attribute reference. */ map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def); if (!map->dst) { cf_log_err(ci, "Syntax error in attribute definition"); goto error; } /* * RHS might be an attribute reference. */ type = cf_pair_value_type(cp); map->src = radius_str2tmpl(map, value, type, src_request_def, src_list_def); if (!map->src) { goto error; } /* * Anal-retentive checks. */ if (debug_flag > 2) { if ((map->dst->type == VPT_TYPE_ATTR) && (*attr != '&')) { WARN("%s[%d]: Please change attribute reference to '&%s %s ...'", cf_pair_filename(cp), cf_pair_lineno(cp), attr, fr_int2str(fr_tokens, map->op, "<INVALID>")); } if ((map->src->type == VPT_TYPE_ATTR) && (*value != '&')) { WARN("%s[%d]: Please change attribute reference to '... %s &%s'", cf_pair_filename(cp), cf_pair_lineno(cp), fr_int2str(fr_tokens, map->op, "<INVALID>"), value); } } /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion, * except for "octets" */ if (map->dst->vpt_da && map->src->vpt_da && (map->src->vpt_da->type != map->dst->vpt_da->type) && (map->src->vpt_da->type != PW_TYPE_OCTETS) && (map->dst->vpt_da->type != PW_TYPE_OCTETS)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } /* * Depending on the attribute type, some operators are * disallowed. */ if (map->dst->type == VPT_TYPE_ATTR) { if ((map->op != T_OP_EQ) && (map->op != T_OP_CMP_EQ) && (map->op != T_OP_ADD) && (map->op != T_OP_SUB) && (map->op != T_OP_LE) && (map->op != T_OP_GE) && (map->op != T_OP_CMP_FALSE) && (map->op != T_OP_SET)) { cf_log_err(ci, "Invalid operator for attribute"); goto error; } /* * This will be an error in future versions of * the server. */ if ((map->op == T_OP_CMP_FALSE) && ((map->src->type != VPT_TYPE_LITERAL) || (strcmp(map->src->name, "ANY") != 0))) { WARN("%s[%d] Attribute deletion MUST use '!* ANY'", cf_pair_filename(cp), cf_pair_lineno(cp)); } } if (map->dst->type == VPT_TYPE_LIST) { /* * Only += and :=, and !* operators are supported * for lists. */ switch (map->op) { case T_OP_CMP_FALSE: if ((map->src->type != VPT_TYPE_LITERAL) || (strcmp(map->src->name, "ANY") != 0)) { cf_log_err(ci, "List deletion MUST use '!* ANY'"); goto error; } break; case T_OP_ADD: if ((map->src->type != VPT_TYPE_LIST) && (map->src->type != VPT_TYPE_EXEC)) { cf_log_err(ci, "Invalid source for list '+='"); goto error; } break; case T_OP_SET: if (map->src->type == VPT_TYPE_EXEC) { WARN("%s[%d] Please change ':=' to '=' for list assignment", cf_pair_filename(cp), cf_pair_lineno(cp)); break; } if (map->src->type != VPT_TYPE_LIST) { cf_log_err(ci, "Invalid source for ':=' operator"); goto error; } break; case T_OP_EQ: if (map->src->type != VPT_TYPE_EXEC) { cf_log_err(ci, "Invalid source for '=' operator"); goto error; } break; default: cf_log_err(ci, "Operator \"%s\" not allowed for list assignment", fr_int2str(fr_tokens, map->op, "<INVALID>")); goto error; } } return map; error: talloc_free(map); return NULL; }