From d4a1e05c667137309feb2345486998927d5a8d93 Mon Sep 17 00:00:00 2001 From: Arran Cudbard-Bell Date: Mon, 24 Mar 2014 11:08:36 +0000 Subject: [PATCH] Fix escaping of URI strings passed to %{rest:} --- src/modules/rlm_rest/rest.c | 76 ++++++++++++++++++++++++++++----- src/modules/rlm_rest/rest.h | 3 ++ src/modules/rlm_rest/rlm_rest.c | 15 ++++--- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/modules/rlm_rest/rest.c b/src/modules/rlm_rest/rest.c index 6e7d67d2b005..77e09b98f03a 100644 --- a/src/modules/rlm_rest/rest.c +++ b/src/modules/rlm_rest/rest.c @@ -2104,7 +2104,7 @@ int rest_response_decode(rlm_rest_t *instance, UNUSED rlm_rest_section_t *sectio * @param[in] section configuration data. * @param[in] handle to cleanup. */ -void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,void *handle) +void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section, void *handle) { rlm_rest_handle_t *randle = handle; rlm_rest_curl_context_t *ctx = randle->ctx; @@ -2145,7 +2145,7 @@ void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t * @param[in] arg pointer, gives context for escaping. * @return length of data written to out (excluding NULL). */ -static size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg) +size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg) { char *escaped; @@ -2171,13 +2171,13 @@ static size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, */ ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, char const *uri) { - char const *p; - char *path_exp = NULL; + char const *p; + char *path_exp = NULL; - char *scheme; - char const *path; + char *scheme; + char const *path; - ssize_t len, outlen; + ssize_t len; p = uri; @@ -2212,7 +2212,6 @@ ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request return 0; } - outlen = len; len = radius_axlat(&path_exp, request, path, rest_uri_escape, NULL); if (len < 0) { @@ -2221,8 +2220,65 @@ ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request return 0; } - *out = talloc_strdup_append(*out, path_exp); + MEM(*out = talloc_strdup_append(*out, path_exp)); talloc_free(path_exp); - return outlen += len; + return talloc_array_length(*out) - 1; /* array_length includes \0 */ +} + +/** Unescapes the host portion of a URI string + * + * This is required because the xlat functions which operate on the input string + * cannot distinguish between host and path components. + * + * @param[out] out Where to write the pointer to the new buffer containing the escaped URI. + * @param[in] instance configuration data. + * @param[in] uri configuration data. + * @param[in] request Current request + * @return length of data written to buffer (excluding NULL) or < 0 if an error + * occurred. + */ +ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, + void *handle, char const *uri) +{ + rlm_rest_handle_t *randle = handle; + CURL *candle = randle->handle; + + char const *p; + + char *scheme; + + ssize_t len; + + p = uri; + + /* + * All URLs must contain at least :/// + */ + p = strchr(p, ':'); + if (!p || (*++p != '/') || (*++p != '/')) { + malformed: + REDEBUG("Error URI is malformed, can't find start of path"); + return -1; + } + p = strchr(p + 1, '/'); + if (!p) { + goto malformed; + } + + len = (p - uri); + + /* + * Unescape any special sequences in the first part of the URI + */ + scheme = curl_easy_unescape(candle, uri, len, NULL); + if (!scheme) { + REDEBUG("Error unescaping host"); + return -1; + } + + MEM(*out = talloc_asprintf(request, "%s%s", scheme, p)); + curl_free(scheme); + + return talloc_array_length(*out) - 1; /* array_length includes \0 */ } diff --git a/src/modules/rlm_rest/rest.h b/src/modules/rlm_rest/rest.h index 2a9a3918fa27..3b26303dbaff 100644 --- a/src/modules/rlm_rest/rest.h +++ b/src/modules/rlm_rest/rest.h @@ -264,4 +264,7 @@ size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle); /* * Helper functions */ +size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg); ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri); +ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, + void *handle, char const *uri); diff --git a/src/modules/rlm_rest/rlm_rest.c b/src/modules/rlm_rest/rlm_rest.c index ad6f4925c68a..cf632c1bfa51 100644 --- a/src/modules/rlm_rest/rlm_rest.c +++ b/src/modules/rlm_rest/rlm_rest.c @@ -161,18 +161,21 @@ static ssize_t rest_xlat(void *instance, REQUEST *request, RDEBUG("Expanding URI components"); + handle = fr_connection_get(inst->conn_pool); + if (!handle) return -1; + /* * Build xlat'd URI, this allows REST servers to be specified by * request attributes. */ - len = rest_uri_build(&uri, instance, request, fmt); - if (len <= 0) return -1; + len = rest_uri_host_unescape(&uri, instance, request, handle, fmt); + if (len <= 0) { + outlen = -1; + goto end; + } RDEBUG("Sending HTTP %s to \"%s\"", fr_int2str(http_method_table, section.method, NULL), uri); - handle = fr_connection_get(inst->conn_pool); - if (!handle) return -1; - /* * Configure various CURL options, and initialise the read/write * context data. @@ -539,7 +542,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * Register the rest xlat function */ - xlat_register(inst->xlat_name, rest_xlat, NULL, inst); + xlat_register(inst->xlat_name, rest_xlat, rest_uri_escape, inst); /* * Parse sub-section configs.