From a510248efc719a7052e7b36d27a9550f3826933e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 7 Oct 2014 18:21:35 +0200 Subject: [PATCH] ACL: add full rights copy for tickets to resolve connection counting, fixes #2349 --- src/access.c | 39 +++++++++++++++++++++++++++++++++------ src/access.h | 36 +++++++++++++++++++++--------------- src/htsp_server.c | 4 ++-- src/http.c | 23 ++++++++++++----------- src/webui/webui.c | 12 ++++++------ 5 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/access.c b/src/access.c index e6cbebd6..27f6dec8 100644 --- a/src/access.c +++ b/src/access.c @@ -57,6 +57,7 @@ access_ticket_destroy(access_ticket_t *at) free(at->at_id); free(at->at_resource); TAILQ_REMOVE(&access_tickets, at, at_link); + access_destroy(at->at_access); free(at); } @@ -92,7 +93,7 @@ access_ticket_timout(void *aux) * Create a new ticket for the requested resource and generate a id for it */ const char * -access_ticket_create(const char *resource) +access_ticket_create(const char *resource, access_t *a) { uint8_t buf[20]; char id[41]; @@ -100,6 +101,8 @@ access_ticket_create(const char *resource) access_ticket_t *at; static const char hex_string[16] = "0123456789ABCDEF"; + assert(a); + at = calloc(1, sizeof(access_ticket_t)); RAND_bytes(buf, 20); @@ -114,6 +117,8 @@ access_ticket_create(const char *resource) at->at_id = strdup(id); at->at_resource = strdup(resource); + at->at_access = access_copy(a); + TAILQ_INSERT_TAIL(&access_tickets, at, at_link); gtimer_arm(&at->at_timer, access_ticket_timout, at, 60*5); @@ -140,18 +145,37 @@ access_ticket_delete(const char *id) /** * */ -int -access_ticket_verify(const char *id, const char *resource) +access_t * +access_ticket_verify2(const char *id, const char *resource) { access_ticket_t *at; if((at = access_ticket_find(id)) == NULL) - return -1; + return NULL; if(strcmp(at->at_resource, resource)) - return -1; + return NULL; - return 0; + return access_copy(at->at_access); +} + +/** + * + */ +access_t * +access_copy(access_t *src) +{ + access_t *dst = malloc(sizeof(*dst)); + *dst = *src; + if (src->aa_username) + dst->aa_username = strdup(src->aa_username); + if (src->aa_representative) + dst->aa_representative = strdup(src->aa_representative); + if (src->aa_dvrcfgs) + dst->aa_dvrcfgs = htsmsg_copy(src->aa_dvrcfgs); + if (src->aa_chtags) + dst->aa_chtags = htsmsg_copy(src->aa_chtags); + return dst; } /** @@ -1207,10 +1231,13 @@ void access_done(void) { access_entry_t *ae; + access_ticket_t *at; pthread_mutex_lock(&global_lock); while ((ae = TAILQ_FIRST(&access_entries)) != NULL) access_entry_destroy(ae); + while ((at = TAILQ_FIRST(&access_tickets)) != NULL) + access_ticket_destroy(at); free((void *)superuser_username); superuser_username = NULL; free((void *)superuser_password); diff --git a/src/access.h b/src/access.h index 21d62a90..12189a3f 100644 --- a/src/access.h +++ b/src/access.h @@ -79,19 +79,6 @@ typedef struct access_entry { extern const idclass_t access_entry_class; -TAILQ_HEAD(access_ticket_queue, access_ticket); - -extern struct access_ticket_queue access_tickets; - -typedef struct access_ticket { - char *at_id; - - TAILQ_ENTRY(access_ticket) at_link; - - gtimer_t at_timer; - char *at_resource; -} access_ticket_t; - typedef struct access { char *aa_username; char *aa_representative; @@ -104,6 +91,20 @@ typedef struct access { uint32_t aa_conn_limit; } access_t; +TAILQ_HEAD(access_ticket_queue, access_ticket); + +extern struct access_ticket_queue access_tickets; + +typedef struct access_ticket { + char *at_id; + + TAILQ_ENTRY(access_ticket) at_link; + + gtimer_t at_timer; + char *at_resource; + access_t *at_access; +} access_ticket_t; + #define ACCESS_ANONYMOUS 0 #define ACCESS_STREAMING (1<<0) #define ACCESS_ADVANCED_STREAMING (1<<1) @@ -118,12 +119,12 @@ typedef struct access { /** * Create a new ticket for the requested resource and generate a id for it */ -const char* access_ticket_create(const char *resource); +const char* access_ticket_create(const char *resource, access_t *a); /** * Verifies that a given ticket id matches a resource */ -int access_ticket_verify(const char *id, const char *resource); +access_t *access_ticket_verify2(const char *id, const char *resource); int access_ticket_delete(const char *ticket_id); @@ -132,6 +133,11 @@ int access_ticket_delete(const char *ticket_id); */ void access_destroy(access_t *a); +/** + * Copy the access structure + */ +access_t *access_copy(access_t *src); + /** * Verifies that the given user in combination with the source ip * complies with the requested mask diff --git a/src/htsp_server.c b/src/htsp_server.c index da872e13..b3c120c1 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -1653,7 +1653,7 @@ htsp_method_getTicket(htsp_connection_t *htsp, htsmsg_t *in) return htsp_error("User does not have access"); snprintf(path, sizeof(path), "/stream/channelid/%d", id); - ticket = access_ticket_create(path); + ticket = access_ticket_create(path, htsp->htsp_granted_access); } else if(!htsmsg_get_u32(in, "dvrId", &id)) { if (!(de = dvr_entry_find_by_id(id))) return htsp_error("DVR entry does not exist"); @@ -1661,7 +1661,7 @@ htsp_method_getTicket(htsp_connection_t *htsp, htsmsg_t *in) return htsp_error("User does not have access"); snprintf(path, sizeof(path), "/dvrfile/%d", id); - ticket = access_ticket_create(path); + ticket = access_ticket_create(path, htsp->htsp_granted_access); } else { return htsp_error("Missing argument 'channelId' or 'dvrId'"); } diff --git a/src/http.c b/src/http.c index 19ecc4cf..1959b9dc 100644 --- a/src/http.c +++ b/src/http.c @@ -410,19 +410,20 @@ http_redirect(http_connection_t *hc, const char *location, */ static int http_access_verify_ticket(http_connection_t *hc) { - const char *ticket_id = http_arg_get(&hc->hc_req_args, "ticket"); + const char *ticket_id; - if (hc->hc_ticket) + if (hc->hc_ticket || hc->hc_access) return 0; - if(!access_ticket_verify(ticket_id, hc->hc_url)) { - char addrstr[50]; - tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50); - tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s", - addrstr, ticket_id, hc->hc_url); - hc->hc_ticket = 1; - return 0; - } - return -1; + ticket_id = http_arg_get(&hc->hc_req_args, "ticket"); + hc->hc_access = access_ticket_verify2(ticket_id, hc->hc_url); + if (hc->hc_access == NULL) + return -1; + char addrstr[50]; + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50); + tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s", + addrstr, ticket_id, hc->hc_url); + hc->hc_ticket = 1; + return 0; } /** diff --git a/src/webui/webui.c b/src/webui/webui.c index 2b5916e7..1c85657f 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -450,7 +450,7 @@ http_channel_playlist(http_connection_t *hc, channel_t *channel) htsbuf_qprintf(hq, "#EXTM3U\n"); htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel_get_name(channel)); htsbuf_qprintf(hq, "http://%s%s?ticket=%s", host, buf, - access_ticket_create(buf)); + access_ticket_create(buf, hc->hc_access)); #if ENABLE_LIBAV transcoder_props_t props; @@ -506,7 +506,7 @@ http_tag_playlist(http_connection_t *hc, channel_tag_t *tag) snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ctm->ctm_channel)); htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel_get_name(ctm->ctm_channel)); htsbuf_qprintf(hq, "http://%s%s?ticket=%s", host, buf, - access_ticket_create(buf)); + access_ticket_create(buf, hc->hc_access)); htsbuf_qprintf(hq, "&mux=%s\n", muxer_container_type2txt(mc)); } @@ -543,7 +543,7 @@ http_tag_list_playlist(http_connection_t *hc) snprintf(buf, sizeof(buf), "/playlist/tagid/%d", idnode_get_short_uuid(&ct->ct_id)); htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", ct->ct_name); htsbuf_qprintf(hq, "http://%s%s?ticket=%s", host, buf, - access_ticket_create(buf)); + access_ticket_create(buf, hc->hc_access)); htsbuf_qprintf(hq, "&mux=%s\n", muxer_container_type2txt(mc)); } @@ -607,7 +607,7 @@ http_channel_list_playlist(http_connection_t *hc) htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel_get_name(ch)); htsbuf_qprintf(hq, "http://%s%s?ticket=%s", host, buf, - access_ticket_create(buf)); + access_ticket_create(buf, hc->hc_access)); htsbuf_qprintf(hq, "&mux=%s\n", muxer_container_type2txt(mc)); } @@ -662,7 +662,7 @@ http_dvr_list_playlist(http_connection_t *hc) snprintf(buf, sizeof(buf), "/dvrfile/%s", uuid); htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf, - access_ticket_create(buf)); + access_ticket_create(buf, hc->hc_access)); } http_output_content(hc, "audio/x-mpegurl"); @@ -702,7 +702,7 @@ http_dvr_playlist(http_connection_t *hc, dvr_entry_t *de) htsbuf_qprintf(hq, "#EXT-X-PROGRAM-DATE-TIME:%s\n", buf); snprintf(buf, sizeof(buf), "/dvrfile/%s", uuid); - ticket_id = access_ticket_create(buf); + ticket_id = access_ticket_create(buf, hc->hc_access); htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf, ticket_id); http_output_content(hc, "application/x-mpegURL");