Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
ACL, HTSP, HTTP: Added streaming connection limit per user
  • Loading branch information
perexg committed Oct 6, 2014
1 parent 6508c94 commit 6f4661d
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 81 deletions.
5 changes: 5 additions & 0 deletions docs/html/config_access.html
Expand Up @@ -82,6 +82,11 @@
<dd>
Enables access to the Configuration tab.

<dt>Limit Connections
<dd>
If nonzero, the user will be limited to this amount of streaming
connection at a time.

<dt>Min Channel Num
<dd>
If nonzero, the user will only be able to access channels with
Expand Down
25 changes: 22 additions & 3 deletions src/access.c
Expand Up @@ -270,13 +270,14 @@ access_verify(const char *username, const char *password,
if(strcmp(ae->ae_username, username) ||
strcmp(ae->ae_password, password))
continue; /* username/password mismatch */

match = 1;
}

if(!netmask_verify(ae, src))
continue; /* IP based access mismatches */

if (ae->ae_username[0] != '*')
match = 1;

bits |= ae->ae_rights;
}

Expand All @@ -295,6 +296,9 @@ access_verify(const char *username, const char *password,
static void
access_update(access_t *a, access_entry_t *ae)
{
if(a->aa_conn_limit < ae->ae_conn_limit)
a->aa_conn_limit = ae->ae_conn_limit;

if(ae->ae_chmin || ae->ae_chmax) {
if(a->aa_chmin || a->aa_chmax) {
if (a->aa_chmin < ae->ae_chmin)
Expand Down Expand Up @@ -399,6 +403,14 @@ access_get_hashed(const char *username, const uint8_t digest[20],
SHA_CTX shactx;
uint8_t d[20];

if (username) {
a->aa_username = strdup(username);
a->aa_representative = strdup(username);
} else {
a->aa_representative = malloc(50);
tcp_get_ip_str((struct sockaddr*)src, a->aa_representative, 50);
}

if(access_noacl) {
a->aa_rights = ACCESS_FULL;
return a;
Expand All @@ -418,7 +430,6 @@ access_get_hashed(const char *username, const uint8_t digest[20],
}
}


TAILQ_FOREACH(ae, &access_entries, ae_link) {

if(!ae->ae_enabled)
Expand All @@ -445,6 +456,8 @@ access_get_hashed(const char *username, const uint8_t digest[20],

/* Username was not matched - no access */
if (!a->aa_match) {
free(a->aa_username);
a->aa_username = NULL;
if (username && *username != '\0')
a->aa_rights = 0;
}
Expand Down Expand Up @@ -1079,6 +1092,12 @@ const idclass_t access_entry_class = {
.name = "Admin",
.off = offsetof(access_entry_t, ae_admin),
},
{
.type = PT_U32,
.id = "conn_limit",
.name = "Limit Connections",
.off = offsetof(access_entry_t, ae_conn_limit),
},
{
.type = PT_U32,
.id = "channel_min",
Expand Down
3 changes: 3 additions & 0 deletions src/access.h
Expand Up @@ -57,6 +57,8 @@ typedef struct access_entry {
int ae_streaming;
int ae_adv_streaming;

uint32_t ae_conn_limit;

int ae_dvr;
struct dvr_config *ae_dvr_config;
LIST_ENTRY(access_entry) ae_dvr_config_link;
Expand Down Expand Up @@ -99,6 +101,7 @@ typedef struct access {
uint32_t aa_chmax;
htsmsg_t *aa_chtags;
int aa_match;
uint32_t aa_conn_limit;
} access_t;

#define ACCESS_ANONYMOUS 0
Expand Down
94 changes: 58 additions & 36 deletions src/htsp_server.c
Expand Up @@ -2202,7 +2202,7 @@ struct {
/**
* Raise privs by field in message
*/
static void
static int
htsp_authenticate(htsp_connection_t *htsp, htsmsg_t *m)
{
const char *username;
Expand All @@ -2212,7 +2212,7 @@ htsp_authenticate(htsp_connection_t *htsp, htsmsg_t *m)
int privgain;

if((username = htsmsg_get_str(m, "username")) == NULL)
return;
return 0;

if(strcmp(htsp->htsp_username ?: "", username)) {
tvhlog(LOG_INFO, "htsp", "%s: Identified as user %s",
Expand All @@ -2223,7 +2223,7 @@ htsp_authenticate(htsp_connection_t *htsp, htsmsg_t *m)
}

if(htsmsg_get_bin(m, "digest", &digest, &digestlen))
return;
return 0;

rights = access_get_hashed(username, digest, htsp->htsp_challenge,
(struct sockaddr *)htsp->htsp_peer);
Expand All @@ -2237,6 +2237,7 @@ htsp_authenticate(htsp_connection_t *htsp, htsmsg_t *m)

access_destroy(htsp->htsp_granted_access);
htsp->htsp_granted_access = rights;
return privgain;
}

/**
Expand Down Expand Up @@ -2281,6 +2282,18 @@ htsp_read_message(htsp_connection_t *htsp, htsmsg_t **mp, int timeout)
return 0;
}

/*
* Status callback
*/
static void
htsp_server_status ( void *opaque, htsmsg_t *m )
{
htsp_connection_t *htsp = opaque;
htsmsg_add_str(m, "type", "HTSP");
if (htsp->htsp_username)
htsmsg_add_str(m, "user", htsp->htsp_username);
}

/**
*
*/
Expand All @@ -2290,6 +2303,7 @@ htsp_read_loop(htsp_connection_t *htsp)
htsmsg_t *m = NULL, *reply;
int r, i;
const char *method;
void *tcp_id = NULL;;

if(htsp_generate_challenge(htsp)) {
tvhlog(LOG_ERR, "htsp", "%s: Unable to generate challenge",
Expand All @@ -2298,10 +2312,18 @@ htsp_read_loop(htsp_connection_t *htsp)
}

pthread_mutex_lock(&global_lock);

htsp->htsp_granted_access =
access_get_by_addr((struct sockaddr *)htsp->htsp_peer);

tcp_id = tcp_connection_launch(htsp->htsp_fd, htsp_server_status,
htsp->htsp_granted_access);

pthread_mutex_unlock(&global_lock);

if (tcp_id == NULL)
return 0;

tvhlog(LOG_INFO, "htsp", "Got connection from %s", htsp->htsp_logname);

/* Session main loop */
Expand All @@ -2312,37 +2334,46 @@ htsp_read_loop(htsp_connection_t *htsp)
return r;

pthread_mutex_lock(&global_lock);
htsp_authenticate(htsp, m);
if (htsp_authenticate(htsp, m)) {
tcp_connection_land(tcp_id);
tcp_id = tcp_connection_launch(htsp->htsp_fd, htsp_server_status,
htsp->htsp_granted_access);
if (tcp_id == NULL) {
htsmsg_destroy(m);
pthread_mutex_unlock(&global_lock);
return 1;
}
}

if((method = htsmsg_get_str(m, "method")) != NULL) {
tvhtrace("htsp", "%s - method %s", htsp->htsp_logname, method);
for(i = 0; i < NUM_METHODS; i++) {
if(!strcmp(method, htsp_methods[i].name)) {
if(!strcmp(method, htsp_methods[i].name)) {

if((htsp->htsp_granted_access->aa_rights & htsp_methods[i].privmask) !=
htsp_methods[i].privmask) {
if((htsp->htsp_granted_access->aa_rights &
htsp_methods[i].privmask) !=
htsp_methods[i].privmask) {

pthread_mutex_unlock(&global_lock);
/* Classic authentication failed delay */
usleep(250000);

reply = htsmsg_create_map();
htsmsg_add_u32(reply, "noaccess", 1);
htsp_reply(htsp, m, reply);

/* Classic authentication failed delay */
usleep(250000);

reply = htsmsg_create_map();
htsmsg_add_u32(reply, "noaccess", 1);
htsp_reply(htsp, m, reply);

htsmsg_destroy(m);
goto readmsg;

} else {
reply = htsp_methods[i].fn(htsp, m);
}
break;
}
htsmsg_destroy(m);
goto readmsg;

} else {
reply = htsp_methods[i].fn(htsp, m);
}
break;
}
}

if(i == NUM_METHODS) {
reply = htsp_error("Method not found");
reply = htsp_error("Method not found");
}

} else {
Expand All @@ -2356,6 +2387,10 @@ htsp_read_loop(htsp_connection_t *htsp)

htsmsg_destroy(m);
}

pthread_mutex_lock(&global_lock);
tcp_connection_land(tcp_id);
pthread_mutex_unlock(&global_lock);
return 0;
}

Expand Down Expand Up @@ -2526,18 +2561,6 @@ htsp_serve(int fd, void **opaque, struct sockaddr_storage *source,
*opaque = NULL;
}

/*
* Status callback
*/
static void
htsp_server_status ( void *opaque, htsmsg_t *m )
{
htsp_connection_t *htsp = opaque;
htsmsg_add_str(m, "type", "HTSP");
if (htsp->htsp_username)
htsmsg_add_str(m, "user", htsp->htsp_username);
}

/*
* Cancel callback
*/
Expand All @@ -2556,7 +2579,6 @@ htsp_init(const char *bindaddr)
static tcp_server_ops_t ops = {
.start = htsp_serve,
.stop = NULL,
.status = htsp_server_status,
.cancel = htsp_server_cancel
};
htsp_server = tcp_server_create(bindaddr, tvheadend_htsp_port, &ops, NULL);
Expand Down
2 changes: 1 addition & 1 deletion src/http.c
Expand Up @@ -996,7 +996,7 @@ http_server_init(const char *bindaddr)
static tcp_server_ops_t ops = {
.start = http_serve,
.stop = NULL,
.status = NULL,
.cancel = NULL
};
http_server = tcp_server_create(bindaddr, tvheadend_webui_port, &ops, NULL);
}
Expand Down

0 comments on commit 6f4661d

Please sign in to comment.