ACL: add per entry (user) stream profile selection

This commit is contained in:
Jaroslav Kysela 2014-10-16 15:36:02 +02:00
parent b1edb29e83
commit 599150006b
7 changed files with 123 additions and 16 deletions

View file

@ -171,6 +171,8 @@ access_copy(access_t *src)
dst->aa_username = strdup(src->aa_username);
if (src->aa_representative)
dst->aa_representative = strdup(src->aa_representative);
if (src->aa_profiles)
dst->aa_profiles = htsmsg_copy(src->aa_profiles);
if (src->aa_dvrcfgs)
dst->aa_dvrcfgs = htsmsg_copy(src->aa_dvrcfgs);
if (src->aa_chtags)
@ -188,6 +190,7 @@ access_destroy(access_t *a)
return;
free(a->aa_username);
free(a->aa_representative);
htsmsg_destroy(a->aa_profiles);
htsmsg_destroy(a->aa_dvrcfgs);
htsmsg_destroy(a->aa_chtags);
free(a);
@ -335,6 +338,12 @@ access_update(access_t *a, access_entry_t *ae)
}
}
if(ae->ae_profile && ae->ae_profile->pro_name[0] != '\0') {
if (a->aa_profiles == NULL)
a->aa_profiles = htsmsg_create_list();
htsmsg_add_str(a->aa_profiles, NULL, idnode_uuid_as_str(&ae->ae_profile->pro_id));
}
if(ae->ae_dvr_config && ae->ae_dvr_config->dvr_config_name[0] != '\0') {
if (a->aa_dvrcfgs == NULL)
a->aa_dvrcfgs = htsmsg_create_list();
@ -757,6 +766,8 @@ access_entry_destroy(access_entry_t *ae)
TAILQ_REMOVE(&access_entries, ae, ae_link);
idnode_unlink(&ae->ae_id);
if (ae->ae_profile)
LIST_REMOVE(ae, ae_profile_link);
if (ae->ae_dvr_config)
LIST_REMOVE(ae, ae_dvr_config_link);
if (ae->ae_chtag)
@ -775,6 +786,22 @@ access_entry_destroy(access_entry_t *ae)
free(ae);
}
/*
*
*/
void
access_destroy_by_profile(profile_t *pro, int delconf)
{
access_entry_t *ae;
while ((ae = LIST_FIRST(&pro->pro_accesses)) != NULL) {
LIST_REMOVE(ae, ae_profile_link);
ae->ae_dvr_config = NULL;
if (delconf)
access_entry_save(ae);
}
}
/*
*
*/
@ -785,7 +812,7 @@ access_destroy_by_dvr_config(dvr_config_t *cfg, int delconf)
while ((ae = LIST_FIRST(&cfg->dvr_accesses)) != NULL) {
LIST_REMOVE(ae, ae_dvr_config_link);
ae->ae_dvr_config = NULL;
ae->ae_profile = profile_find_by_name(NULL, NULL);
if (delconf)
access_entry_save(ae);
}
@ -1026,6 +1053,37 @@ access_entry_dvr_config_get(void *o)
return &ret;
}
static int
access_entry_profile_set(void *o, const void *v)
{
access_entry_t *ae = (access_entry_t *)o;
profile_t *pro = v ? profile_find_by_uuid(v) : NULL;
if (pro == NULL && ae->ae_profile) {
LIST_REMOVE(ae, ae_profile_link);
ae->ae_profile = NULL;
return 1;
} else if (ae->ae_profile != pro) {
if (ae->ae_profile)
LIST_REMOVE(ae, ae_profile_link);
ae->ae_profile = pro;
LIST_INSERT_HEAD(&pro->pro_accesses, ae, ae_profile_link);
return 1;
}
return 0;
}
static const void *
access_entry_profile_get(void *o)
{
static const char *ret;
access_entry_t *ae = (access_entry_t *)o;
if (ae->ae_profile)
ret = idnode_uuid_as_str(&ae->ae_profile->pro_id);
else
ret = "";
return &ret;
}
const idclass_t access_entry_class = {
.ic_class = "access",
.ic_caption = "Access",
@ -1091,6 +1149,14 @@ const idclass_t access_entry_class = {
.name = "Advanced Streaming",
.off = offsetof(access_entry_t, ae_adv_streaming),
},
{
.type = PT_STR,
.id = "profile",
.name = "Streaming Profile",
.set = access_entry_profile_set,
.get = access_entry_profile_get,
.list = profile_class_get_list,
},
{
.type = PT_BOOL,
.id = "dvr",

View file

@ -22,6 +22,7 @@
#include "idnode.h"
#include "htsmsg.h"
struct profile;
struct dvr_config;
struct channel_tag;
@ -57,6 +58,9 @@ typedef struct access_entry {
int ae_streaming;
int ae_adv_streaming;
struct profile *ae_profile;
LIST_ENTRY(access_entry) ae_profile_link;
uint32_t ae_conn_limit;
int ae_dvr;
@ -83,6 +87,7 @@ typedef struct access {
char *aa_username;
char *aa_representative;
uint32_t aa_rights;
htsmsg_t *aa_profiles;
htsmsg_t *aa_dvrcfgs;
uint32_t aa_chmin;
uint32_t aa_chmax;
@ -185,6 +190,8 @@ access_entry_save(access_entry_t *ae);
*
*/
void
access_destroy_by_profile(struct profile *pro, int delconf);
void
access_destroy_by_dvr_config(struct dvr_config *cfg, int delconf);
void
access_destroy_by_channel_tag(struct channel_tag *ct, int delconf);

View file

@ -1783,18 +1783,14 @@ htsp_method_subscribe(htsp_connection_t *htsp, htsmsg_t *in)
}
#endif
#if ENABLE_LIBAV
profile_t *pro;
const char *profile_id = htsmsg_get_str(in, "profile");
profile_t *pro = NULL;
if (profile_id) {
pro = profile_find_by_uuid(profile_id);
if (pro == NULL)
pro = profile_find_by_name(profile_id, "htsp");
if (pro)
profile_id = pro->pro_name;
}
#else
profile_t *pro = profile_find_by_name("htsp", NULL);
#endif
pro = profile_find_by_list(htsp->htsp_granted_access->aa_profiles, profile_id, "htsp");
hs->hs_work = profile_work(pro, st, &hs->hs_work_destroy);
if (hs->hs_work) {

View file

@ -83,6 +83,7 @@ profile_create
return NULL;
}
LIST_INIT(&pro->pro_dvr_configs);
LIST_INIT(&pro->pro_accesses);
if (idnode_insert(&pro->pro_id, uuid, pb->clazz, 0)) {
if (uuid)
tvherror("profile", "invalid uuid '%s'", uuid);
@ -114,6 +115,7 @@ profile_delete(profile_t *pro, int delconf)
TAILQ_REMOVE(&profiles, pro, pro_link);
idnode_unlink(&pro->pro_id);
dvr_config_destroy_by_profile(pro, delconf);
access_destroy_by_profile(pro, delconf);
if (pro->pro_free)
pro->pro_free(pro);
free(pro->pro_name);
@ -308,13 +310,13 @@ profile_find_by_name(const char *name, const char *alt)
return profile_default;
TAILQ_FOREACH(pro, &profiles, pro_link) {
if (!strcmp(pro->pro_name, name))
if (pro->pro_enabled && !strcmp(pro->pro_name, name))
return pro;
}
if (alt) {
TAILQ_FOREACH(pro, &profiles, pro_link) {
if (!strcmp(pro->pro_name, alt))
if (pro->pro_enabled && !strcmp(pro->pro_name, alt))
return pro;
}
}
@ -322,6 +324,35 @@ profile_find_by_name(const char *name, const char *alt)
return profile_default;
}
/*
*
*/
profile_t *
profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt)
{
profile_t *pro, *res = NULL;
htsmsg_field_t *f;
const char *uuid, *uuid2;
pro = profile_find_by_name(name, alt);
uuid = idnode_uuid_as_str(&pro->pro_id);
if (uuids) {
HTSMSG_FOREACH(f, uuids) {
uuid2 = htsmsg_field_get_str(f) ?: "";
if (strcmp(uuid, uuid2) == 0)
return res;
if (!res) {
res = profile_find_by_uuid(uuid2);
if (!res->pro_enabled)
res = NULL;
}
}
}
if (!res)
res = profile_find_by_name(NULL, NULL);
return res;
}
/*
*
*/

View file

@ -64,6 +64,7 @@ typedef struct profile {
TAILQ_ENTRY(profile) pro_link;
LIST_HEAD(,dvr_config) pro_dvr_configs;
LIST_HEAD(,access_entry) pro_accesses;
int pro_enabled;
int pro_shield;
@ -104,6 +105,7 @@ void profile_chain_close(profile_chain_t *prch);
static inline profile_t *profile_find_by_uuid(const char *uuid)
{ return (profile_t*)idnode_find(uuid, &profile_class, NULL); }
profile_t *profile_find_by_name(const char *name, const char *alt);
profile_t *profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt);
htsmsg_t * profile_class_get_list(void *o);

View file

@ -4,9 +4,10 @@
tvheadend.acleditor = function(panel, index)
{
var list = 'enabled,username,password,prefix,streaming,adv_streaming,' +
'dvr,dvr_config,webui,admin,conn_limit,channel_min,channel_max,' +
'channel_tag,comment';
var list = 'enabled,username,password,prefix,' +
'streaming,adv_streaming,profile,' +
'dvr,dvr_config,webui,admin,conn_limit,' +
'channel_min,channel_max,channel_tag,comment';
tvheadend.idnode_grid(panel, {
url: 'api/access/entry',

View file

@ -719,7 +719,9 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
if(http_access_verify(hc, ACCESS_ADVANCED_STREAMING))
return HTTP_STATUS_UNAUTHORIZED;
if(!(pro = profile_find_by_name(http_arg_get(&hc->hc_req_args, "profile"), "service")))
if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
http_arg_get(&hc->hc_req_args, "profile"),
"service")))
return HTTP_STATUS_NOT_ALLOWED;
if((tcp_id = http_stream_preop(hc)) == NULL)
@ -831,7 +833,9 @@ http_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 1))
return HTTP_STATUS_UNAUTHORIZED;
if(!(pro = profile_find_by_name(http_arg_get(&hc->hc_req_args, "profile"), "channel")))
if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
http_arg_get(&hc->hc_req_args, "profile"),
"channel")))
return HTTP_STATUS_NOT_ALLOWED;
if((tcp_id = http_stream_preop(hc)) == NULL)