Add challenge response authentication to HTSP

This commit is contained in:
Andreas Öman 2009-02-28 15:06:57 +00:00
parent 4a05b28a51
commit ab46458c25
3 changed files with 212 additions and 30 deletions

View file

@ -33,6 +33,8 @@
#include "access.h"
#include "dtable.h"
#include <libavutil/sha1.h>
struct access_entry_queue access_entries;
@ -70,6 +72,70 @@ access_verify(const char *username, const char *password,
return (mask & bits) == mask ? 0 : -1;
}
/**
*
*/
uint32_t
access_get_hashed(const char *username, const uint8_t digest[20],
const uint8_t *challenge, struct sockaddr *src)
{
struct sockaddr_in *si = (struct sockaddr_in *)src;
uint32_t b = ntohl(si->sin_addr.s_addr);
access_entry_t *ae;
struct AVSHA1 *shactx = alloca(av_sha1_size);
uint8_t d[20];
uint32_t r = 0;
TAILQ_FOREACH(ae, &access_entries, ae_link) {
if((b & ae->ae_netmask) != ae->ae_network)
continue; /* IP based access mismatches */
av_sha1_init(shactx);
av_sha1_update(shactx, (const uint8_t *)ae->ae_password,
strlen(ae->ae_password));
av_sha1_update(shactx, challenge, 32);
av_sha1_final(shactx, d);
if(memcmp(d, digest, 20)) /* Nintendo would have use strncmp() here :) */
continue;
r |= ae->ae_rights;
}
return r;
}
/**
*
*/
uint32_t
access_get_by_addr(struct sockaddr *src)
{
struct sockaddr_in *si = (struct sockaddr_in *)src;
uint32_t b = ntohl(si->sin_addr.s_addr);
access_entry_t *ae;
uint32_t r = 0;
TAILQ_FOREACH(ae, &access_entries, ae_link) {
if(ae->ae_username[0] != '*')
continue;
if((b & ae->ae_netmask) != ae->ae_network)
continue; /* IP based access mismatches */
r |= ae->ae_rights;
}
return r;
}
/**
*
*/

View file

@ -59,14 +59,21 @@ typedef struct access_entry {
int access_verify(const char *username, const char *password,
struct sockaddr *src, uint32_t mask);
/**
*
*/
uint32_t access_get_hashed(const char *username, const uint8_t digest[20],
const uint8_t *challenge, struct sockaddr *src);
/**
*
*/
uint32_t access_get_by_addr(struct sockaddr *src);
/**
*
*/
void access_init(void);
//access_entry_t *access_add(const char *id);
//access_entry_t *access_by_id(int id);
//void access_delete(access_entry_t *ae);
//void access_save(void);
#endif /* ACCESS_H_ */

153
htsp.c
View file

@ -114,6 +114,10 @@ typedef struct htsp_connection {
*/
struct th_subscription_list htsp_subscriptions;
uint32_t htsp_granted_access;
uint8_t htsp_challenge[32];
} htsp_connection_t;
/**
@ -240,7 +244,11 @@ htsp_send_message(htsp_connection_t *htsp, htsmsg_t *m, htsp_msg_q_t *hmq)
static htsmsg_t *
htsp_build_channel(channel_t *ch, const char *method)
{
channel_tag_mapping_t *ctm;
channel_tag_t *ct;
htsmsg_t *out = htsmsg_create();
htsmsg_t *tags = htsmsg_create_array();
htsmsg_add_u32(out, "channelId", ch->ch_id);
@ -251,6 +259,13 @@ htsp_build_channel(channel_t *ch, const char *method)
htsmsg_add_u32(out, "eventId",
ch->ch_epg_current != NULL ? ch->ch_epg_current->e_id : 0);
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
ct = ctm->ctm_tag;
if(ct->ct_enabled && !ct->ct_internal)
htsmsg_add_str(tags, NULL, ct->ct_identifier);
}
htsmsg_add_msg(out, "tags", tags);
htsmsg_add_str(out, "method", method);
return out;
}
@ -260,22 +275,24 @@ htsp_build_channel(channel_t *ch, const char *method)
*
*/
static htsmsg_t *
htsp_build_tag(channel_tag_t *ct, const char *method)
htsp_build_tag(channel_tag_t *ct, const char *method, int include_channels)
{
channel_tag_mapping_t *ctm;
htsmsg_t *out = htsmsg_create();
htsmsg_t *members = htsmsg_create_array();
htsmsg_t *out = htsmsg_create();
htsmsg_t *members = include_channels ? htsmsg_create_array() : NULL;
htsmsg_add_str(out, "tagId", ct->ct_identifier);
htsmsg_add_str(out, "tagName", ct->ct_name);
htsmsg_add_str(out, "tagIcon", ct->ct_icon);
htsmsg_add_u32(out, "tagTitledIcon", ct->ct_titled_icon);
LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
htsmsg_add_u32(members, NULL, ctm->ctm_channel->ch_id);
if(members != NULL) {
LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
htsmsg_add_u32(members, NULL, ctm->ctm_channel->ch_id);
htsmsg_add_msg(out, "members", members);
}
htsmsg_add_msg(out, "members", members);
htsmsg_add_str(out, "method", method);
return out;
}
@ -288,7 +305,7 @@ static htsmsg_t *
htsp_error(const char *err)
{
htsmsg_t *r = htsmsg_create();
htsmsg_add_str(r, "_error", err);
htsmsg_add_str(r, "error", err);
return r;
}
@ -325,15 +342,20 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
htsp->htsp_async_mode = 1;
/* Send all enabled and external tags */
TAILQ_FOREACH(ct, &channel_tags, ct_link)
if(ct->ct_enabled && !ct->ct_internal)
htsp_send_message(htsp, htsp_build_tag(ct, "tagAdd", 0), NULL);
/* Send all channels */
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
htsp_send_message(htsp, htsp_build_channel(ch, "channelAdd"), NULL);
/* Send all enabled and external tags */
/* Send all enabled and external tags (now with channel mappings) */
TAILQ_FOREACH(ct, &channel_tags, ct_link)
if(ct->ct_enabled && !ct->ct_internal)
htsp_send_message(htsp, htsp_build_tag(ct, "tagAdd"), NULL);
htsp_send_message(htsp, htsp_build_tag(ct, "tagUpdate", 1), NULL);
/* Insert in list so it will get all updates */
LIST_INSERT_HEAD(&htsp_async_connections, htsp, htsp_async_link);
@ -425,6 +447,83 @@ htsp_method_unsubscribe(htsp_connection_t *htsp, htsmsg_t *in)
}
/**
* Update challenge
*/
static int
htsp_update_challenge(htsp_connection_t *htsp)
{
int fd, n;
if((fd = open("/dev/urandom", O_RDONLY)) < 0)
return -1;
n = read(fd, &htsp->htsp_challenge, 32);
close(fd);
return n != 32;
}
/**
* Request unsubscription for a channel
*/
static htsmsg_t *
htsp_method_get_challenge(htsp_connection_t *htsp, htsmsg_t *in)
{
htsmsg_t *r;
if(htsp_update_challenge(htsp))
return htsp_error("Unable to generate challenge");
r = htsmsg_create();
htsmsg_add_bin(r, "_challenge", htsp->htsp_challenge, 32);
return r;
}
/**
* Request unsubscription for a channel
*/
static htsmsg_t *
htsp_method_authenticate(htsp_connection_t *htsp, htsmsg_t *in)
{
htsmsg_t *r;
const char *username;
uint32_t access;
const void *digest;
size_t digestlen;
if((username = htsmsg_get_str(in, "username")) == NULL)
return htsp_error("Missing argument 'username'");
if(htsmsg_get_bin(in, "digest", &digest, &digestlen))
return htsp_error("Missing argument 'digest'");
if(digestlen != 20)
return htsp_error("Invalid digest size");
printf("hashcheck\n");
access = access_get_hashed(username, digest, htsp->htsp_challenge,
(struct sockaddr *)htsp->htsp_peer);
if(access == 0) {
if(htsp_update_challenge(htsp))
return htsp_error("Unable to generate challenge");
r = htsmsg_create();
htsmsg_add_bin(r, "challenge", htsp->htsp_challenge, 32);
htsmsg_add_u32(r, "noaccess", 1);
return r;
}
htsp->htsp_granted_access |= access;
return htsmsg_create();
}
/**
* HTSP methods
@ -434,6 +533,8 @@ struct {
htsmsg_t *(*fn)(htsp_connection_t *htsp, htsmsg_t *in);
int privmask;
} htsp_methods[] = {
{ "getChallenge", htsp_method_get_challenge, 0},
{ "authenticate", htsp_method_authenticate, 0},
{ "async", htsp_method_async, ACCESS_STREAMING},
{ "getEvent", htsp_method_getEvent, ACCESS_STREAMING},
{ "subscribe", htsp_method_subscribe, ACCESS_STREAMING},
@ -495,33 +596,41 @@ htsp_read_loop(htsp_connection_t *htsp)
{
htsmsg_t *m, *reply;
int r, i;
const char *method, *username, *password;
const char *method;
htsp->htsp_granted_access =
access_get_by_addr((struct sockaddr *)htsp->htsp_peer);
while(1) {
readmsg:
if((r = htsp_read_message(htsp, &m, 0)) != 0)
return r;
username = htsmsg_get_str(m, "username");
password = htsmsg_get_str(m, "password");
pthread_mutex_lock(&global_lock);
if((method = htsmsg_get_str(m, "method")) != NULL) {
for(i = 0; i < NUM_METHODS; i++) {
if(!strcmp(method, htsp_methods[i].name)) {
if(access_verify(username, password,
(struct sockaddr *)htsp->htsp_peer,
htsp_methods[i].privmask)) {
printf("mask for %s: %x\n", htsp_methods[i].name,
htsp_methods[i].privmask);
if(htsp_methods[i].privmask &&
!(htsp->htsp_granted_access & htsp_methods[i].privmask)) {
pthread_mutex_unlock(&global_lock);
/* Classic authentication failed delay */
sleep(1);
usleep(250000);
if(htsp_update_challenge(htsp)) {
reply = htsp_error("Unable to generate challenge");
break;
}
reply = htsmsg_create();
htsmsg_add_u32(reply, "_noaccess", 1);
htsmsg_add_u32(reply, "noaccess", 1);
htsmsg_add_bin(reply, "challenge", htsp->htsp_challenge, 32);
htsp_reply(htsp, m, reply);
htsmsg_destroy(m);
@ -766,7 +875,7 @@ htsp_channel_delete(channel_t *ch)
void
htsp_tag_add(channel_tag_t *ct)
{
htsp_async_send(htsp_build_tag(ct, "tagAdd"));
htsp_async_send(htsp_build_tag(ct, "tagAdd", 1));
}
@ -776,7 +885,7 @@ htsp_tag_add(channel_tag_t *ct)
void
htsp_tag_update(channel_tag_t *ct)
{
htsp_async_send(htsp_build_tag(ct, "tagUpdate"));
htsp_async_send(htsp_build_tag(ct, "tagUpdate", 1));
}