diff --git a/cmd.c b/cmd.c index e36ebdd..0f5658b 100644 --- a/cmd.c +++ b/cmd.c @@ -41,6 +41,8 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si char *always_off[] = {"MULTI", "EXEC", "WATCH", "DISCARD", "SUBSCRIBE", "PSUBSCRIBE"}; unsigned int i; + int authorized = 1; + struct acl *a; char *client_ip; u_short client_port; @@ -53,30 +55,31 @@ cmd_authorized(struct conf *cfg, struct evhttp_request *rq, const char *verb, si } } - /* find client's address */ evhttp_connection_get_peer(rq->evcon, &client_ip, &client_port); client_addr = ntohl(inet_addr(client_ip)); - return 1; -#if 0 - for(dc = cfg->disabled; dc; dc = dc->next) { - /* CIDR test */ + /* go through permissions */ + for(a = cfg->perms; a; a = a->next) { + + if(!acl_match(a, &client_addr)) continue; /* match client */ - if((client_addr & dc->mask) != (dc->subnet & dc->mask)) { - continue; + /* go through authorized commands */ + for(i = 0; i < a->enabled.count; ++i) { + if(strncasecmp(a->enabled.commands[i], verb, verb_len) == 0) { + authorized = 1; + } } - /* matched an ip */ - for(i = 0; i < dc->count; ++i) { - if(strncasecmp(dc->commands[i], verb, verb_len) == 0) { - return 0; + /* go through unauthorized commands */ + for(i = 0; i < a->disabled.count; ++i) { + if(strncasecmp(a->disabled.commands[i], verb, verb_len) == 0) { + authorized = 0; } } } -#endif - return 1; + return authorized; } int diff --git a/conf.c b/conf.c index 03eca79..c83777a 100644 --- a/conf.c +++ b/conf.c @@ -46,7 +46,7 @@ conf_read(const char *filename) { conf->http_host = strdup(json_string_value(jtmp)); } else if(strcmp(json_object_iter_key(kv), "http_port") == 0 && json_typeof(jtmp) == JSON_INTEGER) { conf->http_port = (short)json_integer_value(jtmp); - } else if(strcmp(json_object_iter_key(kv), "acl") == 0 && json_typeof(jtmp) == JSON_OBJECT) { + } else if(strcmp(json_object_iter_key(kv), "acl") == 0 && json_typeof(jtmp) == JSON_ARRAY) { conf->perms = conf_parse_acls(jtmp); } } @@ -100,7 +100,6 @@ conf_parse_acl(json_t *j) { if((jcidr = json_object_get(j, "ip")) && json_typeof(jcidr) == JSON_STRING) { const char *s; char *p, *ip; - a->cidr.enabled = 1; s = json_string_value(jcidr); p = strchr(s, '/'); @@ -111,6 +110,7 @@ conf_parse_acl(json_t *j) { memcpy(ip, s, (size_t)(p - s)); mask_bits = (unsigned short)atoi(p+1); } + a->cidr.enabled = 1; a->cidr.mask = (mask_bits == 0 ? 0 : (0xffffffff << (32 - mask_bits))); a->cidr.subnet = ntohl(inet_addr(ip)) & a->cidr.mask; free(ip); @@ -123,13 +123,13 @@ conf_parse_acl(json_t *j) { } /* parse enabled commands */ - if((jlist = json_object_get(j, "enable")) && json_typeof(jlist) == JSON_ARRAY) { - acl_read_commands(jlist, &a->enable); + if((jlist = json_object_get(j, "enabled")) && json_typeof(jlist) == JSON_ARRAY) { + acl_read_commands(jlist, &a->enabled); } /* parse disabled commands */ - if((jlist = json_object_get(j, "disable")) && json_typeof(jlist) == JSON_ARRAY) { - acl_read_commands(jlist, &a->disable); + if((jlist = json_object_get(j, "disabled")) && json_typeof(jlist) == JSON_ARRAY) { + acl_read_commands(jlist, &a->disabled); } return a; @@ -138,18 +138,39 @@ conf_parse_acl(json_t *j) { struct acl * conf_parse_acls(json_t *jtab) { - struct acl *root = NULL, *tmp = NULL; + struct acl *head = NULL, *tail = NULL, *tmp; - void *kv; - for(kv = json_object_iter(jtab); kv; kv = json_object_iter_next(jtab, kv)) { - json_t *val = json_object_iter_value(kv); + unsigned int i; + for(i = 0; i < json_array_size(jtab); ++i) { + json_t *val = json_array_get(jtab, i); tmp = conf_parse_acl(val); - if(root) root->next = tmp; - root = tmp; + if(head == NULL && tail == NULL) { + head = tail = tmp; + } else { + tail->next = tmp; + tail = tmp; + } + } + + return head; +} + +int +acl_match(struct acl *a, in_addr_t *ip) { + + /* TODO: add HTTP Basic Auth */ + + if(a->cidr.enabled == 0) { /* none given, all match */ + return 1; + } + + /* CIDR check. */ + if(((*ip) & a->cidr.mask) == (a->cidr.subnet & a->cidr.mask)) { + return 1; } - return root; + return 0; } diff --git a/conf.h b/conf.h index b2169be..428758f 100644 --- a/conf.h +++ b/conf.h @@ -20,8 +20,8 @@ struct acl { char *http_basic_auth; /* commands that have been enabled or disabled */ - struct acl_commands enable; - struct acl_commands disable; + struct acl_commands enabled; + struct acl_commands disabled; struct acl *next; }; @@ -44,4 +44,7 @@ conf_read(const char *filename); void conf_free(struct conf *conf); +int +acl_match(struct acl *a, in_addr_t *ip); + #endif /* CONF_H */ diff --git a/webdis.json b/webdis.json index f9e4340..e5cc112 100644 --- a/webdis.json +++ b/webdis.json @@ -7,29 +7,31 @@ "http_host": "0.0.0.0", "http_port": 7379, - "disable": { - "0.0.0.0/0": ["DEBUG", "FLUSHDB", "FLUSHALL"] - }, - "acl": [ { "basic_auth": "user:password", - "disable": ["DEBUG", "FLUSHDB", "FLUSHALL"], - "enable": ["SET"] + "disabled": ["DEBUG", "FLUSHDB", "FLUSHALL"], + "enabled": ["SET"] }, { "ip": "192.168.10.0/24", - "disable": ["SET", "FLUSHDB", "FLUSHALL"], - "enable": ["*"] + "disabled": ["SET", "FLUSHDB", "FLUSHALL"], + "enabled": ["*"] }, { "basic_auth": "user:password", "ip": "192.168.10.0/24", - "disable": ["FLUSHDB", "FLUSHALL"], - "enable": ["SET", "*"] + "disabled": ["FLUSHDB", "FLUSHALL"], + "enabled": ["SET", "*"] + }, + + { + "ip": "0.0.0.0/0", + "disabled": ["SET"], + "enabled": ["SET"] } ] }