From: Enrico Lorenzoni Date: Mon, 26 Aug 2024 08:44:25 +0000 (+0100) Subject: iptv: handle relative key URL X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=221400c9f2d41e974cc8f96269e65c1b2e20dce1;p=thirdparty%2Ftvheadend.git iptv: handle relative key URL --- diff --git a/src/input/mpegts/iptv/iptv_http.c b/src/input/mpegts/iptv/iptv_http.c index 7d599deff..d5289ece8 100644 --- a/src/input/mpegts/iptv/iptv_http.c +++ b/src/input/mpegts/iptv/iptv_http.c @@ -347,6 +347,69 @@ iptv_http_reconnect ( http_client_t *hc, const char *url ) urlreset(&u); } +/* + * Return the index of the last occurrence of character `x` in string `s` + */ +static +int last_index_of(const char *s, char x) { + int i; + int len = strlen(s); + assert(s != NULL); + for (i = len - 1; i >= 0; i--) { + if (s[i] == x) { + return i; + } + } + return -1; // x not found +} + +/* + * Allocates a string with the absolute URL obtained by merging the absolute base and the relative URLs + */ +static char * merge_absolute_and_relative_urls(const char * absolute_url, const char * relative_url) { + size_t absoute_key_url_len, last_slash_pos; + char * absolute_key_url; + const unsigned int max_levels = 100; + int i; + + // allocate enough memory to contain `s` + `url` + \0 + absoute_key_url_len = strlen(absolute_url) + strlen(relative_url) + 1; + absolute_key_url = (char*)malloc(absoute_key_url_len); + memset(absolute_key_url, 0, absoute_key_url_len); + + // copy the url up to the last / + // http://test/ab/cd becomes http://test/ab/ + last_slash_pos = last_index_of(absolute_url, '/'); + assert(last_slash_pos < absoute_key_url_len); + assert(last_slash_pos > 0); + memcpy(absolute_key_url, absolute_url, last_slash_pos+1); + + for (i = 0; i < max_levels && (strncmp(relative_url, "../", strlen("../")) == 0); i++) { + // skip `../` in relative_url + relative_url = relative_url + 3; + + // replace the last / with \0 + // http://test/ab/ becomes http://test/ab + last_slash_pos = last_index_of(absolute_key_url, '/'); + assert(last_slash_pos < absoute_key_url_len); + assert(last_slash_pos > 0); + absolute_key_url[last_slash_pos] = 0; + + // keep until the remaining / + // http://test/ab becomes http://test/ + last_slash_pos = last_index_of(absolute_key_url, '/'); + assert(last_slash_pos < absoute_key_url_len); + assert(last_slash_pos > 0); + absolute_key_url[last_slash_pos+1] = 0; + } + + // concat `s` to the base URL + assert(strlen(absolute_key_url) + strlen(relative_url) < absoute_key_url_len); + memcpy(absolute_key_url+strlen(absolute_key_url), relative_url, strlen(relative_url)+1); + + return absolute_key_url; +} + static int iptv_http_complete ( http_client_t *hc ) @@ -356,6 +419,7 @@ iptv_http_complete char *url; htsmsg_t *m, *m2; int r; + char * absolute_key_url = NULL; if (hp == NULL || hp->shutdown || hp->im == NULL) return 0; @@ -396,13 +460,20 @@ url: tvherror(LS_IPTV, "no URI in KEY attribute"); goto end; } + if (memcmp(s, "../", strlen("../")) == 0) { + tvhtrace(LS_IPTV, "KEY URI: relative URL detected (%s), rewriting it", s); + absolute_key_url = merge_absolute_and_relative_urls(url, s); + s = absolute_key_url; + tvhtrace(LS_IPTV, "new KEY URI: '%s'", s); + } hp->hls_encrypted = 1; if (strcmp(hp->hls_key_url ?: "", s)) { free(hp->hls_key_url); hp->hls_key_url = strdup(s); free(hp->hls_url_after_key); hp->hls_url_after_key = url; - url = strdup(s); + url = strdup(s); + free(absolute_key_url); hc->hc_data_complete = iptv_http_complete_key; sbuf_reset(&hp->key_sbuf, 32); }