From: Alan T. DeKok Date: Thu, 21 Dec 2023 12:56:10 +0000 (-0500) Subject: update for string expansions on RHS of SQL X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d0478b2250d9d44ffb9ef7a7e6aa029fea630da0;p=thirdparty%2Ffreeradius-server.git update for string expansions on RHS of SQL and add tests --- diff --git a/src/lib/server/map.c b/src/lib/server/map.c index b9631f1f860..77df3f724d8 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -35,6 +35,8 @@ RCSID("$Id$") #include #include +#include + #include #include #include @@ -2429,6 +2431,7 @@ void map_debug_log(request_t *request, map_t const *map, fr_pair_t const *vp) * * @param[in] ctx where to allocate the map. * @param[out] out Where to write the new map (must be freed with talloc_free()). + * @param[in] request the request * @param[in] lhs of map * @param[in] op of map * @param[in] rhs of map @@ -2438,7 +2441,7 @@ void map_debug_log(request_t *request, map_t const *map, fr_pair_t const *vp) * - 0 on success. * - -1 on failure. */ -int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const *op, char const *rhs, +int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, request_t *request, char const *lhs, char const *op, char const *rhs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules) { ssize_t slen; @@ -2496,6 +2499,7 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const * my_rules = *rhs_rules; my_rules.at_runtime = true; + my_rules.xlat.runtime_el = unlang_interpret_event_list(request); my_rules.enumv = tmpl_attr_tail_da(map->lhs); /* @@ -2519,12 +2523,36 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const * goto parse_quoted; } else if (rhs[0] == '\'') { + size_t len; + quote = T_SINGLE_QUOTED_STRING; parse_quoted: - slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN(rhs, strlen(rhs)), + len = strlen(rhs + 1); + if (len == 1) { + if (rhs[1] != rhs[0]) { + fr_strerror_const("Invalid string on right side"); + return -1; + } + + rhs = ""; + goto alloc_empty; + } + + slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN(rhs + 1, len - 1), quote, value_parse_rules_quoted[quote], &my_rules); - if (slen <= 0) goto error; + if (slen < 0) goto error; + + if (slen == 0) { + rhs = ""; + goto alloc_empty; + } + + ERROR("CONVERT %s --> %s", rhs, map->rhs->name); + + /* + * Ignore any extra data after the string. + */ } else if (rhs[0] == '&') { /* @@ -2539,8 +2567,10 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const * if (slen <= 0) goto error; } else if (!rhs[0] || !my_rules.enumv || (my_rules.enumv->type == FR_TYPE_STRING)) { + quote = T_BARE_WORD; - MEM(map->rhs = tmpl_alloc(map, TMPL_TYPE_DATA, T_BARE_WORD, rhs, strlen(rhs))); + alloc_empty: + MEM(map->rhs = tmpl_alloc(map, TMPL_TYPE_DATA, quote, rhs, strlen(rhs))); (void) fr_value_box_strdup(map->rhs, tmpl_value(map->rhs), NULL, rhs, false); @@ -2551,8 +2581,17 @@ int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const * slen = tmpl_afrom_substr(map, &map->rhs, &FR_SBUFF_IN(rhs, strlen(rhs)), T_BARE_WORD, value_parse_rules_unquoted[T_BARE_WORD], &my_rules); if (slen <= 0) goto error; + } + + if (tmpl_needs_resolving(map->rhs)) { + tmpl_res_rules_t tr_rules = (tmpl_res_rules_t) { + .dict_def = lhs_rules->attr.dict_def, + .enumv = tmpl_attr_tail_da(map->lhs) + }; + + fr_assert(tmpl_is_data_unresolved(map->rhs)); - fr_assert(!tmpl_needs_resolving(map->rhs)); + if (tmpl_resolve(map->rhs, &tr_rules) < 0) goto error; } /* diff --git a/src/lib/server/map.h b/src/lib/server/map.h index 8ee0e7d4146..f6caf8a1bc5 100644 --- a/src/lib/server/map.h +++ b/src/lib/server/map.h @@ -149,7 +149,7 @@ ssize_t map_afrom_substr(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, fr_sbu tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, fr_sbuff_parse_rules_t const *p_rules); -int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, char const *lhs, char const *op, char const *rhs, +int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, request_t *request, char const *lhs, char const *op, char const *rhs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules) CC_HINT(nonnull); int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, diff --git a/src/modules/rlm_sql/sql.c b/src/modules/rlm_sql/sql.c index 482a7deba16..e56dd7ea5f4 100644 --- a/src/modules/rlm_sql/sql.c +++ b/src/modules/rlm_sql/sql.c @@ -593,7 +593,7 @@ int sql_get_map_list(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, while (rlm_sql_fetch_row(&row, inst, request, handle) == RLM_SQL_OK) { map_t *map; - if (map_afrom_fields(ctx, &map, row[2], row[4], row[3], &lhs_rules, &rhs_rules) < 0) { + if (map_afrom_fields(ctx, &map, request, row[2], row[4], row[3], &lhs_rules, &rhs_rules) < 0) { RPEDEBUG("Error parsing user data from database result"); (inst->driver->sql_finish_select_query)(*handle, &inst->config); return -1; diff --git a/src/tests/modules/sql_sqlite/xlat.attrs b/src/tests/modules/sql_sqlite/xlat.attrs new file mode 100644 index 00000000000..3e1af7b75a5 --- /dev/null +++ b/src/tests/modules/sql_sqlite/xlat.attrs @@ -0,0 +1,13 @@ +# +# Input packet +# +Packet-Type = Access-Request +User-Name = "xlat" +User-Password = "password" +NAS-IP-Address = "1.2.3.4" + +# +# Expected answer +# +Packet-Type == Access-Accept +Reply-Message == "Hello xlat" diff --git a/src/tests/modules/sql_sqlite/xlat.unlang b/src/tests/modules/sql_sqlite/xlat.unlang new file mode 100644 index 00000000000..1f45d34cce7 --- /dev/null +++ b/src/tests/modules/sql_sqlite/xlat.unlang @@ -0,0 +1,15 @@ +# +# Clear out old data +# +%sql("${delete_from_radcheck} 'xlat'") +%sql("${delete_from_radreply} 'xlat'") + +if (%sql("${insert_into_radcheck} ('xlat', 'Password.Cleartext', ':=', 'password')") != "1") { + test_fail +} + +if (%sql("${insert_into_radreply} ('xlat', 'Reply-Message', ':=', '\"Hello \%{User-Name}\"')") != "1") { + test_fail +} + +sql