struct access_entry_queue access_entries;
struct access_ticket_queue access_tickets;
struct passwd_entry_queue passwd_entries;
+struct ipblock_entry_queue ipblock_entries;
const char *superuser_username;
const char *superuser_password;
*
*/
static int
-netmask_verify(access_entry_t *ae, struct sockaddr *src)
+netmask_verify(struct access_ipmask_queue *ais, struct sockaddr *src)
{
access_ipmask_t *ai;
int isv4v6 = 0;
}
}
- TAILQ_FOREACH(ai, &ae->ae_ipmasks, ai_link) {
+ TAILQ_FOREACH(ai, ais, ai_link) {
if (ai->ai_family == AF_INET && src->sa_family == AF_INET) {
return 0;
}
+/**
+ *
+ */
+static inline int
+access_ip_blocked(struct sockaddr *src)
+{
+ ipblock_entry_t *ib;
+
+ TAILQ_FOREACH(ib, &ipblock_entries, ib_link)
+ if (netmask_verify(&ib->ib_ipmasks, src))
+ return 1;
+ return 0;
+}
+
/**
*
*/
if (access_noacl)
return 0;
+ if (access_ip_blocked(src))
+ return -1;
+
if (!passwd_verify2(username, password,
superuser_username, superuser_password))
return 0;
continue; /* Didn't get one */
}
- if(!netmask_verify(ae, src))
+ if(!netmask_verify(&ae->ae_ipmasks, src))
continue; /* IP based access mismatches */
if (ae->ae_username[0] != '*')
access_entry_t *ae;
int nouser = username == NULL || username[0] == '\0';
+ if (!access_noacl && access_ip_blocked(src))
+ return a;
+
if (!passwd_verify(username, password)) {
a->aa_username = strdup(username);
a->aa_representative = strdup(username);
continue; /* Didn't get one */
}
- if(!netmask_verify(ae, src))
+ if(!netmask_verify(&ae->ae_ipmasks, src))
continue; /* IP based access mismatches */
if(ae->ae_username[0] != '*')
access_entry_t *ae;
int nouser = username == NULL || username[0] == '\0';
+ if (!access_noacl && access_ip_blocked(src))
+ return a;
+
if (!passwd_verify_digest(username, digest, challenge)) {
a->aa_username = strdup(username);
a->aa_representative = strdup(username);
if(!ae->ae_enabled)
continue;
- if(!netmask_verify(ae, src))
+ if(!netmask_verify(&ae->ae_ipmasks, src))
continue; /* IP based access mismatches */
if(ae->ae_username[0] != '*') {
return a;
}
+ if (access_ip_blocked(src))
+ return a;
+
TAILQ_FOREACH(ae, &access_entries, ae_link) {
if(!ae->ae_enabled)
if(ae->ae_username[0] != '*')
continue;
- if(!netmask_verify(ae, src))
+ if(!netmask_verify(&ae->ae_ipmasks, src))
continue; /* IP based access mismatches */
access_update(a, ae);
*
*/
static void
-access_set_prefix_default(access_entry_t *ae)
+access_set_prefix_default(struct access_ipmask_queue *ais)
{
access_ipmask_t *ai;
ai = calloc(1, sizeof(access_ipmask_t));
ai->ai_family = AF_INET6;
- TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
+ TAILQ_INSERT_HEAD(ais, ai, ai_link);
ai = calloc(1, sizeof(access_ipmask_t));
ai->ai_family = AF_INET;
- TAILQ_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
+ TAILQ_INSERT_HEAD(ais, ai, ai_link);
}
/**
*
*/
static void
-access_set_prefix(access_entry_t *ae, const char *prefix)
+access_set_prefix(struct access_ipmask_queue *ais, const char *prefix, int dflt)
{
static const char *delim = ",;| ";
char buf[100];
in_addr_t s_addr;
access_ipmask_t *ai = NULL;
- while((ai = TAILQ_FIRST(&ae->ae_ipmasks)) != NULL) {
- TAILQ_REMOVE(&ae->ae_ipmasks, ai, ai_link);
+ while((ai = TAILQ_FIRST(ais)) != NULL) {
+ TAILQ_REMOVE(ais, ai, ai_link);
free(ai);
}
ai->ai_network = ntohl(s_addr) & ai->ai_netmask;
}
- TAILQ_INSERT_TAIL(&ae->ae_ipmasks, ai, ai_link);
+ TAILQ_INSERT_TAIL(ais, ai, ai_link);
ai = NULL;
tok = strtok_r(NULL, delim, &saveptr);
}
}
- if (!TAILQ_FIRST(&ae->ae_ipmasks))
- access_set_prefix_default(ae);
+ if (dflt && !TAILQ_FIRST(ais))
+ access_set_prefix_default(ais);
+}
+
+/**
+ *
+ */
+static const char *access_get_prefix(struct access_ipmask_queue *ais)
+{
+ char addrbuf[50];
+ access_ipmask_t *ai;
+ size_t pos = 0;
+ uint32_t s_addr;
+
+ prop_sbuf[0] = prop_sbuf[1] = '\0';
+ TAILQ_FOREACH(ai, ais, ai_link) {
+ if(PROP_SBUF_LEN-pos <= 0)
+ break;
+ if(ai->ai_family == AF_INET6) {
+ inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, sizeof(addrbuf));
+ } else {
+ s_addr = htonl(ai->ai_network);
+ inet_ntop(AF_INET, &s_addr, addrbuf, sizeof(addrbuf));
+ }
+ tvh_strlcatf(prop_sbuf, PROP_SBUF_LEN, pos, ",%s/%d", addrbuf, ai->ai_prefixlen);
+ }
+ return prop_sbuf + 1;
}
/**
if (ae->ae_comment == NULL)
ae->ae_comment = strdup("New entry");
if (TAILQ_FIRST(&ae->ae_ipmasks) == NULL)
- access_set_prefix_default(ae);
+ access_set_prefix_default(&ae->ae_ipmasks);
return ae;
}
static int
access_entry_class_prefix_set(void *o, const void *v)
{
- access_set_prefix((access_entry_t *)o, (const char *)v);
+ access_set_prefix(&((access_entry_t *)o)->ae_ipmasks, (const char *)v, 1);
return 1;
}
static const void *
access_entry_class_prefix_get(void *o)
{
- static char buf[4096], addrbuf[50], *ret = buf+1;
- access_entry_t *ae = (access_entry_t *)o;
- access_ipmask_t *ai;
- size_t pos = 0;
- uint32_t s_addr;
-
- buf[0] = buf[1] = '\0';
- TAILQ_FOREACH(ai, &ae->ae_ipmasks, ai_link) {
- if(sizeof(buf)-pos <= 0)
- break;
-
- if(ai->ai_family == AF_INET6) {
- inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, sizeof(addrbuf));
- } else {
- s_addr = htonl(ai->ai_network);
- inet_ntop(AF_INET, &s_addr, addrbuf, sizeof(addrbuf));
- }
- tvh_strlcatf(buf, sizeof(buf), pos, ",%s/%d", addrbuf, ai->ai_prefixlen);
- }
+ static const char *ret;
+ ret = access_get_prefix(&((access_entry_t *)o)->ae_ipmasks);
return &ret;
}
}
};
+/**
+ * IP block list
+ */
+
+ipblock_entry_t *
+ipblock_entry_create(const char *uuid, htsmsg_t *conf)
+{
+ ipblock_entry_t *ib;
+
+ lock_assert(&global_lock);
+
+ ib = calloc(1, sizeof(ipblock_entry_t));
+
+ TAILQ_INIT(&ib->ib_ipmasks);
+
+ if (idnode_insert(&ib->ib_id, uuid, &ipblock_entry_class, 0)) {
+ if (uuid)
+ tvherror("access", "invalid uuid '%s'", uuid);
+ free(ib);
+ return NULL;
+ }
+
+ if (conf) {
+ ib->ib_enabled = 1;
+ idnode_load(&ib->ib_id, conf);
+ }
+
+ TAILQ_INSERT_TAIL(&ipblock_entries, ib, ib_link);
+
+ return ib;
+}
+
+static void
+ipblock_entry_destroy(ipblock_entry_t *ib)
+{
+ if (ib == NULL)
+ return;
+ TAILQ_REMOVE(&ipblock_entries, ib, ib_link);
+ idnode_unlink(&ib->ib_id);
+ free(ib->ib_comment);
+ free(ib);
+}
+
+void
+ipblock_entry_save(ipblock_entry_t *ib)
+{
+ htsmsg_t *c = htsmsg_create_map();
+ idnode_save(&ib->ib_id, c);
+ hts_settings_save(c, "ipblock/%s", idnode_uuid_as_sstr(&ib->ib_id));
+ htsmsg_destroy(c);
+}
+
+static void
+ipblock_entry_class_save(idnode_t *self)
+{
+ ipblock_entry_save((ipblock_entry_t *)self);
+}
+
+static const char *
+ipblock_entry_class_get_title (idnode_t *self, const char *lang)
+{
+ ipblock_entry_t *ib = (ipblock_entry_t *)self;
+
+ if (ib->ib_comment && ib->ib_comment[0] != '\0')
+ return ib->ib_comment;
+ return N_("IP Blocking");
+}
+
+static void
+ipblock_entry_class_delete(idnode_t *self)
+{
+ ipblock_entry_t *ib = (ipblock_entry_t *)self;
+
+ hts_settings_remove("passwd/%s", idnode_uuid_as_sstr(&ib->ib_id));
+ ipblock_entry_destroy(ib);
+}
+
+static int
+ipblock_entry_class_prefix_set(void *o, const void *v)
+{
+ access_set_prefix(&((ipblock_entry_t *)o)->ib_ipmasks, (const char *)v, 0);
+ return 1;
+}
+
+static const void *
+ipblock_entry_class_prefix_get(void *o)
+{
+ static const char *ret;
+ ret = access_get_prefix(&((ipblock_entry_t *)o)->ib_ipmasks);
+ return &ret;
+}
+
+const idclass_t ipblock_entry_class = {
+ .ic_class = "ipblocking",
+ .ic_caption = N_("IP Blocking"),
+ .ic_event = "ipblocking",
+ .ic_perm_def = ACCESS_ADMIN,
+ .ic_save = ipblock_entry_class_save,
+ .ic_get_title = ipblock_entry_class_get_title,
+ .ic_delete = ipblock_entry_class_delete,
+ .ic_properties = (const property_t[]){
+ {
+ .type = PT_BOOL,
+ .id = "enabled",
+ .name = N_("Enabled"),
+ .off = offsetof(ipblock_entry_t, ib_enabled),
+ },
+ {
+ .type = PT_STR,
+ .id = "prefix",
+ .name = N_("Network prefix"),
+ .set = ipblock_entry_class_prefix_set,
+ .get = ipblock_entry_class_prefix_get,
+ },
+ {
+ .type = PT_STR,
+ .id = "comment",
+ .name = N_("Comment"),
+ .off = offsetof(ipblock_entry_t, ib_comment),
+ },
+ {}
+ }
+};
+
/**
*
*/
TAILQ_INIT(&access_entries);
TAILQ_INIT(&access_tickets);
TAILQ_INIT(&passwd_entries);
+ TAILQ_INIT(&ipblock_entries);
+
+ /* Load ipblock entries */
+ if ((c = hts_settings_load("ipblock")) != NULL) {
+ HTSMSG_FOREACH(f, c) {
+ if (!(m = htsmsg_field_get_map(f))) continue;
+ (void)ipblock_entry_create(f->hmf_name, m);
+ }
+ htsmsg_destroy(c);
+ }
/* Load passwd entries */
if ((c = hts_settings_load("passwd")) != NULL) {
TAILQ_INIT(&ae->ae_ipmasks);
- access_set_prefix_default(ae);
+ access_set_prefix_default(&ae->ae_ipmasks);
access_entry_save(ae);
access_entry_t *ae;
access_ticket_t *at;
passwd_entry_t *pw;
+ ipblock_entry_t *ib;
pthread_mutex_lock(&global_lock);
while ((ae = TAILQ_FIRST(&access_entries)) != NULL)
access_ticket_destroy(at);
while ((pw = TAILQ_FIRST(&passwd_entries)) != NULL)
passwd_entry_destroy(pw);
+ while ((ib = TAILQ_FIRST(&ipblock_entries)) != NULL)
+ ipblock_entry_destroy(ib);
free((void *)superuser_username);
superuser_username = NULL;
free((void *)superuser_password);