Skip to content

Commit 0fe02d7

Browse files
committed
concatenate function arguments when evaluating
the edit code already does this. The function argument code did not. The result was that the functions were being passed value-box lists / groups, when the intention of the admin was to pass in one quoted string. The xlat expression parser "fixed" this issue by adding a cast when it parsed strings. But that cast would then encapsulate the function arguments into another function call. That either prevented the escaping of strings, or did the concatentation to string which then mashed it to SAFE_FOR_NONE. The final string would then be escaped, which is not what the admin intended.
1 parent bcc56b8 commit 0fe02d7

1 file changed

Lines changed: 74 additions & 17 deletions

File tree

src/lib/unlang/xlat_eval.c

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,19 @@ static inline void xlat_debug_log_result(request_t *request, xlat_exp_t const *n
279279
* @param[in] request currently being processed
280280
* @param[in] name of the function being called
281281
* @param[in] arg specification of current argument
282+
* @param[in] node expansion for the current argument
282283
* @param[in] arg_num number of current argument in the argument specifications
283284
* @return
284285
* - XLAT_ACTION_DONE on success.
285286
* - XLAT_ACTION_FAIL on failure.
286287
*/
287288
static xlat_action_t xlat_process_arg_list(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request,
288-
char const *name, xlat_arg_parser_t const *arg, unsigned int arg_num)
289+
char const *name, xlat_arg_parser_t const *arg, xlat_exp_t const *node, unsigned int arg_num)
289290
{
290291
fr_value_box_t *vb;
292+
bool concat = false;
293+
bool quoted = false;
294+
fr_type_t type;
291295

292296
/*
293297
* The funtion may be URI or SQL, which have different sub-types. So we call the function if it
@@ -311,36 +315,84 @@ do { \
311315
} \
312316
} while (0)
313317

318+
/*
319+
* See if we have to concatenate the results.
320+
*
321+
* If the input xlat is more complicated expression, it's going to be a function, e.g.
322+
*
323+
* 1+2 --> %op_add(1,2).
324+
*
325+
* And then we can't do escaping. Note that this is also the case for
326+
*
327+
* "foo" + User-Name --> %op_add("foo", User-Name)
328+
*
329+
* Arguably, we DO want to escape User-Name, but not Foo. Because "+" here is a special case. :(
330+
*/
331+
if ((fr_dlist_num_elements(&node->group->dlist) == 1) && (xlat_exp_head(node->group)->quote != T_BARE_WORD)) {
332+
quoted = concat = true;
333+
type = FR_TYPE_STRING;
334+
335+
} else {
336+
concat = arg->concat;
337+
type = arg->type;
338+
}
339+
314340
if (fr_value_box_list_empty(list)) {
341+
/*
342+
* The expansion resulted in no data, BUT the admin wants a string. So we create an
343+
* empty string.
344+
*
345+
* i.e. If attribute 'foo' doesn't exist, then we have:
346+
*
347+
* %{foo} --> nothing, because 'foo' doesn't exist
348+
* "%{foo}" --> "", because we want a string, therefore the contents of the string are nothing.
349+
*/
350+
if (quoted) {
351+
MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL));
352+
fr_value_box_strdup(vb, vb, NULL, "", false);
353+
fr_value_box_list_insert_tail(list, vb);
354+
355+
return XLAT_ACTION_DONE;
356+
}
357+
315358
if (arg->required) {
316359
REDEBUG("Function \"%s\" is missing required argument %u", name, arg_num);
317360
return XLAT_ACTION_FAIL;
318361
}
362+
319363
return XLAT_ACTION_DONE;
320364
}
321365

322366
vb = fr_value_box_list_head(list);
367+
fr_assert(node->type == XLAT_GROUP);
323368

324369
/*
325370
* Concatenate child boxes, casting to desired type,
326371
* then replace group vb with first child vb
327372
*/
328-
if (arg->concat) {
373+
if (concat) {
329374
if (arg->func) {
330375
do ESCAPE(arg, vb, arg_num); while ((vb = fr_value_box_list_next(list, vb)));
331376

332377
vb = fr_value_box_list_head(list); /* Reset */
333378
}
334379

335380
if (fr_value_box_list_concat_in_place(ctx,
336-
vb, list, arg->type,
381+
vb, list, type,
337382
FR_VALUE_BOX_LIST_FREE, true,
338383
SIZE_MAX) < 0) {
339-
RPEDEBUG("Function \"%s\" failed concatenating arguments to type %s", name, fr_type_to_str(arg->type));
384+
RPEDEBUG("Function \"%s\" failed concatenating arguments to type %s", name, fr_type_to_str(type));
340385
return XLAT_ACTION_FAIL;
341386
}
342387
fr_assert(fr_value_box_list_num_elements(list) <= 1);
343388

389+
/*
390+
* Cast to the type we actually want.
391+
*/
392+
if ((arg->type != FR_TYPE_VOID) && (arg->type != type)) {
393+
goto do_cast;
394+
}
395+
344396
return XLAT_ACTION_DONE;
345397
}
346398

@@ -361,9 +413,10 @@ do { \
361413
ESCAPE(arg, vb, arg_num);
362414

363415
if ((arg->type != FR_TYPE_VOID) && (vb->type != arg->type)) {
364-
cast_error:
416+
do_cast:
365417
if (fr_value_box_cast_in_place(ctx, vb,
366418
arg->type, NULL) < 0) {
419+
cast_error:
367420
RPEDEBUG("Function \"%s\" failed to cast argument %u to type %s", name, arg_num, fr_type_to_str(arg->type));
368421
return XLAT_ACTION_FAIL;
369422
}
@@ -385,7 +438,7 @@ do { \
385438
} while ((vb = fr_value_box_list_next(list, vb)));
386439

387440
/*
388-
* If it's not a void type we still need to escape the values
441+
* If it's a void type we still need to escape the values
389442
*/
390443
} else if (arg->func) {
391444
do ESCAPE(arg, vb, arg_num); while ((vb = fr_value_box_list_next(list, vb)));
@@ -408,15 +461,17 @@ do { \
408461
* List will be modified in accordance to rules
409462
* provided in the args array.
410463
* @param[in] request being processed.
411-
* @param[in] func to call
464+
* @param[in] node which is a function
412465
*/
413466
static inline CC_HINT(always_inline)
414467
xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
415-
request_t *request, xlat_t const *func)
468+
request_t *request, xlat_exp_t const *node)
416469
{
470+
xlat_t const *func = node->call.func;
417471
xlat_arg_parser_t const *arg_p = func->args;
472+
xlat_exp_t *arg, *arg_next;
418473
xlat_action_t xa;
419-
fr_value_box_t *vb, *next;
474+
fr_value_box_t *vb, *vb_next;
420475

421476
/*
422477
* No args registered for this xlat
@@ -435,6 +490,8 @@ xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
435490
*/
436491
case XLAT_INPUT_ARGS:
437492
vb = fr_value_box_list_head(list);
493+
arg = xlat_exp_head(node->call.args);
494+
438495
while (arg_p->type != FR_TYPE_NULL) {
439496
/*
440497
* Separate check to see if the group
@@ -467,8 +524,10 @@ xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
467524
* pre-advance, in case the vb is replaced
468525
* during processing.
469526
*/
470-
next = fr_value_box_list_next(list, vb);
471-
xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p,
527+
vb_next = fr_value_box_list_next(list, vb);
528+
arg_next = xlat_exp_next(node->call.args, arg);
529+
530+
xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p, arg,
472531
(unsigned int)((arg_p - func->args) + 1));
473532
if (xa != XLAT_ACTION_DONE) return xa;
474533

@@ -550,11 +609,12 @@ xlat_action_t xlat_process_args(TALLOC_CTX *ctx, fr_value_box_list_t *list,
550609

551610
do_next:
552611
if (arg_p->variadic) {
553-
if (!next) break;
612+
if (!vb_next) break;
554613
} else {
555614
arg_p++;
615+
arg = arg_next;
556616
}
557-
vb = next;
617+
vb = vb_next;
558618
}
559619
break;
560620
}
@@ -983,7 +1043,7 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
9831043
* the async function mucks with it.
9841044
*/
9851045
if (RDEBUG_ENABLED2) fr_value_box_list_acopy(unlang_interpret_frame_talloc_ctx(request), &result_copy, result);
986-
xa = xlat_process_args(ctx, result, request, node->call.func);
1046+
xa = xlat_process_args(ctx, result, request, node);
9871047
if (xa == XLAT_ACTION_FAIL) {
9881048
fr_value_box_list_talloc_free(&result_copy);
9891049
return xa;
@@ -1053,9 +1113,6 @@ xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
10531113
fr_value_box_list_move(&arg->vb_group, result);
10541114
}
10551115

1056-
// xlat_debug_log_expansion(request, *in, NULL, __LINE__);
1057-
// xlat_debug_log_result(request, *in, arg);
1058-
10591116
VALUE_BOX_VERIFY(arg);
10601117

10611118
fr_dcursor_insert(out, arg);

0 commit comments

Comments
 (0)