blocked = (request->master_state == REQUEST_STOP_PROCESSING);
if (blocked) return RLM_MODULE_NOOP;
- RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
+ RDEBUG3("modsingle[%s]: calling %s (%s)",
comp2str[component], sp->modinst->name,
- sp->modinst->entry->name, request->number);
+ sp->modinst->entry->name);
request->log.indent = 0;
if (sp->modinst->force) {
*/
blocked = (request->master_state == REQUEST_STOP_PROCESSING);
if (blocked) {
- RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
+ RWARN("Module %s became unblocked", sp->modinst->entry->name);
}
fail:
request->log.indent = indent;
- RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
+ RDEBUG3("modsingle[%s]: returned from %s (%s)",
comp2str[component], sp->modinst->name,
- sp->modinst->entry->name, request->number);
+ sp->modinst->entry->name);
return request->rcode;
}
*/
if (!c) goto finish;
+ if (fr_debug_lvl >= 3) {
+ VERIFY_REQUEST(request);
+ }
+
rad_assert(c->debug_name != NULL); /* if this happens, all bets are off. */
/*
* Like MOD_ELSE, but allow for a later "else"
*/
if (if_taken) {
- RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
- unlang_keyword[c->type], request->number);
+ RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+ unlang_keyword[c->type]);
was_if = true;
if_taken = true;
goto next_sibling;
if (c->type == MOD_ELSE) {
if (!was_if) { /* error */
elsif_error:
- RDEBUG2("... skipping %s for request %d: No preceding \"if\"",
- unlang_keyword[c->type], request->number);
+ RDEBUG2("... skipping %s: No preceding \"if\"",
+ unlang_keyword[c->type]);
goto next_sibling;
}
if (if_taken) {
- RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
- unlang_keyword[c->type], request->number);
+ RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+ unlang_keyword[c->type]);
was_if = false;
if_taken = false;
goto next_sibling;
* If we don't remove the request data, something could call
* the xlat outside of a foreach loop and trigger a segv.
*/
- pairfree(&vps);
+ fr_pair_list_free(&vps);
request_data_get(request, (void *)radius_get_vp, foreach_depth);
rad_assert(next != NULL);
* MOD_GROUP.
*/
if (!g->children) {
+ if (c->type == MOD_CASE) {
+ result = RLM_MODULE_NOOP;
+ goto calculate_result;
+ }
+
RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
goto next_sibling;
}
if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
map->rhs = vpt;
- cf_log_err(map->ci, "%s", fr_strerror());
+ cf_log_err(map->ci, "Cannot parse RHS hex as the data type of the attribute %s", map->lhs->tmpl_da->name);
return -1;
}
talloc_free(vpt);
return 1;
}
+/** Load a named module from "instantiate" or "policy".
+ *
+ * If it's "foo.method", look for "foo", and return "method" as the method
+ * we wish to use, instead of the input component.
+ *
+ * @param[out] pcomponent Where to write the method we found, if any. If no method is specified
+ * will be set to MOD_COUNT.
+ * @param[in] real_name Complete name string e.g. foo.authorize.
+ * @param[in] virtual_name Virtual module name e.g. foo.
+ * @param[in] method_name Method override (may be NULL) or the method name e.g. authorize.
+ * @return the CONF_SECTION specifying the virtual module.
+ */
+static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
+ char const *real_name, char const *virtual_name, char const *method_name)
+{
+ CONF_SECTION *cs, *subcs;
+ rlm_components_t method = *pcomponent;
+ char buffer[256];
+
+ /*
+ * Turn the method name into a method enum.
+ */
+ if (method_name) {
+ rlm_components_t i;
+
+ for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+ if (strcmp(comp2str[i], method_name) == 0) break;
+ }
+
+ if (i != MOD_COUNT) {
+ method = i;
+ } else {
+ method_name = NULL;
+ virtual_name = real_name;
+ }
+ }
+
+ /*
+ * Look for "foo" in the "instantiate" section. If we
+ * find it, AND there's no method name, we've found the
+ * right thing.
+ *
+ * Return it to the caller, with the updated method.
+ */
+ cs = cf_section_find("instantiate");
+ if (cs) {
+ /*
+ * Found "foo". Load it as "foo", or "foo.method".
+ */
+ subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
+ if (subcs) {
+ *pcomponent = method;
+ return subcs;
+ }
+ }
+
+ /*
+ * Look for it in "policy".
+ *
+ * If there's no policy section, we can't do anything else.
+ */
+ cs = cf_section_find("policy");
+ if (!cs) return NULL;
+
+ /*
+ * "foo.authorize" means "load policy "foo" as method "authorize".
+ *
+ * And bail out if there's no policy "foo".
+ */
+ if (method_name) {
+ subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
+ if (subcs) *pcomponent = method;
+
+ return subcs;
+ }
+
+ /*
+ * "foo" means "look for foo.component" first, to allow
+ * method overrides. If that's not found, just look for
+ * a policy "foo".
+ *
+ */
+ snprintf(buffer, sizeof(buffer), "%s.%s",
+ virtual_name, comp2str[method]);
+ subcs = cf_section_sub_find_name2(cs, NULL, buffer);
+ if (subcs) return subcs;
+
+ return cf_section_sub_find_name2(cs, NULL, virtual_name);
+}
+
/*
* Compile one entry of a module call.
* policy { ... name { .. } .. }
* policy { ... name.method { .. } .. }
*
- * The "instantiate" virtual modules are identical to the
- * policies at this point. We should probably get rid of
- * the "instantiate" ones, as they're duplicate and
- * confusing.
+ * The only difference between things in "instantiate"
+ * and "policy" is that "instantiate" will cause modules
+ * to be instantiated in a particular order.
*/
subcs = NULL;
- cs = cf_section_find("instantiate");
- if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
- modrefname);
- if (!subcs &&
- (cs = cf_section_find("policy")) != NULL) {
+ p = strrchr(modrefname, '.');
+ if (!p) {
+ subcs = virtual_module_find_cs(&method, modrefname, modrefname, NULL);
+ } else {
char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s.%s",
- modrefname, comp2str[component]);
+ strlcpy(buffer, modrefname, sizeof(buffer));
+ buffer[p - modrefname] = '\0';
- /*
- * Prefer name.section, then name.
- */
- subcs = cf_section_sub_find_name2(cs, NULL,
- buffer);
- if (!subcs) {
- subcs = cf_section_sub_find_name2(cs, NULL,
- modrefname);
- }
+ subcs = virtual_module_find_cs(&method, modrefname, buffer, buffer + (p - modrefname) + 1);
}
/*
*/
if (cf_section_name2(subcs)) {
csingle = do_compile_modsingle(parent,
- component,
+ method,
cf_section_to_item(subcs),
grouptype,
modname);
* group foo { ...
*/
csingle = do_compile_modgroup(parent,
- component,
+ method,
subcs,
GROUPTYPE_SIMPLE,
grouptype, MOD_GROUP);
* modules belongs in raddb/mods-available/,
* which isn't loaded into the "modules" section.
*/
- if (cf_section_sub_find_name2(modules, NULL, realname)) {
- this = module_instantiate(modules, realname);
- if (this) goto allocate_csingle;
-
- /*
- *
- */
- if (realname != modrefname) {
- return NULL;
- }
-
- } else {
- /*
- * We were asked to MAYBE load it and it
- * doesn't exist. Return a soft error.
- */
- if (realname != modrefname) {
- *modname = modrefname;
- return NULL;
- }
- }
- }
-
- /*
- * No module found by that name. Maybe we're calling
- * module.method
- */
- p = strrchr(modrefname, '.');
- if (p) {
- rlm_components_t i;
- p++;
+ this = module_instantiate_method(modules, realname, &method);
+ if (this) goto allocate_csingle;
/*
- * Find the component.
+ * We were asked to MAYBE load it and it
+ * doesn't exist. Return a soft error.
*/
- for (i = MOD_AUTHENTICATE;
- i < MOD_COUNT;
- i++) {
- if (strcmp(p, comp2str[i]) == 0) {
- char buffer[256];
-
- strlcpy(buffer, modrefname, sizeof(buffer));
- buffer[p - modrefname - 1] = '\0';
- component = i;
-
- this = module_instantiate(modules, buffer);
- if (this) {
- method = i;
- goto allocate_csingle;
- }
- }
+ if (realname != modrefname) {
+ *modname = modrefname;
+ return NULL;
}
-
- /*
- * FIXME: check for "module", and give error "no
- * such component" when we don't find the method.
- */
}
/*
rad_assert(parent != NULL);
p = mod_callabletogroup(parent);
- rad_assert(p->tail != NULL);
+ if (!p->tail) goto elsif_fail;
+ /*
+ * We're in the process of compiling the
+ * section, so the parent's tail is the
+ * previous "if" statement.
+ */
f = mod_callabletogroup(p->tail);
- rad_assert((f->mc.type == MOD_IF) ||
- (f->mc.type == MOD_ELSIF));
+ if ((f->mc.type != MOD_IF) &&
+ (f->mc.type != MOD_ELSIF)) {
+ elsif_fail:
+ cf_log_err_cs(g->cs, "Invalid location for 'elsif'. There is no preceding 'if' statement");
+ talloc_free(g);
+ return NULL;
+ }
/*
* If we took the previous condition, we
rad_assert(parent != NULL);
p = mod_callabletogroup(parent);
- rad_assert(p->tail != NULL);
+ if (!p->tail) goto else_fail;
f = mod_callabletogroup(p->tail);
- rad_assert((f->mc.type == MOD_IF) ||
- (f->mc.type == MOD_ELSIF));
+ if ((f->mc.type != MOD_IF) &&
+ (f->mc.type != MOD_ELSIF)) {
+ else_fail:
+ cf_log_err_cs(g->cs, "Invalid location for 'else'. There is no preceding 'if' statement");
+ talloc_free(g);
+ return NULL;
+ }
/*
* If we took the previous condition, we
if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
c->pass2_fixup = PASS2_FIXUP_NONE;
}
+
+ /*
+ * Convert virtual &Attr-Foo to "%{Attr-Foo}"
+ */
+ vpt = c->data.vpt;
+ if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
+ vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
return true;
}
if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
map->rhs = vpt;
- cf_log_err(map->ci, "%s", fr_strerror());
+ cf_log_err(map->ci, "Cannot parse RHS hex as the data type of the attribute %s", map->lhs->tmpl_da->name);
return -1;
}
talloc_free(vpt);
}
/*
+ * Convert RHS to expansions, too.
+ */
+ vpt = c->data.map->rhs;
+ if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
+ vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ /*
* @todo v3.1: do the same thing for the RHS...
*/
/*
* Mark it as requiring a paircompare() call, instead of
- * paircmp().
+ * fr_pair_cmp().
*/
c->pass2_fixup = PASS2_PAIRCOMPARE;
}
/*
+ * Convert virtual &Attr-Foo to "%{Attr-Foo}"
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
+ g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
+ g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ /*
* We may have: switch Foo-Bar {
*
* where Foo-Bar is an attribute defined
goto do_children;
}
+ if (g->vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(cf_section_to_item(g->cs), g->vpt)) {
+ return false;
+ }
+ }
+
/*
* Compile and sanity check xlat
* expansions.
}
}
+ /*
+ * Virtual attribute fixes for "case" statements, too.
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
+ g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
+ g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
if (!modcall_pass2(g->children)) return false;
g->done_pass2 = true;
break;
char const *name1 = cf_section_name1(g->cs);
if (strcmp(name1, unlang_keyword[c->type]) != 0) {
- c->debug_name = talloc_asprintf(c, "%s %s", name1, cf_section_name2(g->cs));
+ name2 = cf_section_name2(g->cs);
+
+ if (!name2) {
+ c->debug_name = name1;
+ } else {
+ c->debug_name = talloc_asprintf(c, "%s %s", name1, name2);
+ }
}
}
}
}
}
+
+int modcall_pass2_condition(fr_cond_t *c)
+{
+ if (!fr_condition_walk(c, pass2_callback, NULL)) return -1;
+
+ return 0;
+}