talloc_free(xlat);
}
-
-/** Register an old style xlat function
- *
- * @note No new legacy xlat functions should be added to the server.
- * Each one added creates additional work later for a member
- * of the development team to fix the function to conform to
- * the new API.
- *
- * @param[in] mod_inst Instance of module that's registering the xlat function.
- * @param[in] name xlat name.
- * @param[in] func xlat function to be called.
- * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
- * @param[in] instantiate function to pre-parse any xlat specific data.
- * @param[in] inst_size sizeof() this xlat's instance data.
- * @param[in] buf_len Size of the output buffer to allocate when calling the function.
- * May be 0 if the function allocates its own buffer.
- * @return
- * - A handle for the newly registered xlat function on success.
- * - NULL on failure.
- */
-xlat_t *xlat_register_legacy(void *mod_inst, char const *name,
- xlat_func_legacy_t func, xlat_escape_legacy_t escape,
- xlat_instantiate_t instantiate, size_t inst_size,
- size_t buf_len)
-{
- xlat_t *c;
- bool is_new = false;
-
- if (!xlat_root && (xlat_init() < 0)) return NULL;
-
- if (!*name) {
- ERROR("%s: Invalid xlat name", __FUNCTION__);
- return NULL;
- }
-
- /*
- * If it already exists, replace the instance.
- */
- c = fr_rb_find(xlat_root, &(xlat_t){ .name = name });
- if (c) {
- if (c->internal) {
- ERROR("%s: Cannot re-define internal expansion %s", __FUNCTION__, name);
- return NULL;
- }
- /*
- * Doesn't exist. Create it.
- */
- } else {
- c = talloc_zero(xlat_root, xlat_t);
- c->name = talloc_typed_strdup(c, name);
- talloc_set_destructor(c, _xlat_func_talloc_free);
- is_new = true;
- }
-
- c->func.sync = func;
- c->type = XLAT_FUNC_LEGACY;
- c->buf_len = buf_len;
- c->escape = escape;
- c->mod_inst = mod_inst;
- c->instantiate = instantiate;
- c->inst_size = inst_size;
-
- DEBUG3("%s: %s", __FUNCTION__, c->name);
-
- if (is_new && (fr_rb_replace(NULL, xlat_root, c) < 0)) {
- ERROR("Failed inserting xlat registration for %s",
- c->name);
- talloc_free(c);
- return NULL;
- }
-
- return c;
-}
-
-
/** Register an xlat function for a module
*
* @param[in] ctx Used to automate deregistration of the xlat fnction.
return NULL;
}
- if ((c->type != XLAT_FUNC_NORMAL) || (c->flags.needs_async != flags->needs_async)) {
+ if (c->flags.needs_async != flags->needs_async) {
ERROR("%s: Cannot change async capability of %s", __FUNCTION__, name);
return NULL;
}
- if (c->func.async != func) {
+ if (c->func != func) {
ERROR("%s: Cannot change callback function for %s", __FUNCTION__, name);
return NULL;
}
}
*c = (xlat_t){
.name = talloc_typed_strdup(c, name),
- .func = {
- .async = func
- },
+ .func = func,
.mctx = our_mctx,
- .type = XLAT_FUNC_NORMAL,
.flags = *flags,
.input_type = XLAT_INPUT_UNPROCESSED /* set default - will be overridden if args are registered */
};
* These xlats wrap the xlat methods of the modules in a redundant section,
* emulating the behaviour of a redundant section, but over xlats.
*
- * @todo - make xlat_register_legacy() take ASYNC / SYNC / UNKNOWN. We may
- * need "unknown" here in order to properly handle the children, which
- * we don't know are async-safe or not. For now, it's best to assume
- * that all xlat's in a redundant block are module calls, and are not async-safe
- *
* @return
* - 0 on success.
* - -1 on error.
switch (node->type) {
case XLAT_FUNC:
- switch (node->call.func->type) {
- case XLAT_FUNC_LEGACY:
- {
- fr_value_box_t *value;
- char *str = NULL;
- char *result_str = NULL;
- ssize_t slen;
-
- if (!fr_dlist_empty(result)) {
- VALUE_BOX_TALLOC_LIST_VERIFY(result);
- result_str = fr_value_box_list_aprint(NULL, result, NULL, NULL);
- if (!result_str) return XLAT_ACTION_FAIL;
- } else {
- result_str = talloc_typed_strdup(NULL, "");
- }
+ {
+ xlat_action_t xa;
+ xlat_thread_inst_t *t;
+ fr_value_box_list_t result_copy;
- MEM(value = fr_value_box_alloc_null(ctx));
- if (node->call.func->buf_len > 0) {
- fr_value_box_bstr_alloc(value, &str, value, NULL, node->call.func->buf_len, false);
- }
+ t = xlat_thread_instance_find(node);
+ fr_assert(t);
- XLAT_DEBUG("** [%i] %s(func) - %%{%s:%pV}", unlang_interpret_stack_depth(request), __FUNCTION__,
- node->fmt,
- fr_box_strvalue_len(result_str, talloc_array_length(result_str) - 1));
+ XLAT_DEBUG("** [%i] %s(func-async) - %%%c%s:%pM%c",
+ unlang_interpret_stack_depth(request), __FUNCTION__,
+ (node->call.func->input_type == XLAT_INPUT_ARGS) ? '(' : '{',
+ node->fmt, result,
+ (node->call.func->input_type == XLAT_INPUT_ARGS) ? ')' : '}');
- slen = node->call.func->func.sync(value, &str, node->call.func->buf_len,
- node->call.func->mod_inst, NULL, request, result_str);
- xlat_debug_log_expansion(request, *in, result);
- if (slen < 0) {
- talloc_free(value);
- talloc_free(result_str);
- return XLAT_ACTION_FAIL;
- }
- if (slen == 0) { /* Zero length result */
- talloc_free(result_str);
- talloc_free(value);
- break;
- }
- (void)talloc_get_type_abort(str, char); /* Check output buffer is sane */
+ VALUE_BOX_TALLOC_LIST_VERIFY(result);
- /*
- * Shrink the buffer
- */
- if (node->call.func->buf_len > 0) {
- if (slen > 0) fr_value_box_bstr_realloc(value, &str, value, slen);
- } else {
- fr_value_box_bstrdup_buffer_shallow(NULL, value, NULL, str, false);
- }
+ /*
+ * Always need to init and free the
+ * copy list as debug level could change
+ * when the xlat function executes.
+ */
+ fr_value_box_list_init(&result_copy);
- VALUE_BOX_VERIFY(value);
- fr_dcursor_append(out, value); /* Append the result of the expansion */
- talloc_free(result_str);
- xlat_debug_log_result(request, value);
+ /*
+ * Need to copy the input list in case
+ * the async function mucks with it.
+ */
+ if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result);
+ xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args);
+ if (xa == XLAT_ACTION_FAIL) {
+ fr_dlist_talloc_free(&result_copy);
+ return xa;
}
- break;
-
- case XLAT_FUNC_NORMAL:
- {
- xlat_action_t xa;
- xlat_thread_inst_t *t;
- fr_value_box_list_t result_copy;
-
- t = xlat_thread_instance_find(node);
- fr_assert(t);
-
- XLAT_DEBUG("** [%i] %s(func-async) - %%%c%s:%pM%c",
- unlang_interpret_stack_depth(request), __FUNCTION__,
- (node->call.func->input_type == XLAT_INPUT_ARGS) ? '(' : '{',
- node->fmt, result,
- (node->call.func->input_type == XLAT_INPUT_ARGS) ? ')' : '}');
-
- VALUE_BOX_TALLOC_LIST_VERIFY(result);
-
- /*
- * Always need to init and free the
- * copy list as debug level could change
- * when the xlat function executes.
- */
- fr_value_box_list_init(&result_copy);
-
- /*
- * Need to copy the input list in case
- * the async function mucks with it.
- */
- if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result);
- xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args);
- if (xa == XLAT_ACTION_FAIL) {
- fr_dlist_talloc_free(&result_copy);
- return xa;
- }
- VALUE_BOX_TALLOC_LIST_VERIFY(result);
+ VALUE_BOX_TALLOC_LIST_VERIFY(result);
- xa = node->call.func->func.async(ctx, out,
- XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL),
- request, result);
- VALUE_BOX_TALLOC_LIST_VERIFY(result);
+ xa = node->call.func->func(ctx, out,
+ XLAT_CTX(node->call.inst->data, t->data, t->mctx, NULL),
+ request, result);
+ VALUE_BOX_TALLOC_LIST_VERIFY(result);
- if (RDEBUG_ENABLED2) xlat_debug_log_expansion(request, *in, &result_copy);
- fr_dlist_talloc_free(&result_copy);
+ if (RDEBUG_ENABLED2) xlat_debug_log_expansion(request, *in, &result_copy);
+ fr_dlist_talloc_free(&result_copy);
- switch (xa) {
- case XLAT_ACTION_FAIL:
- return xa;
+ switch (xa) {
+ case XLAT_ACTION_FAIL:
+ return xa;
- case XLAT_ACTION_PUSH_CHILD:
- RDEBUG3(" -- CHILD");
- return xa;
+ case XLAT_ACTION_PUSH_CHILD:
+ RDEBUG3(" -- CHILD");
+ return xa;
- case XLAT_ACTION_PUSH_UNLANG:
- RDEBUG3(" -- UNLANG");
- return xa;
+ case XLAT_ACTION_PUSH_UNLANG:
+ RDEBUG3(" -- UNLANG");
+ return xa;
- case XLAT_ACTION_YIELD:
- RDEBUG3(" -- YIELD");
- return xa;
+ case XLAT_ACTION_YIELD:
+ RDEBUG3(" -- YIELD");
+ return xa;
- case XLAT_ACTION_DONE: /* Process the result */
- fr_dcursor_next(out);
- xlat_debug_log_result(request, fr_dcursor_current(out));
- break;
- }
+ case XLAT_ACTION_DONE: /* Process the result */
+ fr_dcursor_next(out);
+ xlat_debug_log_result(request, fr_dcursor_current(out));
break;
}
- }
+ }
break;
case XLAT_ALTERNATE:
case XLAT_VIRTUAL:
{
- char *str = NULL;
- ssize_t slen;
-
XLAT_DEBUG("** [%i] %s(virtual) - %%{%s}", unlang_interpret_stack_depth(request), __FUNCTION__,
node->fmt);
xlat_debug_log_expansion(request, node, NULL);
- if (node->call.func->type == XLAT_FUNC_NORMAL) {
- node->call.func->func.async(ctx, out,
- XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL),
- request, NULL);
- } else {
- MEM(value = fr_value_box_alloc_null(ctx));
- slen = node->call.func->func.sync(value, &str, node->call.func->buf_len, node->call.func->mod_inst,
- NULL, request, NULL);
- if (slen < 0) {
- talloc_free(value);
- goto fail;
- }
- if (slen == 0) continue;
-
- fr_value_box_bstrdup_buffer_shallow(NULL, value, NULL, str, false);
- fr_dcursor_append(out, value);
- }
+ xa = node->call.func->func(ctx, out,
+ XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL),
+ request, NULL);
fr_dcursor_next(out);
xlat_debug_log_result(request, fr_dcursor_current(out));
int lvl)
{
ssize_t slen;
- char *str = NULL, *child;
- char const *p;
+ char *str = NULL;
fr_value_box_t string, *value;
fr_value_box_list_t head;
fr_dcursor_t cursor;
break;
case XLAT_VIRTUAL:
- XLAT_DEBUG("xlat_sync_eval VIRTUAL");
-
+ {
/*
* Temporary hack to use the new API
*/
- if (node->call.func->type == XLAT_FUNC_NORMAL) {
- fr_value_box_list_t result;
- xlat_action_t action;
- fr_dcursor_t out;
- TALLOC_CTX *pool = talloc_new(NULL);
-
- fr_value_box_list_init (&result);
- fr_dcursor_init(&out, &result);
-
- action = node->call.func->func.async(ctx, &out,
- XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL),
- request, NULL);
- if (action == XLAT_ACTION_FAIL) {
+ fr_value_box_list_t result;
+ xlat_action_t action;
+ fr_dcursor_t out;
+ TALLOC_CTX *pool = talloc_new(NULL);
+
+ XLAT_DEBUG("xlat_sync_eval VIRTUAL");
+
+ fr_value_box_list_init (&result);
+ fr_dcursor_init(&out, &result);
+
+ action = node->call.func->func(ctx, &out,
+ XLAT_CTX(node->call.func->uctx, NULL, NULL, NULL),
+ request, NULL);
+ if (action == XLAT_ACTION_FAIL) {
+ talloc_free(pool);
+ return NULL;
+ }
+ if (!fr_dlist_empty(&result)) {
+ str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double);
+ if (!str) {
+ RPEDEBUG("Failed concatenating xlat result string");
talloc_free(pool);
return NULL;
}
- if (!fr_dlist_empty(&result)) {
- str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double);
- if (!str) {
- RPEDEBUG("Failed concatenating xlat result string");
- talloc_free(pool);
- return NULL;
- }
- } else {
- str = talloc_strdup(ctx, "");
- }
- talloc_free(pool); /* Memory should be in new ctx */
- break;
- }
-
- if (node->call.func->buf_len > 0) {
- str = talloc_array(ctx, char, node->call.func->buf_len);
- str[0] = '\0'; /* Be sure the string is \0 terminated */
- }
- slen = node->call.func->func.sync(ctx, &str, node->call.func->buf_len, node->call.func->mod_inst, NULL, request, NULL);
- if (slen < 0) {
- talloc_free(str);
- return NULL;
+ } else {
+ str = talloc_strdup(ctx, "");
}
+ talloc_free(pool); /* Memory should be in new ctx */
+ }
break;
case XLAT_FUNC:
+ {
+ fr_value_box_list_t result;
+ TALLOC_CTX *pool = talloc_new(NULL);
+
XLAT_DEBUG("xlat_sync_eval MODULE");
+ fr_value_box_list_init(&result);
/*
- * Temporary hack to use the new API.
- *
- * Will not handle yields.
+ * Use the unlang stack to evaluate
+ * the async xlat up until the point
+ * that it needs to yield.
*/
- if (node->call.func->type == XLAT_FUNC_NORMAL) {
- fr_value_box_list_t result;
- TALLOC_CTX *pool = talloc_new(NULL);
- fr_value_box_list_init(&result);
- /*
- * Use the unlang stack to evaluate
- * the async xlat up until the point
- * that it needs to yield.
- */
- if (unlang_xlat_push(pool, NULL, &result, request, node, true) < 0) {
- talloc_free(pool);
- return NULL;
- }
-
- switch (unlang_interpret_synchronous(unlang_interpret_event_list(request), request)) {
- default:
- break;
-
- case RLM_MODULE_REJECT:
- case RLM_MODULE_FAIL:
- RPEDEBUG("xlat evaluation failed");
- talloc_free(pool);
- return NULL;
- }
+ if (unlang_xlat_push(pool, NULL, &result, request, node, true) < 0) {
+ talloc_free(pool);
+ return NULL;
+ }
- if (!fr_dlist_empty(&result)) {
- str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double);
- if (!str) {
- RPEDEBUG("Failed concatenating xlat result string");
- talloc_free(pool);
- return NULL;
- }
- } else {
- str = talloc_strdup(ctx, "");
- }
- talloc_free(pool); /* Memory should be in new ctx */
- return str;
- } else if (node->child) {
- if (xlat_process(ctx, &child, request,
- node->child, node->call.func->escape, node->call.func->mod_inst) == 0) {
- return NULL;
- }
+ switch (unlang_interpret_synchronous(unlang_interpret_event_list(request), request)) {
+ default:
+ break;
- XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
- } else {
- XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
- child = talloc_typed_strdup(ctx, "");
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_FAIL:
+ RPEDEBUG("xlat evaluation failed");
+ talloc_free(pool);
+ return NULL;
}
- XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
-
- /*
- * Smash \n --> CR.
- *
- * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string.
- *
- * This is really the reverse of fr_snprint().
- */
- if (*child) {
- fr_type_t type;
- fr_value_box_t data;
-
- type = FR_TYPE_STRING;
- if (fr_value_box_from_str(ctx, &data, type, NULL,
- child, talloc_array_length(child) - 1,
- &fr_value_unescape_double, false) < 0) {
- talloc_free(child);
+ if (!fr_dlist_empty(&result)) {
+ str = fr_value_box_list_aprint(ctx, &result, NULL, &fr_value_escape_double);
+ if (!str) {
+ RPEDEBUG("Failed concatenating xlat result string");
+ talloc_free(pool);
return NULL;
}
-
- talloc_free(child);
- child = data.datum.ptr;
-
} else {
- char *q;
-
- p = q = child;
- while (*p) {
- if (*p == '\\') switch (p[1]) {
- default:
- *(q++) = p[1];
- p += 2;
- continue;
-
- case 'n':
- *(q++) = '\n';
- p += 2;
- continue;
-
- case 't':
- *(q++) = '\t';
- p += 2;
- continue;
- }
-
- *(q++) = *(p++);
- }
- *q = '\0';
- }
-
- if (node->call.func->buf_len > 0) {
- str = talloc_array(ctx, char, node->call.func->buf_len);
- str[0] = '\0'; /* Be sure the string is \0 terminated */
+ str = talloc_strdup(ctx, "");
}
- slen = node->call.func->func.sync(ctx, &str, node->call.func->buf_len, node->call.func->mod_inst, NULL, request, child);
- talloc_free(child);
- if (slen < 0) {
- talloc_free(str);
- return NULL;
- }
- break;
+ talloc_free(pool); /* Memory should be in new ctx */
+ }
+ return str;
#ifdef HAVE_REGEX
case XLAT_REGEX:
* Break here to avoid nodes being evaluated multiple times
* and parts of strings being duplicated.
*/
- if ((node->type == XLAT_FUNC) && (node->call.func->type == XLAT_FUNC_NORMAL)) {
+ if (node->type == XLAT_FUNC) {
i++;
break;
}