From 7b1ce7852bda14ded502226ebdc3f3ffee65f0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Tue, 1 Feb 2011 22:43:22 +0100 Subject: [PATCH] Initial ticket support, needs testing --- src/access.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ src/access.h | 24 +++++++- src/http.c | 9 +++ src/http.h | 5 -- src/webui/webui.c | 13 +++-- 5 files changed, 176 insertions(+), 12 deletions(-) diff --git a/src/access.c b/src/access.c index e04f7ad5..696822f2 100644 --- a/src/access.c +++ b/src/access.c @@ -37,10 +37,144 @@ #include "settings.h" struct access_entry_queue access_entries; +struct access_ticket_queue access_tickets; const char *superuser_username; const char *superuser_password; +static pthread_mutex_t access_ticket_mutex; + +/** + * + */ +static void +access_ticket_destroy(access_ticket_t *at) +{ + free(at->at_id); + free(at->at_resource); + TAILQ_REMOVE(&access_tickets, at, at_link); + free(at); +} + +/** + * + */ +static access_ticket_t * +access_ticket_find(const char *id) +{ + access_ticket_t *at = NULL; + + if(id != NULL) { + TAILQ_FOREACH(at, &access_tickets, at_link) + if(!strcmp(at->at_id, id)) + return at; + } + + return NULL; +} + +/** + * + */ +static void +access_ticket_timout(void *aux) +{ + access_ticket_t *at = aux; + + pthread_mutex_lock(&access_ticket_mutex); + access_ticket_destroy(at); + pthread_mutex_unlock(&access_ticket_mutex); +} + +/** + * Create a new ticket for the requested resource and generate a id for it + */ +const char * +access_ticket_create(const char *resource) +{ + uint8_t buf[20]; + char id[41]; + unsigned int i, rnd; + access_ticket_t *at; + SHA_CTX shactx; + + static const char hex_string[16] = "0123456789ABCDEF"; + + pthread_mutex_lock(&access_ticket_mutex); + + at = calloc(1, sizeof(access_ticket_t)); + rnd = time(NULL); + + //Generate a pseudo-random ticket id + SHA_Init(&shactx); + for(i=0; i<5; i++) { + SHA_Update(&shactx, (const uint8_t *)&rnd, sizeof(int)); + rnd = rand_r(&rnd); + } + SHA_Final(buf, &shactx); + + //convert to hexstring + for(i=0; i> 4) & 0xF)]; + id[(i*2)+1] = hex_string[(buf[i]) & 0x0F]; + } + id[40] = '\0'; + + at->at_id = strdup(id); + at->at_resource = strdup(resource); + + TAILQ_INSERT_TAIL(&access_tickets, at, at_link); + gtimer_arm(&at->at_timer, access_ticket_timout, at, 60*5); + + pthread_mutex_unlock(&access_ticket_mutex); + + return at->at_id; +} + +/** + * + */ +int +access_ticket_delete(const char *id) +{ + access_ticket_t *at; + pthread_mutex_lock(&access_ticket_mutex); + + if((at = access_ticket_find(id)) == NULL) { + pthread_mutex_unlock(&access_ticket_mutex); + return -1; + } + + gtimer_disarm(&at->at_timer); + access_ticket_destroy(at); + + pthread_mutex_unlock(&access_ticket_mutex); + return 0; +} + +/** + * + */ +int +access_ticket_verify(const char *id, const char *resource) +{ + access_ticket_t *at; + + pthread_mutex_lock(&access_ticket_mutex); + + if((at = access_ticket_find(id)) == NULL) { + pthread_mutex_unlock(&access_ticket_mutex); + return -1; + } + + if(strcmp(at->at_resource, resource)) { + pthread_mutex_unlock(&access_ticket_mutex); + return -1; + } + + pthread_mutex_unlock(&access_ticket_mutex); + return 0; +} /** * @@ -424,6 +558,9 @@ access_init(int createdefault) const char *s; TAILQ_INIT(&access_entries); + TAILQ_INIT(&access_tickets); + + pthread_mutex_init(&access_ticket_mutex, NULL); dt = dtable_create(&access_dtc, "accesscontrol", NULL); diff --git a/src/access.h b/src/access.h index 834a372c..7af118e2 100644 --- a/src/access.h +++ b/src/access.h @@ -42,14 +42,36 @@ typedef struct access_entry { uint32_t ae_netmask; /* derived from ae_prefixlen */ } access_entry_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_ticket_t; #define ACCESS_STREAMING 0x1 #define ACCESS_WEB_INTERFACE 0x2 #define ACCESS_RECORDER 0x4 #define ACCESS_ADMIN 0x8 - #define ACCESS_FULL 0x3f +/** + * Create a new ticket for the requested resource and generate a id for it + */ +const char* access_ticket_create(const char *resource); + +/** + * Verifies that a given ticket id matches a resource + */ +int access_ticket_verify(const char *id, const char *resource); + +int access_ticket_delete(const char *ticket_id); /** * Verifies that the given user in combination with the source ip * complies with the requested mask diff --git a/src/http.c b/src/http.c index ea8a4f98..9cca5036 100644 --- a/src/http.c +++ b/src/http.c @@ -308,6 +308,15 @@ http_redirect(http_connection_t *hc, const char *location) int http_access_verify(http_connection_t *hc, int mask) { + const char *ticket_id = http_arg_get(&hc->hc_req_args, "ticket"); + + if(!access_ticket_verify(ticket_id, hc->hc_url)) { + tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s", + inet_ntoa(hc->hc_peer->sin_addr), ticket_id, + hc->hc_url); + return 0; + } + return access_verify(hc->hc_username, hc->hc_password, (struct sockaddr *)hc->hc_peer, mask); } diff --git a/src/http.h b/src/http.h index 8cc497c3..27897dfe 100644 --- a/src/http.h +++ b/src/http.h @@ -80,11 +80,6 @@ typedef struct http_connection { char *hc_username; char *hc_password; - int hc_authenticated; /* Used by RTSP, it seems VLC does not - send authentication headers for each - command, so we just say that it's ok - if it has authenticated at least once */ - struct config_head *hc_user_config; int hc_no_output; diff --git a/src/webui/webui.c b/src/webui/webui.c index c2060b92..13e754f4 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -243,6 +243,9 @@ static void http_stream_playlist(http_connection_t *hc, channel_t *channel) { htsbuf_queue_t *hq = &hc->hc_reply; + char buf[255]; + const char *ticket_id = NULL; + channel_t *ch = NULL; const char *host = http_arg_get(&hc->hc_args, "Host"); @@ -252,7 +255,10 @@ http_stream_playlist(http_connection_t *hc, channel_t *channel) RB_FOREACH(ch, &channel_name_tree, ch_name_link) { if (channel == NULL || ch == channel) { htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", ch->ch_name); - htsbuf_qprintf(hq, "http://%s/stream/channelid/%d\n", host, ch->ch_id); + + snprintf(buf, sizeof(buf), "/stream/channelid/%d", ch->ch_id); + ticket_id = access_ticket_create(buf); + htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf, ticket_id); } } @@ -385,11 +391,6 @@ http_stream(http_connection_t *hc, const char *remain, void *opaque) channel_t *ch = NULL; service_t *service = NULL; - if(http_access_verify(hc, ACCESS_STREAMING)) { - http_error(hc, HTTP_STATUS_UNAUTHORIZED); - return HTTP_STATUS_UNAUTHORIZED; - } - hc->hc_keep_alive = 0; if(remain == NULL) {