ACL: add full rights copy for tickets to resolve connection counting, fixes #2349

This commit is contained in:
Jaroslav Kysela 2014-10-07 18:21:35 +02:00
parent 5b3f64834a
commit a510248efc
5 changed files with 74 additions and 40 deletions

View file

@ -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);

View file

@ -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

View file

@ -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'");
}

View file

@ -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;
}
/**

View file

@ -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");