Skip to content

Commit ed63f4e

Browse files
committed
tweak lhs/rhs handling rules, and require well-formed strings
use different rules for local LHS / RHS, which ensures that there's no aliasing, and that the local rules updates don't mangle each other. There were corner cases where the LHS rules would get over-written in the tmpl_needs_resolving() condition near the end of the file. Complain if quoted strings on the RHS aren't well formed. Add a test for this case, too
1 parent 3b22192 commit ed63f4e

File tree

9 files changed

+75
-29
lines changed

9 files changed

+75
-29
lines changed

src/lib/server/map.c

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,8 +1839,8 @@ int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t co
18391839
return map_exec_to_vp(ctx, out, request, map);
18401840

18411841
default:
1842+
fr_sterror_const("Internal sanity check failure");
18421843
rcode = -1;
1843-
fr_assert(0); /* Should have been caught at parse time */
18441844
error:
18451845
talloc_free(n);
18461846
return rcode;
@@ -2534,7 +2534,7 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
25342534
fr_token_t quote, op;
25352535
map_t *map;
25362536
map_t *parent = *parent_p;
2537-
tmpl_rules_t my_rules;
2537+
tmpl_rules_t my_lhs_rules, my_rhs_rules;
25382538

25392539
op = fr_table_value_by_str(fr_tokens_table, op_str, T_INVALID);
25402540
if (op == T_INVALID) {
@@ -2557,8 +2557,8 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
25572557
return -1;
25582558
}
25592559

2560-
my_rules = *lhs_rules;
2561-
lhs_rules = &my_rules;
2560+
my_lhs_rules = *lhs_rules;
2561+
lhs_rules = &my_lhs_rules;
25622562

25632563
/*
25642564
* We're only called from SQL. If the default list is request, then we only use that for
@@ -2568,7 +2568,7 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
25682568
* this flag. But this function already has parameter overload :(
25692569
*/
25702570
if (fr_assignment_op[op] && (lhs_rules->attr.list_def == request_attr_request)) {
2571-
my_rules.attr.list_def = request_attr_control;
2571+
my_lhs_rules.attr.list_def = request_attr_control;
25722572
}
25732573

25742574
/*
@@ -2616,7 +2616,7 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
26162616
*/
26172617
if (parent) {
26182618
fr_assert(tmpl_is_attr(parent->lhs));
2619-
my_rules.attr.namespace = tmpl_attr_tail_da(parent->lhs);
2619+
my_lhs_rules.attr.namespace = tmpl_attr_tail_da(parent->lhs);
26202620

26212621
slen = tmpl_afrom_attr_substr(map, NULL, &map->lhs, &FR_SBUFF_IN_STR(lhs),
26222622
&map_parse_rules_bareword_quoted, lhs_rules);
@@ -2646,17 +2646,17 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
26462646
goto error;
26472647
}
26482648

2649-
my_rules = *rhs_rules;
2650-
my_rules.at_runtime = true;
2651-
my_rules.xlat.runtime_el = unlang_interpret_event_list(request);
2652-
my_rules.enumv = tmpl_attr_tail_da(map->lhs);
2649+
my_rhs_rules = *rhs_rules;
2650+
my_rhs_rules.at_runtime = true;
2651+
my_rhs_rules.xlat.runtime_el = unlang_interpret_event_list(request);
2652+
my_rhs_rules.enumv = tmpl_attr_tail_da(map->lhs);
26532653

26542654
/*
26552655
* LHS is a structureal type. The RHS is either empty (create empty LHS), or it's a string
26562656
* containing a list of attributes to create.
26572657
*/
2658-
if (!fr_type_is_leaf(my_rules.enumv->type)) {
2659-
my_rules.enumv = NULL;
2658+
if (!fr_type_is_leaf(my_rhs_rules.enumv->type)) {
2659+
my_rhs_rules.enumv = NULL;
26602660
}
26612661

26622662
/*
@@ -2679,14 +2679,14 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
26792679
/*
26802680
* No value, or no enum, parse it as a bare-word string.
26812681
*/
2682-
if (!rhs[0] || !my_rules.enumv) goto do_bare_word;
2682+
if (!rhs[0] || !my_rhs_rules.enumv) goto do_bare_word;
26832683

2684-
MEM(vb = fr_value_box_alloc(map, my_rules.enumv->type, my_rules.enumv));
2684+
MEM(vb = fr_value_box_alloc(map, my_rhs_rules.enumv->type, my_rhs_rules.enumv));
26852685

26862686
/*
26872687
* It MUST be the given data type.
26882688
*/
2689-
slen = fr_value_box_from_str(map, vb, my_rules.enumv->type, my_rules.enumv,
2689+
slen = fr_value_box_from_str(map, vb, my_rhs_rules.enumv->type, my_rhs_rules.enumv,
26902690
rhs, strlen(rhs), NULL);
26912691
if (slen <= 0) goto error;
26922692

@@ -2722,12 +2722,24 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
27222722
goto alloc_empty;
27232723
}
27242724

2725-
slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN(rhs + 1, len - 1),
2726-
quote, value_parse_rules_quoted[quote], &my_rules);
2725+
slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN(rhs + 1, len),
2726+
quote, value_parse_rules_quoted[quote], &my_rhs_rules);
27272727
if (slen < 0) {
27282728
REDEBUG3("Failed parsing right-hand side as quoted string.");
27292729
fail_rhs:
2730-
fr_strerror_printf("Failed parsing right-hand side: %s", fr_strerror());
2730+
fr_strerror_printf("Failed parsing right-hand side, %s", fr_strerror());
2731+
goto error;
2732+
}
2733+
2734+
fr_assert((size_t) slen <= (len + 1));
2735+
2736+
if (rhs[slen + 1] != rhs[0]) {
2737+
fr_strerror_printf("Failed parsing right-hand side, missing end quote in ... %s", rhs);
2738+
goto error;
2739+
}
2740+
2741+
if (rhs[slen + 2]) {
2742+
fr_strerror_const("Failed parsing right-hand side, unexpected data after end quote");
27312743
goto error;
27322744
}
27332745

@@ -2736,28 +2748,22 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
27362748
goto alloc_empty;
27372749
}
27382750

2739-
/*
2740-
* Ignore any extra data after the string.
2741-
*
2742-
* @todo - this should likely be a parse error: we didn't parse the entire string!
2743-
*/
2744-
27452751
} else if (rhs[0] == '&') {
27462752
/*
27472753
* No enums here.
27482754
*/
2749-
fr_assert(my_rules.attr.list_def == request_attr_request);
2755+
fr_assert(my_rhs_rules.attr.list_def == request_attr_request);
27502756

27512757
parse_as_attr:
2752-
my_rules.enumv = NULL;
2758+
my_rhs_rules.enumv = NULL;
27532759

2754-
slen = tmpl_afrom_attr_str(map, NULL, &map->rhs, rhs, &my_rules);
2760+
slen = tmpl_afrom_attr_str(map, NULL, &map->rhs, rhs, rhs_rules);
27552761
if (slen <= 0) {
27562762
REDEBUG3("Failed parsing right-hand side as attribute.");
27572763
goto fail_rhs;
27582764
}
27592765

2760-
} else if (!rhs[0] || !my_rules.enumv || (my_rules.enumv->type == FR_TYPE_STRING)) {
2766+
} else if (!rhs[0] || !my_rhs_rules.enumv || (my_rhs_rules.enumv->type == FR_TYPE_STRING)) {
27612767
do_bare_word:
27622768
quote = T_BARE_WORD;
27632769

@@ -2778,7 +2784,7 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *
27782784
* Parse it as the given data type.
27792785
*/
27802786
slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN_STR(rhs),
2781-
T_BARE_WORD, value_parse_rules_unquoted[T_BARE_WORD], &my_rules);
2787+
T_BARE_WORD, value_parse_rules_unquoted[T_BARE_WORD], &my_rhs_rules);
27822788
if (slen <= 0) {
27832789
goto parse_as_attr;
27842790
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# Input packet
3+
#
4+
Packet-Type = Access-Request
5+
User-Name = "user_auth"
6+
User-Password = "password"
7+
NAS-IP-Address = "1.2.3.4"
8+
9+
#
10+
# Expected answer
11+
#
12+
Packet-Type == Access-Reject
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#
2+
# Clear out old data
3+
#
4+
%sql("${delete_from_radcheck} 'user_auth'")
5+
%sql("${delete_from_radreply} 'user_auth'")
6+
7+
if (%sql("${insert_into_radcheck} ('user_auth', 'NAS-IP-Address', '==', '1.2.3.4')") != "1") {
8+
test_fail
9+
}
10+
11+
if (%sql("${insert_into_radcheck} ('user_auth', 'Password.Cleartext', ':=', 'password')") != "1") {
12+
test_fail
13+
}
14+
15+
if (%sql("${insert_into_radreply} ('user_auth', 'Reply-Message', ':=', '\"whoops')") != "1") {
16+
test_fail
17+
}
18+
19+
sql
20+
if (!fail) {
21+
test_fail
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.attrs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.unlang
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.attrs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.unlang
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.attrs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../sql/auth_fail.unlang

0 commit comments

Comments
 (0)